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.
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.
// ->
. :
1 + 1 // -> 2
// ->
console.log
. :
console.log('hello, world!') // -> hello, world!
//
. :
// foo
const foo = function () {}
:
[] == ![] // -> true
!!'false' == !!'true' // -> true
!!'false' === !!'true' // -> true
:
true == 'true' // -> true
false == 'false' // -> false
// 'false'
, «» (truthy)
!!'false' // -> true
!!'true' // -> true
'b' + 'a' + + 'a' + 'a'
JavaScript, . :
'foo' + + 'bar' // -> 'fooNaN'
'foo' + (+'bar')
, 'bar'
.
NaN === NaN // -> false
:
Type(x)
Type(y)
, false.Type(x)
,NaN
IEEE:
: , , , (unordered). , NaN. NaN , .
— “What is the rationale for all comparisons returning false for IEEE754 NaN values?”
, …
(![]+[])[+[]]+(![]+[])[+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]
// -> 'fail'
, :
(![]+[]) // -> 'false'
![] // -> false
[]
false
. - (binary + Operator -> ToPrimitive -> [[DefaultValue]]
) :
(![]+[].toString()) // -> 'false'
, [0]
:
'false'[0] // -> 'f'
, i
. i
fail
'falseundefined'
['10']
«» (truthy) , , , true
.
!![] // -> true
[] == true // -> false
ECMA-262:
, 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 .
Number
, 0
. , undefined
, Number
undefined
. undefined
, NaN
.
Number() // -> 0
Number(undefined) // -> NaN
:
n
+0
.n
? ToNumber (value)
.undefined
, ToNumber(undefined)
NaN
.:
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 (degrade gracefully) , <script>
. , Netscape 1.x, . HTML- .
Node.js V8, HTML- runtime- Node.js. , :
NaN
'number'
:
typeof NaN // -> 'number'
typeof
instanceof
:
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.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
'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:
, :
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-.
console.log.call.call.call.call.call.apply(a => a, [1, 2])
, ! : call
apply
. :
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__
, :
(1).__proto__.__proto__.__proto__ // -> null
- , - ToObject
. :
(1).__proto__ // -> [Number: 0]
(1).__proto__.__proto__ // -> {}
(1).__proto__.__proto__.__proto__ // -> null
__proto__
:
?
`${{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
x
, undefined
.x
x
.x
, y
. , 1
.y
..
[...[...'...']].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
, :
? 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'
.
:
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