10 JavaScript Difficulties You Need to Know in Front-end Development

1. Immediately execute the function
Immediately execute the function, namely Immediately Invoked Function Expression (IIFE), as its name, is to create the function and execute it immediately. It doesn't bind any events and doesn't need to wait for any async operations:

(function() {
     // 立即执行代码
     // ......
})();

The immediately executed function function(){…} is an anonymous function, and a pair of parentheses surrounding it converts it into an expression, followed by a pair of parentheses that call the function. Immediately executing a function can also be understood as calling an anonymous function immediately. The most common use case for an immediate function is to limit the scope of a var variable to your function to avoid naming conflicts.

2. Closures
For closures, when the outer function returns, the inner function can still access the variables of the outer function.

function f1()
{
    var N = 0; // N是f1函数的局部变量
    function f2() // f2f1函数的内部函数,是闭包
    {
        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, but 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. Defining private variables using closures
JavaScript developers prefix private variables with an underscore. But in fact, these variables can still be accessed and modified, not really private variables. At this point, using closures can define truly 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 property of the object p is a private property and cannot be directly accessed using p.name.

4. Prototype
has a prototype property for JavaScript constructors, which is used to set the properties and methods that all instance objects need to share, but the prototype property cannot be enumerated. JavaScript only supports inheritance of properties and methods through the prototype property.

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, both x and y are object instances created by the constructor Rectangle, and they inherit the getDimensions method through prototype.

5. Modular
JavaScript is not a modular programming language, at least not before ES6. However, for a complex web application, modular programming is a basic requirement. At this time, you can use the immediately executed function to achieve modularization, just as many JS libraries such as jQuery and our Fundebug are implemented in 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 modularity is to control the accessibility of properties and methods in the module as needed, that is, private or public. In the code, module is an independent module, N is its private property, print is its private method, decription 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, which is called variable hoisting (Hoisting). That is, wherever 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 declare them later.

However, only variable declarations are hoisted, not variable assignments. If you don't understand this, sometimes an error occurs:

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

Equivalent to the following code:

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

To avoid unnecessary bugs, developers should declare variables and functions at the beginning of each scope.
7.
Currying Currying, or Currying, can make functions more flexible. We can call it with multiple parameters at once; we can also call it with only a few parameters and let it return a function to handle the rest.

var add = function(x) {
    return function(y) {
        return x + y;
    };
};
console.log(add(3)(3)); // 输出6
var add3 = add(3);
console.log(add3(3)); // 输出6
var add11 = add(11);
console.log(add11(1)); // 输出12

In the code, we can pass in two 3s as parameters add(3)(3) at one time, or we can pass in one parameter to get the add3 and add11 functions, which is very flexible to use.

8. apply, call and bind methods
JavaScript developers need to understand the difference 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, which is equivalent to calling a function specifying this value:

var user = {
    name: "miss niu",
    whatIsYourName: function() {
        console.log(this.name);
    }
};
user.whatIsYourName(); // 输出"miss niu",
var user2 = {
    name: "mir guo"
};
user.whatIsYourName.call(user2); // 输出"mir guo"

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 needs to specify each parameter individually:

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

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

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 in memory, so that for the same input value, only the results need to be read from the memory next time.

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 in memory.

10. Function overloading

The so-called function overloading (method
overloading), is the same function name, but the input and output are not the same. In other words, allow a function to have various inputs, and return different results according to different inputs. Intuitively, function overloading can be done with if...else or switch, so leave it alone. The father of jQuery, John
Resig, came up with a very clever (bian) wonderful (tai) method, using closures.

In effect, the find method of the people object allows 3 different inputs:
when there are 0 parameters, it returns everyone's name; when it has 1 parameter, it searches for the person's name according to firstName and returns it; when there are 2 parameters, it searches for the person's name according to the complete name and returns it. return.

The difficulty is that people.find can only bind one function, so how can it handle 3 different inputs? It is impossible to bind three functions find0, find1 and find2 at the same time! The key here is the old property.

According to the calling sequence of the addMethod function, people.find is finally bound to the find2 function. However, when binding find2, old is find1; in the same way, when binding find1, old is find0. The three functions find0, find1 and find2 are linked through closures.

According to the logic of addMethod, when f.length does not match arguments.length, it will call old until it matches.

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"]

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325860306&siteId=291194637