一体何、Javascript


この投稿は、楽しくてトリッキーなJavaScriptの例のリストです。 これは素晴らしい言語です。 シンプルな構文、大規模なエコシステム、そしてさらに重要なことに、巨大なコミュニティがあります。


同時に、JavaScriptはややこしいことをするかなりおもしろい言語であることを皆知っています。 そのうちのいくつかは、私たちの毎日の仕事をすぐに地獄に変えてしまいます。 この投稿では、それらのいくつかを検討します。


内容



やる気


楽しみのために
- 「楽しみのために:偶然の革命家の物語」 、リーナス・トーバルズ

このリストの主な目標は、いくつかのクレイジーな例を収集し、可能であればそれらがどのように機能するかを説明することです。 前に知らなかったことを学ぶのはいいことだからです。


初めての方は、これらのメモを使用してJavaScriptの詳細をご覧ください。 この記事が仕様を読むのにより多くの時間を費やすよう動機付けられることを願っています。 あなたがプロの開発者であれば、これらの例を、私たちの愛するJavaScriptのすべてのトリックとサプライズの良いリファレンスと考えることができます。 いずれにしても、読んでください。 あなたはおそらくあなた自身のために新しい何かを見つけるでしょう。


表記法


// -> . :


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_VALUE5e-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/J335292/


All Articles