JavaScript is full of bugs, and you can easily write bugs.
- What the F *ck JavaScript?
- Translator: Fundebug
To ensure readability, free translation rather than literal translation is used in this paper. In addition, the copyright of this article belongs to the original author, and translation is for study only.
JavaScript is a great language, with a very concise syntax, a large ecosystem, and most importantly, a great community supporting it. At the same time, we know that JavaScript is a tricky language. There are some pits that drive us crazy, and there are some wacky tricks that make us laugh. The idea of this article is derived from Brian Leroux’s talk “WTFJS” at dotJS2012.
My main purpose in collecting these examples is to sort them out and clearly understand how they work. It’s fun to learn a lot of knowledge that I didn’t know before. If you’re a beginner, you can learn more about JavaScript by studying these notes; If you are a professional developer, you can use these notes as a good source of reference. Anyway, just read on and you’ll learn something new.
A function is not a function, right?
⚠️ This is a bug with a lower version, V8(<=5.5), or Node.js(<=7).
// Declare a class which extends null
class Foo extends null {}
// -> [Function: Foo]
new Foo instanceof null
// > TypeError: function is not a function
/ / > the at... ... ...
Copy the code
Note: This bug does not appear in higher versions tested (Node.js, V8.1.1). If you haven’t upgraded to a higher version, why not give it a try?
An array of addition
What happens if we add two arrays?
[1.2.3] + [4.5.6] / / - > '1,2,34,5,6'
Copy the code
This is actually a splicing operation, so let’s explain it step by step:
[1.2.3] + [4.5.6]
/ / call the toString ()
[1.2.3].toString() + [4.5.6].toString()
// String concatenation
'1, 2, 3' + '4 and 6'
// ->
'1,2,34,5,6'
Copy the code
Removal of semicolons from arrays
We create an array of four empty elements. As a result, the array actually has only three elements, because the last semicolon has been removed.
let a = [,,,]
a.length / / - > 3
a.toString() / / - > ', '
Copy the code
Trailing commas (also known as final commas) are useful when adding new elements, parameters, or attributes. If you want to add a new attribute that has a semicolon at the end of the previous line, you can add it to the new line without modifying the previous line. This makes version control diff operations clearer and less problematic. – Trailing commas at MDN
Array equality matching is scary
Please look at:
[] = =' ' // -> 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
Copy the code
Please refer to 7.2.13 Abstract Equality Comparison for details
Undefined and Number
If no arguments are passed to the Number constructor, 0 is returned. If undefined is passed as an argument, NaN is returned.
Number(a)/ / - > 0
Number(undefined) // -> NaN
Copy the code
According to the specification:
- If no arguments are passed in, then n=0;
- Otherwise, n= ToNumber(value);
- If value is undefined, then ToNumnber(undefined) is NaN.
Reference:
- 20.1.1 The Number Constructor
- 7.1.3 ToNumber (argument)
JavaScript has a lot of bugs, so use Fundebug!
ParseInt is not a good thing either
ParseInt is famous for its strange behavior:
parseInt('f*ck'); // -> NaN
parseInt('f*ck'.16); / / - > 15
Copy the code
This is because parseInt parses character by character until it encounters an unusable character. The hexadecimal number for f is 15.
Infinity can be converted to the corresponding number:
//
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
Copy the code
Beware of null arguments:
parseInt(null.24) / / - > 23
Copy the code
First, null is translated as the string “null”. N “for 23 in base 24. ParseInt (null, 24) === 23… Wait, what?” The at StackOverflow.
parseInt('n'.24) / / - > 23
Copy the code
Don’t forget base 8:
parseInt('06'); / / 6
parseInt('08'); // 8 if support ECMAScript 5
parseInt('08'); // 0 if not support ECMAScript 5
Copy the code
If the input string starts with 0, it is base 8 or base 10. Which one it is depends on the implementation. For ECMAScript5, the value is in base 10. But not all browsers support it. Therefore, the safest way is to specify the base when calling parseInt.
ParseInt always converts input to a string.
parseInt({ toString: (a)= > 2.valueOf: (a)= > 1 }) / / - > 2
Number({ toString: (a)= > 2.valueOf: (a)= > 1 }) / / - > 1
Copy the code
The math of true and false
true + true / / - > 2
(true + true) * (true + true) - true / / - > 3
Copy the code
Let’s convert true to Number:
Number(true) / / - > 1
Copy the code
Unary plus attempts to convert a parameter to a number. It converts string integers to float, and non-string true, false, and NULL are also converted. For values that cannot be converted, NaN is returned. Therefore, we have a simpler conversion method:
+true / / - > 1
Copy the code
The ToNumber function is called when you use addition or multiplication. By definition:
If true, return 1. If false, return +0. That’s why we can add Boolean values (true, false) to numbers.
Reference:
- 12.5.6 the Unary + Operator
- 12.8.3 The Addition Operator (+)
- 7.1.3 ToNumber (argument)
HTML comments can be used in JavaScript
In JavaScript, use
// valid comment<! -- valid comment tooCopy the code
The purpose of htML-enabled comments is to allow browsers that do not support
Node.js is also based on V8 implementation, so it can be used in Node.js.
Reference: B.1.3 html-like Comments
NaN is Number
NaN is of type ‘number’ :
typeof NaN // -> 'number'
Copy the code
To see how Typeof and Instanceof work, see:
- 12.5.5 The typeof Operator
- 12.10.4 Runtime Semantics: InstanceofOperator (O, C)
[] and NULL are objects
typeof [] // -> 'object'
typeof null // -> 'object'
/ / but
null instanceof Object // false
Copy the code
For null, as defined by Typeof, “object” is returned as an object that does not implement [[Call]].
You can use the toString function to check the type of an object (Array, Date, Null) :
Object.prototype.toString.call([])
// -> '[object Array]'
Object.prototype.toString.call(new Date)
// -> '[object Date]'
Object.prototype.toString.call(null)
// -> '[object Null]'
Copy the code