
この投稿は、楽しくてトリッキーなJavaScriptの例のリストです。 これは素晴らしい言語です。 シンプルな構文、大規模なエコシステム、そしてさらに重要なことに、巨大なコミュニティがあります。
同時に、JavaScriptはややこしいことをするかなりおもしろい言語であることを皆知っています。 そのうちのいくつかは、私たちの毎日の仕事をすぐに地獄に変えてしまいます。 この投稿では、それらのいくつかを検討します。
内容
やる気
楽しみのために
- 「楽しみのために:偶然の革命家の物語」 、リーナス・トーバルズ
このリストの主な目標は、いくつかのクレイジーな例を収集し、可能であればそれらがどのように機能するかを説明することです。 前に知らなかったことを学ぶのはいいことだからです。
初めての方は、これらのメモを使用してJavaScriptの詳細をご覧ください。 この記事が仕様を読むのにより多くの時間を費やすよう動機付けられることを願っています。 あなたがプロの開発者であれば、これらの例を、私たちの愛するJavaScriptのすべてのトリックとサプライズの良いリファレンスと考えることができます。 いずれにしても、読んでください。 あなたはおそらくあなた自身のために新しい何かを見つけるでしょう。
表記法
// ->
. :
1 + 1
// ->
console.log
. :
console.log('hello, world!') // -> hello, world!
//
. :
const foo = function () {}
[] ![]
:
[] == ![]
:
true false
!!'false' == !!'true' // -> true
!!'false' === !!'true' // -> true
:
:
true == 'true'
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
:
:
Type(x)
Type(y)
, false.Type(x)
,
- x NaN, false.
- y NaN, false.
- … … …
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
:
ECMA-262:
null «», false
, null
«» (falsy) , false
.
!!null
null == false
«» , 0
''
, false
.
0 == false
'' == false
:
, :
Number.MIN_VALUE
:
Number.MIN_VALUE > 0
:
Number.MIN_VALUE
— 5e-324
, , (float precision), . , .
— Number.NEGATIVE_INFINITY
, .
V8 v5.5 (Node.js <=7). «undefined is not a function», ?
class Foo extends null {}
new Foo instanceof null
:
. , , .
?
[1, 2, 3] + [4, 5, 6]
:
. :
[1, 2, 3] + [4, 5, 6]
[1, 2, 3].toString() + [4, 5, 6].toString()
'1,2,3' + '4,5,6'
'1,2,34,5,6'
. - :
let a = [,,,]
a.length
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()
Number(undefined)
:
:
- ,
n
+0
. n
? ToNumber (value)
.undefined
, ToNumber(undefined)
NaN
.
:
parseInt
parseInt
:
parseInt('f*ck');
parseInt('f*ck', 16);
:
, parseInt
, . f
'f*ck'
15
.
Infinity
:
parseInt('Infinity', 10)
parseInt('Infinity', 18)
parseInt('Infinity', 19)
parseInt('Infinity', 23)
parseInt('Infinity', 24)
parseInt('Infinity', 29)
parseInt('Infinity', 30)
parseInt('Infinity', 34)
parseInt('Infinity', 35)
parseInt('Infinity', 36)
parseInt('Infinity', 37)
null
:
parseInt(null, 24)
:
null
"null"
, . 0 23 , , NaN
. 24 "n"
, 14- , . 31 "u"
, 21- , , . 37 , NaN
.
— “parseInt(null, 24) === 23… , ?”
(octal):
parseInt('06');
parseInt('08');
parseInt('08');
:
"0", 8 () 10 (). . ECMAScript 5 10, . parseInt
.
parseInt
:
parseInt({ toString: () => 2, valueOf: () => 1 })
Number({ toString: () => 2, valueOf: () => 1 })
true
false
:
true + true
(true + true) * (true + true) - true
…
:
Number
. , true
1
:
Number(true)
. , true
, false
null
. , NaN
. true
1
:
+true
, 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
:
typeof
instanceof
:
[] null
typeof []
typeof null
null instanceof Object
:
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
9999999999999999
10000000000000000
10000000000000000 + 1
10000000000000000 + 1.1
:
IEEE 754-2008 . :
0.1 + 0.2
. 0.1
0.2
:
0.1 + 0.2
(0.1 + 0.2) === 0.3
:
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()
1..isOne()
2.0.isOne()
(7).isOne()
:
, Number
, JavaScript. , . Number
:
1 < 2 < 3
3 > 2 > 1
:
? . :
1 < 2 < 3
true < 3
1 < 3
3 > 2 > 1
true > 1
1 > 1
« »
:
3 > 2 >= 1
:
JavaScript . :
3 - 1
3 + 1
'3' - 1
'3' + 1
'' + ''
[] + []
{} + []
[] + {}
{} + {}
'222' - -'111'
[4] * [4]
[] * []
[4, 4] * [4, 4]
:
? , JavaScript:
Number + Number ->
Boolean + Number ->
Boolean + Boolean ->
Number + String ->
String + Boolean ->
String + String ->
? []
{}
, ToPrimitive
ToString
. :
, ?
RegExp.prototype.toString = function() {
return this.source
}
/7/ - /5/
:
String
'str'
typeof 'str'
'str' instanceof String
:
String
:
typeof String('str')
String('str')
String('str') == 'str'
new
:
new String('str') == 'str'
typeof new String('str')
? ?
new String('str') // -> [String: 'str']
String:
« » (backticks)
, :
function f(...args) {
return args
}
, :
f(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
? :
:
let x, { x: y = 1 } = { x }; y;
x
, undefined
.x
x
.x
, y
. , 1
.y
.
(spreading)
.
[...[...'...']].length
:
3
? TODO, @@iterator
, , , . , . .
'...'
.
, 3
.
:
[...'...'] // -> [ '.', '.', '.' ]
[...[...'...']] // -> [ '.', '.', '.' ]
[...[...'...']].length // -> 3
, :
[...'...'] // -> [ '.', '.', '.' ]
[...[...'...']] // -> [ '.', '.', '.' ]
[...[...[...'...']]] // -> [ '.', '.', '.' ]
[...[...[...[...'...']]]] // -> [ '.', '.', '.' ]
// …
JavaScript. :
foo: {
console.log('first');
break foo;
console.log('second');
}
:
break
continue
. , break
continue
, .
foo
. console.log('first');
.
JavaScript:
a: b: c: d: e: f: g: 1, 2, 3, 4, 5;
:
, :
try..catch
? 2
3
?
(() => {
try {
return 2;
} finally {
return 3;
}
})()
3
. ?
:
?
:
new (class F extends (String, Array) { })
? .
:
extends ((String, Array))
. , (String, Array)
Array
. , Array
.
,
:
(function* f() { yield f })().next()
// -> { value: [GeneratorFunction: f], done: false }
, , value
f
. :
(function* f() )().next().value().next()
(function* f() )().next().value().next().value().next()
(function* f() )().next().value().next().value().next().value().next()
:
, , :
:
(typeof (new (class { class () {} })))
, . , '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
foo + 'evil'
const bar = nonCoercible('bar')
bar + '1'
bar.toString() + 1
bar === 'bar'
bar.toString() === 'bar'
bar == 'bar'
const baz = nonCoercible(1)
baz == 1
baz === 1
baz.valueOf() === 1
:
:
let f = () => 10
f()
, , :
let f = () => {}
f()
:
{}
undefined
. , , f
.
:
(function () {
return
{
b : 10
}
})()
:
return
:
(function () {
return {
b : 10
}
})()
var obj = { property: 1 }
var array = ['property']
obj[array]
?
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'`