Intensive lectures on important and difficult points of JavaScript with examples

Invisible pit of map() function and parseInt() function

  1. Example: There is an array, and each element in the array is a string of type Number ['1', '2', '3', '4'], if we want to convert all the elements in the array to integers , what should I do?

We might think of calling the parseInt() function in the Array's map() function. Like this:

var arr = ['1', '2', '3', '4'];
var result = arr.map(parseInt);
console.log(result);

But after running, the result is [1, NaN, NaN, NaN], which is very different from the expected result [1, 2, 3, 4]. In fact, this is a function hidden in map() and parseInt( ) invisible pit in the function.

arr.map(parseInt)

The above code is effectively equivalent to the following:

arr.map(function (val, index) {
    
    
    return parseInt(val, index);
});

The second parameter received by the parseInt() function is actually the index value of the array, so the actual processing process is as follows.

parseInt('1', 0);  // 1
parseInt('2', 1);  // NaN
parseInt('3', 2);  // NaN
parseInt('4', 3);  // NaN

Any integer rounded to base 0 returns itself, so the first line of code returns "1".

The second line of code parseInt('2', 1), because the radix corresponding to the parseInt() function can only be 2 to 36, and integers that do not meet the radix will return "NaN" after processing;

The third line of code parseInt('3', 2) means that 3 is processed as a binary representation. In fact, there are only 0 and 1 in binary, and 3 is beyond the range of binary representation. It cannot be converted and returns "NaN";

The fourth line of code parseInt('4', 3), similar to the third line, 4 cannot be represented by ternary data and returns "NaN".

Therefore, we need to pay attention to this when using the parseInt() function in the map() function. You cannot directly use the parseInt() function as a parameter of the map() function, but need to use it in the callback function of the map() function, and try to Specify the radix, the code is as follows.

var arr = ['1', '2', '3', '4'];

var result = arr.map(function (val) {
    
      
    return parseInt(val, 10);
});

console.log(result);  // [1, 2, 3, 4]

isNaN() function and Number.isNaN() function

There is a special value NaN (Not a Number) in the Number type data, which indicates that the value should be returned but the value is not returned.

The purpose of NaN is to ensure the normal execution of the program under certain abnormal conditions. For example, 0/0, in other languages, the program will throw an exception directly, but in JavaScript it will return "NaN", and the program can be executed normally.

The characteristics of NaN:

    1. Any operation involving NaN returns "NaN"
    1. NaN is not equal to any value, including NaN itself

When judging NaN, ES5 provides the isNaN() function, and ECMAScript 6 (hereinafter referred to as ES6) adds a static function isNaN() for the Number type.

Since the isNaN() function is provided in ES5, why should the Number.isNaN() function be added in ES6? What is the difference between the two in use?

This is because the isNaN() function itself is misleading, and the Number.isNaN() function in ES6 will really judge whether the variable is NaN, and will not perform data type conversion. Returns "true" only if the value passed in is NaN, and returns "false" for any other type of value.

You can test it with the following code:

isNaN(NaN);       // true
isNaN(undefined);  // true
isNaN({
    
    });        // true

isNaN(true);      // false,Number(true)会转换成数字1
isNaN(null);      // false,Number(null)会转换成数字0
isNaN(1);         // false
isNaN('');        // false,Number('')会转换为成数字0
isNaN("1");            // false,字符串"1"可以转换成数字1
isNaN("JavaScript");   // true,字符串"JavaScript"无法转换成数字
// Date类型
isNaN(new Date());     // false
isNaN(new Date().toString());  // true

// Date是一种比较特殊的类型,当我们调用new Date()函数生成的实例并转换为数值类型时,
// 会转换为对应的时间戳,例如下面的代码
Number(new Date()); // 1543333199705
Number.isNaN(NaN);        // true
Number.isNaN(undefined);   // false
Number.isNaN(null);       // false
Number.isNaN(true);       // false
Number.isNaN('');         // false
Number.isNaN(123);        // false

Summarize:

The difference between the isNaN() function and the Number.isNaN() function is as follows:

  • The isNaN() function needs to convert the data type first when judging whether it is NaN, and only returns "true" when it cannot be converted to a number
  • When the Number.isNaN() function judges whether it is NaN, it only needs to judge whether the incoming value is NaN, and does not perform data type conversion.

Commonly used methods for judging null in JavaScript

1. Determine whether the variable is an empty object

function isEmpty(obj) {
    
    
  for(let key in obj) {
    
    
      if(obj.hasOwnProperty(key)) {
    
    
         return false;
      }
  }
  return true;
}

2. Determine whether the variable is an empty array

arr instanceof Array && arr.length === 0

3. Judgment variable is an empty string

str == '' || str.trim().length == 0;

4. Determine whether the variable is 0 or NaN

!(Number(num) && num) == true;

What exactly does the new operator do?

The new operator will change the direction of this during execution, so before understanding the new operator, let's explain the usage of this.

function Cat(name, age) {
    
    
   this.name = name;
   this.age = age;
}
console.log(new Cat('miaomiao',18));  // Cat {name: "miaomiao", age: 18}

The output results contain name and age information. In fact, we did not return any value through return, why does the output information include the name and age attributes? What works is the this keyword.

We output this through the following code to see the specific content of this.

function Cat(name,age) {
    
    
   console.log(this);  // Cat {}
   this.name = name;
   this.age = age;
}
new Cat('miaomiao',18);

We can find that the actual value of this is an empty Cat object, and the last two sentences are equivalent to adding name and age attributes to the Cat object. Is this really the case? Why don't we rewrite the Cat function.

function Cat(name,age){
    
    
   var Cat = {
    
    };
   Cat.name = name;
   Cat.age = age;
}
console.log(new Cat('miaomiao',18));  // Cat {}

The name and age attributes are not included in the output, why?

Because in JavaScript, if the function has no return value, it returns this by default. The this in the above code is actually a Cat empty object, and the name and age properties are just added to the temporary variable Cat. In order to allow the output to include the name and age attributes, we simply return the temporary variable Cat.

function Cat(name, age) {
    
    
   var Cat = {
    
    };
   Cat.name = name;
   Cat.age = age;
   return Cat;
}
console.log(new Cat('miaomiao', 18));  // {name: "miaomiao", age: 18}

The final return value contains the name and age attributes. Through the above analysis, we understand the usage of this in the constructor, so what is the relationship between it and the new operator?

Let's take a look at the following simple line of code. The function of this code is to generate an instance of a Cat object through the new operator.

var cat = new Cat();

On the surface, the main function of this line of code is to create an instance of the Cat object, and assign this instance value to the cat variable, and the cat variable will contain the properties and functions of the Cat object.
In fact, the new operator does three things, as shown in the following code.

1. var cat = {
    
    };
2. cat._ _proto_ _  =  Cat.prototype;
3. Cat.call(cat);

First line: Create an empty object.
The second line: point the __proto__ attribute of the empty object to the prototype attribute of the Cat object.
The third line: Point this in the Cat() function to the cat variable.

The cat variable is then an instance of the Cat object.

We customize a function similar to the new function to explain the above 3 lines of code in detail.

function Cat(name, age) {
    
    
   this.name = name;
   this.age = age;
}
function New() {
    
    
   var obj = {
    
    };
   var res = Cat.apply(obj, arguments);
   return typeof res === 'object' ? res : obj;
}
console.log(New('mimi', 18));  //Object {name: "mimi", age: 18}

The returned result also contains the name and age attributes, which proves that the new operator has changed the pointing of this. After Cat.apply(obj, arguments) is called, this in the Cat object points to the obj object, so the obj object has the name and age attributes.

Therefore, not only the function itself of the new operator should be paid attention to, but also its prototype property.

We make changes to the above code, add a sayHi() function to the prototype of the Cat object, and then use the object returned by the New() function to call the sayHi() function to see how it is executed.

function Cat(name, age) {
    
    
   this.name = name;
   this.age = age;
}

Cat.prototype.sayHi = function () {
    
    
   console.log('hi')
};

function New() {
    
    
   var obj = {
    
    };
   var res = Cat.apply(obj, arguments);
   return typeof res === 'object' ? res : obj;
}
console.log(New('mimi', 18).sayHi());

The result of running the above code is as follows:

Uncaught TypeError: New(...).sayHi is not a function

We found that the execution error was reported. The object returned by the New() function did not call the sayHi() function. This is because the sayHi() function belongs to the Cat prototype function. Only objects on the Cat prototype chain can inherit the sayHi() function. Then How should we do it?

What needs to be used here is the __proto__ attribute. The __proto__ attribute of the instance points to the prototype of the corresponding function when the instance object is created. Set the __proto__ value of the obj object to the prototype attribute of the Cat object, then the obj object inherits the sayHi() function on the Cat prototype, so that the sayHi() function can be called.

function Cat(name, age) {
    
    
   this.name = name;
   this.age = age;
}

Cat.prototype.sayHi = function () {
    
    
   console.log('hi')
};

function New() {
    
    
   var obj = {
    
    };
   obj._ _proto_ _ = Cat.prototype;  // 核心代码,用于继承
   var res = Cat.apply(obj, arguments);
   return typeof res === 'object' ? res : obj;
}
console.log(New('mimi', 18).sayHi());

As a result, "hi" is output, and the method call is successful.

おすすめ

転載: blog.csdn.net/weixin_43867717/article/details/128393216