Home  >  Article  >  Web Front-end  >  10 difficult points that must be mastered in JavaScript (must read)

10 difficult points that must be mastered in JavaScript (must read)

黄舟
黄舟Original
2018-05-11 11:13:517236browse

10 JavaScript difficulties that you may not know yet, don’t worry, this article lists them one by one and overcomes them one by one. Interested friends can refer to

to understand this blog JavaScript developers will not have bad luck...

1. Immediately execute the function

Immediately execute the function, that is, Immediately Invoked Function Expression (IIFE), as it is The name means that the function is executed immediately when it is created. It does not bind any events and does not need to wait for any asynchronous operations:

(function() {
 // 代码
 // ...
})();

function(){…} is an anonymous function, and a pair of parentheses surrounding it convert it into an expression, followed by A pair of parentheses calls this function. Executing a function immediately can also be understood as calling an anonymous function immediately. The most common application scenario of executing a function immediately is to limit the scope of the var variable to your function, so as to avoid naming conflicts.

2. Closure

For closure, when the external function returns, the internal function can still access the variables of the external function.

function f1()
{
 var N = 0; // N是f1函数的局部变量
 function f2() // f2是f1函数的内部函数,是闭包
 {
 N += 1; // 内部函数f2中使用了外部函数f1中的变量N
 console.log(N);
 }
 return f2;
}
var result = f1();
result(); // 输出1
result(); // 输出2
result(); // 输出3

In the code, the external function f1 is executed only once, the variable N is set to 0, and the internal function f2 is assigned to the variable result. Since the external function f1 has been executed, its internal variable N should be cleared in the memory. However, this is not the case: every time we call result, we find that the variable N has been in the memory and is accumulating. why? This is the magic of closures!

3. Use closures to define private variables

Usually, JavaScript developers use underscores as prefixes for private variables. But in fact, these variables can still be accessed and modified, and are not truly private variables. At this time, you can use closures to define real private variables:

function Product() {
 var name;
 this.setName = function(value) {
 name = value;
 };
 this.getName = function() {
 return name;
 };
}
var p = new Product();
p.setName("Fundebug");
console.log(p.name); // 输出undefined
console.log(p.getName()); // 输出Fundebug

In the code, the name attribute of object p is a private attribute and cannot be accessed directly using p.name.

4. prototype

Each JavaScript constructor has a prototype attribute, which is used to set the properties and methods that all instance objects need to share. The prototype property cannot be enumerated. JavaScript only supports inheritance of properties and methods through the prototype attribute.

function Rectangle(x, y)
{
 this._length = x;
 this._breadth = y;
}
Rectangle.prototype.getDimensions = function()
{
 return {
 length: this._length,
 breadth: this._breadth
 };
};
var x = new Rectangle(3, 4);
var y = new Rectangle(4, 3);
console.log(x.getDimensions()); // { length: 3, breadth: 4 }
console.log(y.getDimensions()); // { length: 4, breadth: 3 }

In the code, x and y are both object instances created by the constructor Rectangle, and they inherit the getDimensions method through prototype.

5. Modularity

JavaScript is not a modular programming language, at least not until ES6 is implemented. However, for a complex Web application, modular programming is the most basic requirement. At this time, you can use immediate execution functions to achieve modularity, just as many JS libraries such as jQuery and our Fundebug are implemented this way.

var module = (function() {
 var N = 5;
 function print(x) {
 console.log("The result is: " + x);
 }
 function add(a) {
 var x = a + N;
 print(x);
 }
 return {
 description: "This is description",
 add: add
 };
})();
console.log(module.description); // 输出"this is description" 
module.add(5); // 输出“The result is: 10”

The so-called modularization is to control the accessibility of attributes and methods in the module according to needs, that is, private or public. In the code, module is an independent module, N is its private property, print is its private method, description is its public property, and add is its public method.

6. Variable Hoisting

JavaScript will move all variable and function declarations to the front of its scope. This is called variable hoisting (Hoisting). That is, no matter where you declare variables and functions, the interpreter will move them to the front of the scope. So we can use variables and functions first and then declare them.

However, only the variable declaration is promoted, but the variable assignment will not be promoted. If you don't understand this, sometimes an error will occur:

console.log(y); // 输出undefined
y = 2; // 初始化y

The above code is equivalent to the following code:

var y; // 声明y
console.log(y); // 输出undefined
y = 2; // 初始化y

To avoid bugs, developers should start each scope with Declare variables and functions.

7. Currying

Currying, that is, Currying, can make functions more flexible. We can call it by passing in multiple parameters at once; we can also call it by passing in only part of the parameters and let it return a function to process the remaining parameters.

var add = function(x) {
 return function(y) {
 return x + y;
 };
};
console.log(add(1)(1)); // 输出2
var add1 = add(1);
console.log(add1(1)); // 输出2
var add10 = add(10);
console.log(add10(1)); // 输出11

In the code, we can pass in two 1's as parameters to add(1)(1) at one time, or we can pass in one parameter and then get the add1 and add10 functions, which is very flexible to use.

8. apply, call and bind methods

JavaScript developers need to understand the differences between apply, call and bind methods. What they have in common is that the first parameter is this, which is the context that the function depends on when running.

Among the three, the call method is the simplest. It is equivalent to calling a function by specifying this value:

var user = {
 name: "Rahul Mhatre",
 whatIsYourName: function() {
 console.log(this.name);
 }
};
user.whatIsYourName(); // 输出"Rahul Mhatre",
var user2 = {
 name: "Neha Sampat"
};
user.whatIsYourName.call(user2); // 输出"Neha Sampat"

The apply method is similar to the call method. The only difference between the two is that the apply method uses an array to specify parameters, while the call method requires each parameter to be specified individually:

apply(thisArg, [argsArray])
call(thisArg, arg1, arg2, …)
var user = {
 greet: "Hello!",
 greetUser: function(userName) {
 console.log(this.greet + " " + userName);
 }
};
var greet1 = {
 greet: "Hola"
};
user.greetUser.call(greet1, "Rahul"); // 输出"Hola Rahul"
user.greetUser.apply(greet1, ["Rahul"]); // 输出"Hola Rahul"

Using the bind method, you can bind this value to the function and then use it as a new function Return:

var user = {
 greet: "Hello!",
 greetUser: function(userName) {
 console.log(this.greet + " " + userName);
 }
};
var greetHola = user.greetUser.bind({greet: "Hola"});
var greetBonjour = user.greetUser.bind({greet: "Bonjour"});
greetHola("Rahul") // 输出"Hola Rahul"
greetBonjour("Rahul") // 输出"Bonjour Rahul"

9. Memoization

Memoization is used to optimize time-consuming calculations by caching the calculation results into memory, so that for the same input value, Next time you only need to read the results from memory.

function memoizeFunction(func)
{
 var cache = {};
 return function()
 {
 var key = arguments[0];
 if (cache[key])
 {
  return cache[key];
 }
 else
 {
  var val = func.apply(this, arguments);
  cache[key] = val;
  return val;
 }
 };
}
var fibonacci = memoizeFunction(function(n)
{
 return (n === 0 || n === 1) ? n : fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(100)); // 输出354224848179262000000
console.log(fibonacci(100)); // 输出354224848179262000000

In the code, the second calculation of fibonacci(100) only needs to read the result directly from the memory.

10. Function overloading

所谓函数重载(method overloading),就是函数名称一样,但是输入输出不一样。或者说,允许某个函数有各种不同输入,根据不同的输入,返回不同的结果。凭直觉,函数重载可以通过if…else或者switch实现,这就不去管它了。jQuery之父John Resig提出了一个非常巧(bian)妙(tai)的方法,利用了闭包。

从效果上来说,people对象的find方法允许3种不同的输入: 0个参数时,返回所有人名;1个参数时,根据firstName查找人名并返回;2个参数时,根据完整的名称查找人名并返回。

难点在于,people.find只能绑定一个函数,那它为何可以处理3种不同的输入呢?它不可能同时绑定3个函数find0,find1与find2啊!这里的关键在于old属性。

由addMethod函数的调用顺序可知,people.find最终绑定的是find2函数。然而,在绑定find2时,old为find1;同理,绑定find1时,old为find0。3个函数find0,find1与find2就这样通过闭包链接起来了。

根据addMethod的逻辑,当f.length与arguments.length不匹配时,就会去调用old,直到匹配为止。

function addMethod(object, name, f)
{  
 var old = object[name];  
 object[name] = function()
 {
 // f.length为函数定义时的参数个数
 // arguments.length为函数调用时的参数个数    
 if (f.length === arguments.length)
 {  
  return f.apply(this, arguments);    
 }
 else if (typeof old === "function")
 {
  return old.apply(this, arguments);    
 }  
 };
}
// 不传参数时,返回所有name
function find0()
{  
 return this.names;
}
// 传一个参数时,返回firstName匹配的name
function find1(firstName)
{  
 var result = [];  
 for (var i = 0; i < this.names.length; i++)
 {    
 if (this.names[i].indexOf(firstName) === 0)
 {      
  result.push(this.names[i]);    
 }  
 }  
 return result;
}
// 传两个参数时,返回firstName和lastName都匹配的name
function find2(firstName, lastName)
{ 
 var result = [];  
 for (var i = 0; i < this.names.length; i++)
 {    
 if (this.names[i] === (firstName + " " + lastName))
 {      
  result.push(this.names[i]);    
 }  
 }  
 return result;
}
var people = {  
 names: ["Dean Edwards", "Alex Russell", "Dean Tom"]
};
addMethod(people, "find", find0);
addMethod(people, "find", find1);
addMethod(people, "find", find2);
console.log(people.find()); // 输出["Dean Edwards", "Alex Russell", "Dean Tom"]
console.log(people.find("Dean")); // 输出["Dean Edwards", "Dean Tom"]
console.log(people.find("Dean", "Edwards")); // 输出["Dean Edwards"]

The above is the detailed content of 10 difficult points that must be mastered in JavaScript (must read). For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn