Skip to content

Instantly share code, notes, and snippets.

@thamsrang
Last active October 9, 2019 13:58
Show Gist options
  • Select an option

  • Save thamsrang/ceda5f22af8923acb9a2e7d831b6a5be to your computer and use it in GitHub Desktop.

Select an option

Save thamsrang/ceda5f22af8923acb9a2e7d831b6a5be to your computer and use it in GitHub Desktop.
JavaScript code tips and tricks. JavaScript Unknown Facts. JavaScript Deep learning. JavaScript Object Conversion. JavaScript Type Conversion. #js #depth
/****
* READ FIRST: https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839/
* READ SECOND: https://github.com/denysdovhan/wtfjs
*/
// Coercion is the term that is used for unexpected type casting in JavaScript.
// https://dmitripavlutin.com/javascriptss-addition-operator-demystified/
// http://2ality.com/2012/01/object-plus-object.html
// https://dorey.github.io/JavaScript-Equality-Table/
// https://wtfjs.com/
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness
// http://getify.github.io/coercions-grid/
// https://delapouite.com/ramblings/javascript-coercion-rules.html
// https://g00glen00b.be/javascript-coercion/
// https://blog.usejournal.com/little-known-features-of-javascript-901665291387
var a = Object['length'];
console.log( a ); // Prints 1
var b = {1}['length'];
console.log( b ); // Prints ['length']
var c = {}.1;
console.log( c ); //Prints 0.1
var d = []+{};
console.log( d ); //Prints "[object Object]"
var e = {}"str";
console.log( e ); // Prints "str"
var f = {}1;
console.log(f); // Prints 1
var g = 1+true;
console.log(g); // Prints 2. true is converted to 1.
var h = 1+false;
console.log(f); // Prints 1. false is converted to 0.
console.log("" + 1 + 0); // Prints 10
console.log("" - 1 + 0); // Prints -1
console.log(true + false); // Prints 1
console.log(6 / "3"); // Prints 2
console.log("2" * "3"); // Prints 6
console.log(4 + 5 + "px"); // Prints 9px
console.log("$" + 4 + 5); // Prints $45
console.log("4" - 2); // Prints 2
console.log("4px" - 2); // Prints NaN
console.log(7 / 0); // Prints Infinity
console.log(" -9\n" + 5); // Prints -9
5 && 2 = 2
2 && 5 = 5
5 || 0 = 5
0 || 5 = 5
null + 1 = 1 // (3)
undefined + 1 = NaN // (4)
null == "\n0\n" = false // (5)
+null == +"\n0\n" = true // (6)
// 5
console.log(" -9\n" - 5); // Prints -14
console.log(null + 1); // Prints 1
console.log(undefined + 1); // Prints NaN
console.log( Boolean("0") ); // Prints true
console.log( Boolean(" ") ); // Prints true (any non-empty string is true)
/** Date **/
console.log(1*(new Date)); // Prints Timestamp - 1529568542851
console.log(new Date-0); // Prints Timestamp - 1529568542851
console.log(+new Date); // Prints Timestamp - 1529568542851
console.log([] + []); // JavaScript will give you "" (which makes little sense)
console.log({} + []); // JS : 0
console.log([] + {}); // JS : "[object Object]"
console.log({} + {}); // JS : NaN or [object Object][object Object] depending upon browser
console.log("hello" - 1); // JS : NaN
var str = "constructor";
str[str]("01"); // Prints "01"
// Source : https://medium.freecodecamp.org/js-type-coercion-explained-27ba3d9a2839
true + false // 1
12 / "6" // 2
"number" + 15 + 3 // 'number153'
15 + 3 + "number" // '18number'
[1] > null // true
"foo" + + "bar" // 'fooNaN'
'true' == true // false
false == 'false' // false
null == '' // false
!!"false" == !!"true" // true
['x'] == 'x' // true
[] + null + 1 // 'null1'
[1,2,3] == [1,2,3] // false
{}+[]+{}+[1] // '0[object Object]1'
!+[]+[]+![] // 'truefalse'
new Date(0) - 0 // 0
new Date(0) + 0 // 'Thu Jan 01 1970 02:00:00(EET)0'
Math.max(); // Prints -Infinity
Math.min(); // Prints Infinity
// Credit: https://github.com/brianleroux/wtfjs
console.log(111111111111111111111); // Prints 111111111111111110000
("foo" + + "bar") === "fooNaN" // Prints true. Evaluted as “foo” + (+ “bar”), which converts “bar” to not a number.
0.1 + 0.2 === 0.3; // Prints false. Result of 0.1 + 0.2 is 0.30000000000000004
Number.MIN_VALUE > 0; // Prints true. Result of Number.MIN_VALUE is 5e-324
typeof NaN === "number"; // Prints true. Because NaN.__proto__ is Number
NaN === NaN; //Prints false.
typeof null === "object"; // Prints true.
null instanceof Object; //Prints false. Classic null is not an Object.
parseInt('06'); // Parse to 6
parseInt('08'); // Parse to 0 in old browser. In Chrome66 works fine. This is because parseInt accepts a second argument for radix. If it is not supplied and the string starts with a 0 it will be parsed as an octal number.
"string" instanceof String; //prints false.
String("string") instanceof String; // Prints false.
new String("string") instanceof String; //Prints true.
(function(){
var x = y = 1;
})();
console.log(x); // undefined
console.log(y); // 1 -- oops, auto-global!
// It’s treated like: var x = (y = 1); thus, “y=1” creates an auto-global since there’s no binding “var” statement for it. Afterwards, that value gets copied into the properly defined local var “x”.
"222" - -"111" // 333. Evaluted as "222"-(-"111");
(function(){
console.log(window); // "undefined"
var window = window;
console.log(window); // "undefined"
})();
// Because of “hoisting”, all variable declarations will be executed immediately at the top of a function scope. However, the variable initializations are not hoisted. So, local variable “window” is declared but uninitialized/”undefined”.
Object.prototype.foo = 10;
console.log(foo); //Prints 10
var bignum = 1e300; // 1e300
var a = 1e400; //Infinity
console.log(a - bignum); //Infinity
setTimeout(function(rand){ console.log(rand); },10); // FF passes a "magic" param we call "rand". I got 99999
for (var i=0; i<100000; i++) { i; } // take some time
// For Firefox only, any function executed by a setTimeout or setInterval invocation will get passed to it (whether you want it to or not) a mysterious “lateness” variable, which represents the number of milliseconds late the function is in executing. Sucks because it can clobber an intentionally unpassed “default” variable to your function. Sucks even more if this variable is intended to be boolean, because you end up with ”random” true/false’y values.
(true + 1) === 2;​ ​// true
(true + true) === 2; // true
true === 2; // false
true === 1; // false
var a = {};
a.b === undefined; // true because property b is not set
undefined = 42;
a.b === undefined; // false. In JavaScript, undefined is nothing but a global variable name without a default value. Therefore, its primitive value is undefined. You can change the value of undefined. undefined is mutable.
function laugh()
{
return
{
haha: "ha!"
};
}
laugh(); // returns undefined
// note the number to the left of the 'e', 7 and 8 respectively
console.log( 1.7976931348623157e+308 === 1.7976931348623158e+308 ); // true!
var enum; // Uncaught SyntaxError: Unexpected reserved word
//----------------------------------------------------------------------------------
// arguments hacking
(function(a,b,c) {
console.log(a,b,c); // one two three
console.log(arguments[0], arguments[1], arguments[2]); // one two three
arguments[0] = "uno";
console.log(a,b,c); // uno two three
console.log(arguments[0], arguments[1], arguments[2]); // uno two three
// a is magically married to arguments[0], b to arguments[1] etc
// so one could change locally scoped variables from another scope like so:
changeArguments(arguments);
console.log(a,b,c); // I messed up your dataz
})("one", "two", "three");
// not cool.
function changeArguments(args){
args[0] = "I messed"
args[1] = "up your";
args[2] = "dataz";
}
// A more real world example:
(function(arg1, arg2) {
console.log(arg1, arg2); //-> uno dos
Array.prototype.shift.apply(arguments);
console.log(arg1, arg2); //-> dos dos
console.log(arguments); ["dos"]
})('uno', 'dos');
//--------------------------------------------------------------------------------------
"0" && {} // true
0 && {} // false
0 == "0" // true
var a = 012; // 10 is assigned to a. Integer Octet conversion.
var a = 8;
var someFunc = function(){
console.log("'a value is ", a, "'");
var a = 8;
};
someFunc(); // Prints 'a value is undefined'. Variable 'a' is Hoisted.
3 > 2 > 1 // false. Remember how true sometimes has a value so in the above 3 > 2 evaluates to true making the second part of the expression evaluate true > 1 which is false.
(1) === 1; // true
Number.prototype.isOne = function () { return this === 1; }
(1).isOne(); // false!
Number.prototype.reallyIsOne = function () { return this - 1 === 0; }
(1).reallyIsOne(); // true
(function(){return 2*3;}).toString() === (function(){return 6;}).toString(); // false. (function(){return 2*3;}).toString() is "function(){return 2*3;}"; (function(){return 6;}).toString(); is "function(){return 6;}";
window.window == window // true
window.window.window == window // true
window.window.window.window == window //true
[] == 0 // true
+[] === 0 // true
++[] === 1 // Uncaught ReferenceError: Invalid left-hand side expression in prefix operation
[[]][0] === []; // false
++[[]][0] === 1; // true
++[[]][+[]] === 1 // true
Number.MAX_VALUE*1.0000000000000001 === (1/0) // false
Number.MAX_VALUE*1.0000000000000002 === (1/0) // true
var foo = {
toString: function () {
return 5;
},
valueOf: function () {
return "foo";
}
};
alert(foo.toString() + 1); // 6 (bad!)
alert(foo + 1); // "foo1" (no good!)
alert(+foo); // NaN (the worst!)
alert.call.call.call.call.call.apply(function (a) {return a}, ["1","2"]); // Prints 2
alert.apply.apply.call.call(function (b) {return b}, {a:1},{b:2},{c:3} ) // Prints {b:2}
Function.prototype.call.apply(function (a) {return a}, [1,2]); // Prints 2
//Example
function logThisAndArgs() {
console.log(this, arguments);
};
Function.prototype.call.apply(logThisAndArgs, [{'some':'object'},1,2,3,4])
// Prints >{ some:"object"} >Arguments(4)[1, 2, 3, 4, callee:f]
// Check it now
Function.prototype.call.call(logThisAndArgs, {'some':'object'},1,2,3,4)
// Prints >{ some:"object"} >Arguments(4)[1, 2, 3, 4, callee:f]
1 + + 1 // => 2
1 + - + 1 // => 0
1 + - + - + 1 // => 2
1 + - + - + - + 1 // => 0
1 + - + + + - + 1 // => 2
1 + / + + + / + 1 // => '1/ + + + /1'
isNaN( null ); // false
null === NaN; // false
null == NaN; // false
// Then why
Number( null ); // 0
// When you create instances of String or Number, they take the default value ("" for strings and 0 for numbers). This is not the same for Object and Array.
var a = new Number;
a == 0 // true
var a = new String;
a == "" // true
var a = new Object;
a == {} // false
var a = new Array;
a == [] // false
// This is even more confusing when using the JSON-style syntax to create objects and arrays.
var a = {};
a == {} // false
var a = [];
a == [] // false
var a = {};
var b = {key:2};
var c = {key:3};
a[b]=123;
a[c]=456;
console.log(a[b]); // Prints 456. a is {"[object Object]":456}.
console.log((!+[]+[]+![]).length); //Prints 9.
console.log((!+[]+[]+![])); //Prints "truefalse".
var Z = "constructor";
Z[Z][Z]("alert('wtfjs!')")(); // alerts wtfjs!
/**
Z[Z]; // function String() { [native code] }
Z[Z][Z]; // function Function() { [native code] }
*/
//-----------------------------------------------------------------------------------------------------------------------
// How do you determine if a number is an integer in JavaScript?
x = 1;
x === Math.floor(x); // returns true
// But what happens if we try to add a method for this to the Number prototype?
Number.prototype.isInteger = function() {
return this === Math.floor(this);
}
x = 1;
x.isInteger(); // returns false!
// Why? It turns out that when you add methods to Number, the type of the number inside the method becomes "object" rather than "number", but Math.floor returns a result of type "number". If you use the === operator, the two values are no longer equal because they're different types. So the method can be fixed two ways.
// Solution 1 is to avoid comparing types:
Number.prototype.isInteger = function() {
return this == Math.floor(this); // works but breaks if you care about 0 vs other falsy values
}
// Solution 2 is better; cast "this" to the Number type and then the types are equal.
Number.prototype.isInteger = function() {
return Number(this) === Math.floor(this);
}
//-----------------------------------------------------------------------------------------------------------------------
// https://j11y.io/javascript/another-javascript-quiz/#comment-28938
// 2010-07-12-fail.md
// Let's take the last post a step further:
console.log( (![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]] ) // "fail"
// Breaking that mass of symbols into pieces we notices, that the following patten occurs often:
console.log( (![]+[]) ) // "false"
console.log( ![] ) // false
// So we try adding [] to false. But through a number of internal function calls( binary + Operator -> ToPrimitive -> [[DefaultValue]]) we end up with converting the right operand to a String:
console.log( [].toString() ) // ""
console.log( (![]+[].toString()) ) // false + ""
// Aha, so we are concatenating strings here! Now this is plain obvious! Moving on to the next bit:
console.log( [+[]] ) // [ 0]
console.log( +[] ) // 0
// Thinking of a String as an Array we can access its first character via [0]. So "false"[0] returns "f".
//-----------------------------------------------------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment