📜 ⬆️ ⬇️

What the hell is javascript


This post is a list of fun and tricky JavaScript examples. This is a great language. It has a simple syntax, a large ecosystem and, more importantly, a huge community.


At the same time, we all know that JavaScript is a pretty funny language that has tricky things. Some of them quickly turn our daily work into hell, and some make them laugh. In this post we will look at some of them.


Content



Motivation


For pleasure
- “Just for Fun: The Story of an Accidental Revolutionary,” Linus Torvalds

The main purpose of this list is to collect some crazy examples and, if possible, explain how they work. Just because it's nice to find out something that we didn’t know before.


If you are new, you can use these notes to learn more about JavaScript. I hope this article motivates you to spend more time reading the specifications. If you are a professional developer, then you can consider these examples as a good reference for all the frills and surprises of our favorite JavaScript. In any case, just read. You will probably find something new for yourself.


Notation


// -> . :


1 + 1 // -> 2

// -> console.log . :


console.log('hello, world!') // -> hello, world!

// . :


//    foo
const foo = function () {}


[] ![]


:


[] == ![] // -> true

:



true false


!!'false' ==  !!'true'  // -> true
!!'false' === !!'true' // -> true

:


:


true == 'true'    // -> true
false == 'false'  // -> false

// 'false' , «» (truthy)


!!'false' // -> true
!!'true'  // -> true


baNaNa


'b' + 'a' + + 'a' + 'a'

JavaScript, . :


'foo' + + 'bar' // -> 'fooNaN'

:


'foo' + (+'bar'), 'bar' .



NaN NaN


NaN === NaN // -> false

:


:


  1. Type(x) Type(y), false.
  2. Type(x) ,
    1. x NaN, false.
    2. y NaN, false.
    3. … … …


NaN IEEE:


: , , , (unordered). , NaN. NaN , .
— “What is the rationale for all comparisons returning false for IEEE754 NaN values?”

fail


, …


(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]
// -> 'fail'

:


, :


(![]+[]) // -> 'false'
![]      // -> false

[] false. - (binary + Operator -> ToPrimitive -> [[DefaultValue]]) :


(![]+[].toString()) // -> 'false'

, [0]:


'false'[0] // -> 'f'

, i . i fail 'falseundefined' ['10']


[] «», true


«» (truthy) , , , true.


!![]       // -> true
[] == true // -> false

:


ECMA-262:



null «», false


, null «» (falsy) , false.


!!null        // -> false
null == false // -> false

«» , 0 '', false.


0 == false  // -> true
'' == false // -> true

:


, :




Number.MIN_VALUE :


Number.MIN_VALUE > 0 // -> true

:


Number.MIN_VALUE — 5e-324, , (float precision), . , .


— Number.NEGATIVE_INFINITY, .




V8 v5.5 (Node.js <=7). «undefined is not a function», ?


//  ,  null
class Foo extends null {}
// -> [Function: Foo]

new Foo instanceof null
// -> TypeError:    
// ->     at … … …

:


. , , .



?


[1, 2, 3] + [4, 5, 6]  // -> '1,2,34,5,6'

:


. :


[1, 2, 3] + [4, 5, 6]
//  toString()
[1, 2, 3].toString() + [4, 5, 6].toString()
// 
'1,2,3' + '4,5,6'
// ->
'1,2,34,5,6'


. - :


let a = [,,,]
a.length     // -> 3
a.toString() // -> ',,'

:


( « ») JavaScript- , . , , . , .


—


—


JS , :


[] == ''   // -> true
[] == 0    // -> true
[''] == '' // -> true
[0] == 0   // -> true
[0] == ''  // -> false
[''] == 0  // -> true

[null] == ''      // true
[null] == 0       // true
[undefined] == '' // true
[undefined] == 0  // true

[[]] == 0  // true
[[]] == '' // true

[[[[[[]]]]]] == '' // true
[[[[[[]]]]]] == 0  // true

[[[[[[ null ]]]]]] == 0  // true
[[[[[[ null ]]]]]] == '' // true

[[[[[[ undefined ]]]]]] == 0  // true
[[[[[[ undefined ]]]]]] == '' // true

:


! , 7.2.13 .


undefined Number


Number, 0. , undefined, Number undefined . undefined, NaN.


Number()          // -> 0
Number(undefined) // -> NaN

:


:


  1. , n +0.
  2. n ? ToNumber (value).
  3. undefined, ToNumber(undefined) NaN.

:



parseInt


parseInt :


parseInt('f*ck');     // -> NaN
parseInt('f*ck', 16); // -> 15

:


, parseInt , . f 'f*ck' 15.


Infinity :


//
parseInt('Infinity', 10) // -> NaN
// ...
parseInt('Infinity', 18) // -> NaN...
parseInt('Infinity', 19) // -> 18
// ...
parseInt('Infinity', 23) // -> 18...
parseInt('Infinity', 24) // -> 151176378
// ...
parseInt('Infinity', 29) // -> 385849803
parseInt('Infinity', 30) // -> 13693557269
// ...
parseInt('Infinity', 34) // -> 28872273981
parseInt('Infinity', 35) // -> 1201203301724
parseInt('Infinity', 36) // -> 1461559270678...
parseInt('Infinity', 37) // -> NaN

null:


parseInt(null, 24) // -> 23

:


null "null", . 0 23 , , NaN. 24 "n", 14- , . 31 "u", 21- , , . 37 , NaN.


— “parseInt(null, 24) === 23… , ?”


(octal):


parseInt('06'); // 6
parseInt('08'); // 8 if support ECMAScript 5
parseInt('08'); // 0 if not support ECMAScript 5

:


"0", 8 () 10 (). . ECMAScript 5 10, . parseInt.


parseInt :


parseInt({ toString: () => 2, valueOf: () => 1 }) // -> 2
Number({ toString: () => 2, valueOf: () => 1 })   // -> 1

true false


:


true + true // -> 2
(true + true) * (true + true) - true // -> 3

…


:


Number . , true 1:


Number(true) // -> 1

. , true, false null. , NaN. true 1:


+true // -> 1

, ToNumber. , :


argument true, 1. argument false, +0.

.


:



HTML- JavaScript


, HTML- <!-- JavaScript.


//  
<!--   

:


? - HTML (degrade gracefully) , <script>. , Netscape 1.x, . HTML- .


Node.js V8, HTML- runtime- Node.js. , :



NaN


NaN 'number':


typeof NaN            // -> 'number'

:


typeof instanceof:



[] null


typeof []   // -> 'object'
typeof null // -> 'object'

// 
null instanceof Object // false

:


typeof :



, typeof 35: typeof. null, , , [[Call]], "object".


toString .


Object.prototype.toString.call([])
// -> '[object Array]'

Object.prototype.toString.call(new Date)
// -> '[object Date]'

Object.prototype.toString.call(null)
// -> '[object Null]'


999999999999999  // -> 999999999999999
9999999999999999 // -> 10000000000000000

10000000000000000       // -> 10000000000000000
10000000000000000 + 1   // -> 10000000000000000
10000000000000000 + 1.1 // -> 10000000000000002

:


IEEE 754-2008 . :



0.1 + 0.2


. 0.1 0.2 :


0.1 + 0.2 // -> 0.30000000000000004
(0.1 + 0.2) === 0.3 // -> false

:


StackOverflow ” ?”:


0.2 0.3 . , 0.2 double 0.2, 0.3 double 0.3. 0.1 0.2 0.3, .

, 0.30000000000000004.com. , , JavaScript.



- Number String.


Number.prototype.isOne = function () {
  return Number(this) === 1
}

1.0.isOne() // -> true
1..isOne()  // -> true
2.0.isOne() // -> false
(7).isOne() // -> false

:


, Number, JavaScript. , . Number:




1 < 2 < 3 // -> true
3 > 2 > 1 // -> false

:


? . :


1 < 2 < 3 // 1 < 2 -> true
true  < 3 // true -> 1
1     < 3 // -> true

3 > 2 > 1 // 3 > 2 -> true
true  > 1 // true -> 1
1     > 1 // -> false

« »:


3 > 2 >= 1 // true

:




JavaScript . :


 3  - 1  // -> 2
 3  + 1  // -> 4
'3' - 1  // -> 2
'3' + 1  // -> '31'

'' + '' // -> ''
[] + [] // -> ''
{} + [] // -> 0
[] + {} // -> '[object Object]'
{} + {} // -> '[object Object][object Object]'

'222' - -'111' // -> 333

[4] * [4]       // -> 16
[] * []         // -> 0
[4, 4] * [4, 4] // NaN

:


? , JavaScript:


Number  + Number  -> 
Boolean + Number  -> 
Boolean + Boolean -> 
Number  + String  -> 
String  + Boolean -> 
String  + String  -> 

? [] {}, ToPrimitive ToString. :




 ,     ?
//    toString
RegExp.prototype.toString = function() {
  return this.source
}

/7/ - /5/ // -> 2

:



String


'str' // -> 'str'
typeof 'str' // -> 'string'
'str' instanceof String // -> false

:


String :


typeof String('str')   // -> 'string'
String('str')          // -> 'str'
String('str') == 'str' // -> true

new:


new String('str') == 'str' // -> true
typeof new String('str')   // -> 'object'

? ?


new String('str') // -> [String: 'str']

String:



« » (backticks)


, :


function f(...args) {
  return args
}

, :


f(1, 2, 3) // -> [ 1, 2, 3 ]

, « »?


f`true is ${true}, false is ${false}, array is ${[1,2,3]}`
// -> [ [ 'true is ', ', false is ', ', array is ', '' ],
// ->   true,
// ->   false,
// ->   [ 1, 2, 3 ] ]

:


, (Tagged template literals). f . . - . . :


function template(strings, ...keys) {
  // -     …
}

, styled-components, React-.



Call call call


@cramforce


console.log.call.call.call.call.call.apply(a => a, [1, 2])

:


, ! : call apply. :



constructor


const c = 'constructor'
c[c][c]('console.log("WTF?")')() // -> WTF?

:


:


//   ,     'constructor'
const c = 'constructor'

// c —   
c // -> 'constructor'

//   
c[c] // -> [Function: String]

//   
c[c][c] // -> [Function: Function]

//   Function        
c[c][c]('console.log("WTF?")') // -> [Function: anonymous]

//      
//     'WTF?'
c[c][c]('console.log("WTF?")')() // -> WTF?

Object.prototype.constructor - Object, -. String, Number, .




{ [{}]: {} } // -> { '[object Object]': {} }

:


? (Computed property name). , , '[object Object]' {}.


« »:


({[{}]:{[{}]:{}}})[{}][{}] // -> {}

// structure:
// {
//   '[object Object]': {
//     '[object Object]': {}
//   }
// }

:



proto


, . __proto__, :


(1).__proto__.__proto__.__proto__ // -> null

:


- , - ToObject. :


(1).__proto__ // -> [Number: 0]
(1).__proto__.__proto__ // -> {}
(1).__proto__.__proto__.__proto__ // -> null

__proto__:



${{Object}}


?


`${{Object}}`

:


// -> '[object Object]'

:


Object (Shorthand property notation):


{ Object: Object }

, toString. '[object Object]'.




:


let x, { x: y = 1 } = { x }; y;

. y? :


// -> 1

:


let x, { x: y = 1 } = { x }; y;
//  ↑       ↑           ↑    ↑
//  1       3           2    4

  1. x , undefined.
  2. x x.
  3. x, y. , 1 .
  4. y.


(spreading)


.


[...[...'...']].length // -> 3

:


3? TODO, @@iterator, , , . , . .


'...' ., 3.


:


[...'...']             // -> [ '.', '.', '.' ]
[...[...'...']]        // -> [ '.', '.', '.' ]
[...[...'...']].length // -> 3

, :


[...'...']                 // -> [ '.', '.', '.' ]
[...[...'...']]            // -> [ '.', '.', '.' ]
[...[...[...'...']]]       // -> [ '.', '.', '.' ]
[...[...[...[...'...']]]]  // -> [ '.', '.', '.' ]
//   …


JavaScript. :


foo: {
  console.log('first');
  break foo;
  console.log('second');
}

// -> first
// -> undefined

:


break continue. , break continue , .


foo. console.log('first'); .


JavaScript:




a: b: c: d: e: f: g: 1, 2, 3, 4, 5; // -> 5

:


, :



try..catch


? 2 3?


(() => {
  try {
    return 2;
  } finally {
    return 3;
  }
})()

3. ?


:



?


:


new (class F extends (String, Array) { }) // -> F []

? .


:


extends ((String, Array)). , (String, Array) Array. , Array.



,


:


(function* f() { yield f })().next()
// -> { value: [GeneratorFunction: f], done: false }

, , value f. :


(function* f() { yield f })().next().value().next()
// -> { value: [GeneratorFunction: f], done: false }

//  
(function* f() { yield f })().next().value().next().value().next()
// -> { value: [GeneratorFunction: f], done: false }

//  
(function* f() { yield f })().next().value().next().value().next().value().next()
// -> { value: [GeneratorFunction: f], done: false }

//   
// …

:


, , :




:


(typeof (new (class { class () {} }))) // -> 'object'

, . , 'object'.


:


ECMAScript 5 . :


const foo = {
  class: function() {}
};

ES6 . . : function, :


class {
  class() {}
}

. typeof 'object'.


:



, (Non-coercible objects)


Well-Known Symbols :


function nonCoercible(val) {
  if (val == null) {
    throw TypeError('nonCoercible should not be called with null or undefined')
  }

  const res = Object(val)

  res[Symbol.toPrimitive] = () => {
    throw TypeError('Trying to coerce non-coercible object')
  }

  return res
}

:


// 
const foo = nonCoercible({foo: 'foo'})

foo * 10      // -> TypeError: Trying to coerce non-coercible object
foo + 'evil'  // -> TypeError: Trying to coerce non-coercible object

//  
const bar = nonCoercible('bar')

bar + '1'                 // -> TypeError: Trying to coerce non-coercible object
bar.toString() + 1        // -> bar1
bar === 'bar'             // -> false
bar.toString() === 'bar'  // -> true
bar == 'bar'              // -> TypeError: Trying to coerce non-coercible object

// 
const baz = nonCoercible(1)

baz == 1             // -> TypeError: Trying to coerce non-coercible object
baz === 1            // -> false
baz.valueOf() === 1  // -> true

:




:


let f = () => 10
f() // -> 10

, , :


let f = () => {}
f() // -> undefined

:


{} undefined. , , f .



:


(function () {
  return
  {
    b : 10
  }
})() // -> undefined

:


return :


(function () {
  return {
    b : 10
  }
})() // -> { b: 10 }


var obj = { property: 1 }
var array = ['property']

obj[array] // -> 1

?


var map = {}
var x = 1
var y = 2
var z = 3

map[[x, y, z]] = true
map[[x + 10, y, z]] = true

map["1,2,3"]  // -> true
map["11,2,3"] // -> true

:


[] toString. — :


['property'].toString() // -> 'property'`



')

Source: https://habr.com/ru/post/335292/


All Articles