Last active
November 5, 2022 12:37
-
-
Save SaicharanKandukuri/9121d0cb22dd70db3b3764f37f8737da to your computer and use it in GitHub Desktop.
[null & 0 in javascript] code to show how strange relation between null & 0 works in javascript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
CODE to show how relation between null ( an object ) & 0 ( a Number ) works in JavaScript | |
code below is not fully implemented according to algorithm in ECMA-262 only the part where values of null & 0 satisfies are covered | |
REFER: https://262.ecma-international.org/5.1 | |
(C) saicharankandukuri 2022 | |
*/ | |
const LOG = (buff) => console.log(buff); | |
/* | |
isPrimitive & toPrimitive functions are from https://stackoverflow.com/questions/52573030/is-there-a-way-to-call-toprimitive-in-javascript | |
thanks to https://stackoverflow.com/users/4151830/matthijs | |
*/ | |
const isPrimitive = ( value ) => | |
typeof value === 'object' ? value === null : typeof value !== 'function'; | |
const toPrimitive = ( value, hint='default' ) => { | |
// if value is already a primitive, we're done | |
if( isPrimitive( value ) ) | |
return value; | |
// if value[ Symbol.toPrimitive ] exists (is not undefined or null) | |
let method = value[ Symbol.toPrimitive ]; | |
if( method != null ) { // using != instead of !== is intentional | |
// then call value[ Symbol.toPrimitive ]( hint ) | |
let result = Reflect.apply( method, value, [ hint ] ); | |
if( isPrimitive( result ) ) | |
return result; | |
// if it doesn't return a primitive, do not fall back to legacy | |
// methods but just throw an error | |
} else { | |
// if value[ Symbol.toPrimitive ] doesn't exist, try the legacy | |
// valueOf() and toString() methods, in that order unless hint | |
// is 'string' in which case toString() is tried first. | |
// | |
// for these we need to be more garbage-tolerant: if the first | |
// legacy method is a non-function or returns a non-primitive, | |
// just ignore it and move on to the second one. | |
method = value[ hint === 'string' ? 'toString' : 'valueOf' ]; | |
if( typeof method === 'function' ) { | |
let result = Reflect.apply( method, value, [] ); | |
if( isPrimitive( result ) ) | |
return result; | |
} | |
method = value[ hint === 'string' ? 'valueOf' : 'toString' ]; | |
if( typeof method === 'function' ) { | |
let result = Reflect.apply( method, value, [] ); | |
if( isPrimitive( result ) ) | |
return result; | |
} | |
} | |
throw new TypeError("Cannot convert object to primitive value"); | |
}; | |
const ABSTRACT_RELATION = (x, y) => { | |
// REFER: https://262.ecma-international.org/5.1/#sec-11.8.5 | |
// [NOTE]: LeftShift argument is skipped cause comparision results same either ways for null & 0 | |
/* | |
If it is not the case that | |
both Type(px) is String and Type(py) is String, | |
then | |
*/ | |
// to primitive a with hint Number => pa | |
let px = toPrimitive(x, Number); | |
let py = toPrimitive(y, Number); | |
if (typeof px && typeof py != 'string') { | |
// nx be the ToNumber | |
nx = Number(px); | |
ny = Number(py); | |
if (nx == ny) { | |
return false; | |
} | |
} | |
} | |
const EQUALITY_COMPARISION = (x, y) => { | |
// [NOT IMPLMENTED]: If Type(x) is the same as Type(y) cause type(null) != type(0) | |
// If Type(x) is the same as Type(y), | |
if (typeof x == null & typeof y == 'undefined') { | |
return true; | |
} | |
if (typeof x == 'undefined' & typeof y == null) { | |
return true; | |
} | |
// if x is object and y is Number or string || or the other way around | |
// return toPrimitive(<object_variable>, Hint Number) == non_object_variable | |
if ( typeof(x) == 'object' && (typeof y == 'number'|| typeof y == 'string')) { | |
LOG("HERE") | |
return toPrimitive(x, Number) == y; | |
} | |
if ( (typeof x == 'number'|| typeof x == 'string') && typeof y == 'object') { | |
return x == toPrimitive(y, Number) == x; | |
} | |
} | |
const LESS_THAN_OR_EQUAL = (x, y) => { | |
// https://262.ecma-international.org/5.1/#sec-11.8.3 | |
/* | |
The Less-than-or-equal Operator ( <= ) | |
The production RelationalExpression : RelationalExpression <= ShiftExpression is evaluated as follows: | |
Let lref be the result of evaluating RelationalExpression. | |
Let lval be GetValue(lref). | |
Let rref be the result of evaluating ShiftExpression. | |
Let rval be GetValue(rref). | |
Let r be the result of performing abstract relational comparison rval < lval with LeftFirst equal to false. (see 11.8.5). | |
If r is true or undefined, return false. Otherwise, return true. | |
*/ | |
// [Note]: In algoritm the LeftShift is set to false which mean the comparision should run from right side | |
// Because of the comparision is with null & 0 and logically either ways gives same result that part is skipped | |
let r = ABSTRACT_RELATION(x,y) | |
return r == (true || 'undefined') ? false : true; | |
} | |
const GREATER_THAN_OR_EQUAL = (x, y) => { | |
// REFER: https://262.ecma-international.org/5.1/#sec-11.8.4 | |
/* | |
The Greater-than-or-equal Operator ( >= ) | |
The production RelationalExpression : RelationalExpression >= ShiftExpression is evaluated as follows: | |
Let lref be the result of evaluating RelationalExpression. | |
Let lval be GetValue(lref). | |
Let rref be the result of evaluating ShiftExpression. | |
Let rval be GetValue(rref). | |
Let r be the result of performing abstract relational comparison lval < rval. (see 11.8.5) | |
If r is true or undefined, return false. Otherwise, return true. | |
*/ | |
let r = ABSTRACT_RELATION(x,y) | |
return r == (true || 'undefined') ? false : true; | |
} | |
const LESS_THAN = (x, y) => { | |
// REFER: https://262.ecma-international.org/5.1/#sec-11.8.1 | |
/* | |
The Less-than Operator ( < ) | |
The production RelationalExpression : RelationalExpression < ShiftExpression is evaluated as follows: | |
Let lref be the result of evaluating RelationalExpression. | |
Let lval be GetValue(lref). | |
Let rref be the result of evaluating ShiftExpression. | |
Let rval be GetValue(rref). | |
Let r be the result of performing abstract relational comparison lval < rval. (see 11.8.5) | |
If r is undefined, return false. Otherwise, return r. | |
*/ | |
let r = ABSTRACT_RELATION(x,y) | |
if (r == undefined) { | |
return false; | |
} | |
return r; | |
} | |
const GREATER_THAN = (x, y) => { | |
// REFER: https://262.ecma-international.org/5.1/#sec-11.8.2 | |
/* | |
The Greater-than Operator ( > ) | |
The production RelationalExpression : RelationalExpression > ShiftExpression is evaluated as follows: | |
Let lref be the result of evaluating RelationalExpression. | |
Let lval be GetValue(lref). | |
Let rref be the result of evaluating ShiftExpression. | |
Let rval be GetValue(rref). | |
Let r be the result of performing abstract relational comparison rval < lval with LeftFirst equal to false. (see 11.8.5). | |
If r is undefined, return false. Otherwise, return r. | |
*/ | |
let r = ABSTRACT_RELATION(x,y) | |
if (r == undefined) { | |
return false; | |
} | |
return r; | |
} | |
// LOG(toPrimitive(null, Number)) | |
// LOG(ABSTRACT_RELATION(null, 0)) | |
LOG("null == 0 \t->\t" + EQUALITY_COMPARISION(null, 0)) // null == 0 | |
LOG("null >= 0 \t->\t" + GREATER_THAN_OR_EQUAL(null, 0)) // null >= 0 | |
LOG("null <= 0 \t->\t" + LESS_THAN_OR_EQUAL(null, 0)) // null <= 0 | |
LOG("null > 0 \t->\t" + GREATER_THAN(null, 0)) // null > 0 | |
LOG("null < 0 \t->\t" + LESS_THAN(null, 0)) // null < 0 |
Author
SaicharanKandukuri
commented
Nov 5, 2022
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment