Original author: Andy Croxall
Original link: Ten Oddities And Secrets About JavaScript
Translation editor: Zhang Xinxu
Data types and definitions
1. Null is an object
Among the many types of JavaScript, there is the Null type, which has a unique value of null, that is, its literal, defined as A value that makes no sense at all. It behaves like an object, as shown in the following detection code:
alert (typeof null); //Pop up 'object'
as shown below:
Although the typeof value shows "object", null is not considered an object instance. You know, the values in JavaScript are object instances, each value is a Number object, and each object is an Object object. Because null has no value, it is obvious that null is not an instance of anything. Therefore, the value below equals false.
alert(null instanceof Object); // is false
Translator’s Note: null can also be understood as an object placeholder
2. NaN is a numerical value
The original meaning of NaN is to represent a certain The value is not a numerical value, but it is a numerical value and is not equal to itself. It is strange. Look at the following code:
alert(typeof NaN); //pop up 'Number'
alert(NaN === NaN); //is false
The results are as follows:
Actually NaN is not equal to anything. To confirm whether something is NaN, you can only use isNaN.
3. Arrays without keywords are equivalent to false (about Truthy and Falsy)
Here is another great quirk of JavaScript:
alert(new Array() == false); // is true
The result is as follows:
To understand what is going on here, you need to understand the concepts of truthy and falsy. They are a true/flase literal. In JavaScript, all non-Boolean values have a built-in boolean flag. When the value is required to have boolean behavior, this built-in Boolean value will appear, such as when you want to compare with a Boolean value.
Since apples cannot be compared with pears, when JavaScript requires a comparison between two different types of values, it will first weaken them into the same type. false, undefined, null, 0, "", NaN are all weakened to false. This coercion does not always exist, only when used as an expression. Look at the following simple example:
var someVar =0;
alert(someVar == false); //display true
The results are as follows:
In the above test, we tried to compare the value 0 with the boolean value false. Since the two data types are incompatible, JavaScript automatically forced conversion into unified and equivalent truthy and falsy, where 0 is equivalent to false (as mentioned above) mentioned).
You may have noticed that there are no empty arrays in some of the above values that are equivalent to false. Just because the empty array is a strange thing: it itself is actually truthy, but when the empty array is compared with the Boolean type, its behavior is falsy. Not sure? There are reasons for this. Let’s take an example to verify the strange behavior of empty arrays:
var someVar = []; //Empty array
alert(someVar == false); //The result is true
if (someVar) alert('hello'); //The alert statement is executed, so someVar is treated as true
The result is as shown in the screenshot below, with two boxes popping up in succession:
Translator’s Note: The reason for this difference is that, according to the author, the array has a built-in toString() method. For example, when alerting directly, a string will pop up in the form of join(“,”), and an empty array will naturally It is an empty string, so it is equivalent to false. For details, please refer to the author's other article, "Twisted logic: understanding truthy & falsy". But what I personally find strange is that when empty objects, empty functions, weak equals true or false, false is displayed. Why? Is it really because arrays are a weirdo and need special considerations?
To avoid comparison problems with casts, you can use strong equals (===) instead of weak equals (==).
var someVar = 0;
alert(someVar = = false); //The result true – 0 belongs to falsy
alert(someVar === false); //The result false – zero is a numerical value, not a Boolean value
The result is as screenshot below (win7 FF4):
If you want to delve deeper into some unique quirks such as type coercion in JavaScript, you can refer to the official relevant document specifications:
section 11.9.3 of the ECMA-262
Regular Expression Formula
4. replace() can accept callback function
This is one of the least known secrets of JavaScript, first introduced in v1.3. In most cases, the use of replace() is similar to the following:
alert('10 13 21 48 52'.replace(/d /g, '*')); //Replace all numbers with *
This is a simple replacement, one character String, an asterisk. But what if we want to have more control over when replacement occurs? We only want to replace values below 30, what should we do? At this point, it is beyond your reach to rely solely on regular expressions. We need to use the callback function to process each match.
alert('10 13 21 48 52'.replace( /d /g, function(match) {
return parseInt(match) <30?'*' : match;
}));
When each match is completed, JavaScript applies a callback function and passes the matching content to the match parameter. Then, depending on the filtering rules in the callback function, either an asterisk is returned, or the match itself is returned (no replacement occurs).
The screenshot below:
5. Regular expressions: not just match and replace
Many JavaScript engineers only deal with regular expressions through match and replace. But there are far more regular expression-related methods defined by JavaScript than these two.
It is worth mentioning that test() works similarly to match(), but the return value is different: test() returns a Boolean type, used to verify whether it matches, and the execution speed is higher than match().
alert(/w{3,}/.test( 'Hello')); //Pop up 'true'
The above line of code is used to verify whether the string has more than three ordinary characters. Obviously "hello" meets the requirements, so true pops up.
The results are as follows:
We should also pay attention to the RegExp object, which you can use to create dynamic regular expression objects, for example:
function findWord(word, string) {
var instancesOfWord = string.match(new RegExp('\b' word '\b', 'ig'));
alert(instancesOfWord);
}
findWord('car', 'Carl went to buy a car but had forgotten his credit card.');
Here, we dynamically create a matching verification based on the parameter word. The function of this test code is to select the word car without distinguishing between large and small selections. At a quick glance, the only word in the test English sentence is car, so the performance here is only one word. is used to represent word boundaries.
The results are as follows:
Function and Scope
6. You can pretend to be a scope
Scope is used to determine what variables are available, independent JavaScript (such as JavaScript is not in a running function) in the window object Operating in the global scope, the window object can be accessed under any circumstances. However, local variables declared in a function can only be used within that function.
var animal ='dog';
function getAnimal (adjective) { alert(adjective '' this.animal); }
getAnimal('lovely'); //pop up 'lovely dog'
Here our variables and functions are declared in in global scope. Because this points to the current scope, which is window in this example. Therefore, this function looks for window.animal, which is 'dog'. So far, so good. However, in practice, we can make a function run in a different scope and ignore its own scope. We can use a built-in method called call() to achieve scope impersonation.
var animal ='dog';
function getAnimal (adjective) { alert(adjective '' this.animal); };
var myObj = {animal: 'camel'};
getAnimal.call(myObj, 'lovely'); //pop up 'lovely camel' '
The first parameter in the call() method can pretend to be this in the function. Therefore, this.animal here is actually myObj.animal, which is 'camel'. The subsequent parameters are passed to the function body as ordinary parameters.
Another related one is the apply() method, which works the same as call(). The difference is that the parameters passed to the function are represented in the form of an array instead of independent variables. Therefore, if the above test code is represented by apply(), it is:
getAnimal.apply(myObj, ['lovely']); //Function parameters are sent in the form of array
In the demo page, the result of clicking the first button is as follows:
The result of clicking the second and third buttons is as follows:
7. The function can be executed In itself
The following is very OK:
(function() { alert('hello'); })(); // Pop up 'hello'
The parsing here is simple enough: declare a function, and then execute it immediately because of () parsing . You may wonder why we do this (referring to the direct () call), which seems a bit contradictory: functions usually contain code that we want to execute later, rather than parsing and executing it now, otherwise , we don’t need to put the code in the function.
Another good use of self-executing functions (SEFs) is to use bound variable values in deferred code, such as event callbacks, timeouts and intervals. Execution(intervals). The following example:
var someVar ='hello';
setTimeout(function() { alert(someVar); }, 1000);
var someVar ='goodbye';
Newbies always ask in the forum why the timeout popup here is goodbye instead Not hello? The answer is that the callback function in timeout does not assign the value of the someVar variable until it is run. At that time, someVar had been rewritten by goodbye for a long time.
SEFs provide a solution to this problem. Instead of implicitly specifying the timeout callback as above, the someVar value is directly passed in as a parameter. The effect is significant, which means that we pass in and isolate the someVar value, protecting it from changing whether there is an earthquake, tsunami, or the girlfriend is roaring.
var someVar = 'hello';
setTimeout( (function(someVar) {
returnfunction() { alert(someVar); }
})(someVar), 1000);
var someVar ='goodbye';
Things have changed, and this time, the pop-up here is hello. This is the difference between function parameters and external variables.
For example, the popup after clicking the last button is as follows:
Browser
8. FireFox reads and returns colors in RGB format instead of Hex
Until now I have not really understood why Mozilla It will look like this. In order to have a clear understanding, look at the following example:
Hello, world!
< ;script>
var ie = navigator.appVersion.indexOf('MSIE') !=-1;
var p = document.getElementById('somePara');
alert(ie ? p.currentStyle. color : getComputedStyle(p, null).color);
The pop-up result of most browsers is ff9900, but the result of FireFox is rgb(255, 153, 0), in the form of RGB. Often, when dealing with colors, we need to spend a lot of code to convert RGB colors to Hex.
The following are the results of the above code in different browsers:
Other miscellaneous
9. 0.1 0.2 !== 0.3
This weird problem does not only appear in JavaScript , which is a common problem in computer science and affects many languages. The title equation outputs 0.30000000000000004.
This is a problem called machine precision. When JavaScript tries to execute the (0.1 0.2) line of code, it converts the value into its preferred binary flavor. This is where the problem starts, 0.1 is not actually 0.1, but its binary form. Essentially, when you write these values down, they are bound to lose precision. You might just want a simple two decimal places, but what you get (according to Chris Pine's comment) is a binary floating point calculation. For example, if you want to translate a paragraph into simplified Chinese, but the result is traditional, there are still differences.
There are generally two ways to deal with problems related to this:
Convert it to an integer and then calculate it, and then convert it to the desired decimal content after the calculation is completed
Adjust your logic and set the permission The range is not the specified result.
For example, we should not look like this:
var num1=0.1, num2=0.2, shouldEqual=0.3;
alert(num1 num2 == shouldEqual); //false
And you can try this:
alert(num1 num2 > shouldEqual - 0.001&& num1 num2 < shouldEqual 0.001); // true
10. Undefined can be defined
We end with a gentle and drizzly little quirk. As strange as it may sound, undefined is not a reserved word in JavaScript, although it has a special meaning and is the only way to determine whether a variable is undefined. Therefore:
var someVar;
alert(someVar = = undefined); //Show true
So far, everything seems calm and normal, but the plot is always bloody:
undefined ="I'm not undefined!";
var someVar;
alert(someVar == undefined ); // Display false!
This is why the outermost closure function in the jQuery source code has an undefined parameter that is not passed in. The purpose is to protect undefined from being taken advantage of by external bad actors. And enter.