A deep understanding of javascript function parameters and closures, and a deep understanding of javascript
Recently I have been studying javascript Functions. functions are the first-class objects of javascript. To learn javascript well, I must have a deep understanding of functions. I have compiled the learning process into an article. One is to deepen my understanding of functions, and the other is to provide readers with learning methods to avoid detours. There are a lot of content, but they are all my summary of the function.
1. Function Parameters
1.1: What is the parameter?
1.2: parameter omitted
1.3: Default Value
1.4: parameter transfer method
1.5: parameters with the same name
1.6: arguments object
2. Closure
2.1: Closure Definition
2.2: function expression to be called Immediately (IIFE, Immediately invoked function expression)
1. Function Parameters
1.1: What is the parameter?
When defining a function, you sometimes need to transmit additional data to the function. Different external data will get different results, which are called parameters.
function keith(a){ return a+a; } console.log(keith(3)); //6
In the code above, the parameter a is passed to the keith function and the expression a + a is returned.
1.2: parameter omitted
Function parameters are not required. The javascript specification allows you to omit the actual parameters passed during the call.
function keith(a, b, c) { return a; } console.log(keith(1, 2, 3)); //1 console.log(keith(1)); //1 console.log(keith()); // 'undefined'
In the code above, the keith function defines three parameters, but no matter how many parameters are passed during the call, javascript will not report an error. The default value of the parameter is undefined. All users who know function definitions and function scopes know that The length attribute of a function returns the number of parameters. Note that the length attribute is independent of the number of actual parameters, but only returns the number of formal parameters.
(Actual parameter: The parameter passed during the call. Format parameters: parameters passed during definition .)
However, there is no way to omit only the front element and keep the back element. If you must omit the previous element, only the display is passed into undefined.
function keith(a, b) { return a; } console.log(keith(, 1)); //SyntaxError: expected expression, got ',' console.log(keith(undefined, 2)); //'undefined'
In the code above, if the first parameter is omitted, the browser reports an error. If undefined is passed to the first parameter, no error is returned.
1.3: Default Value
In JavaScript, the default value of the function parameter is undefined. However, it is useful to set different default values in some cases. The general rule is to test whether the parameter value of the function subject is undefined. If so, a value is assigned. If not, the actual value passed by the parameter is returned.
function keith(a, b) { (typeof b !== 'undefined') ? b = b: b = 1; return a * b; } console.log(keith(15)); //15 console.log(keith(15, 2)) //30
The above Code makes a judgment. If the parameter B is not input during the call, the default value is 1.
The default parameters parameter is defined from ECMAScript 6 ). By using the default parameters, you no longer need to check the function body.
function keith(a, b = 1) { return a * b; } console.log(keith(15)); //15 console.log(keith(15, 2)) //30
1.4: parameter transfer method
Function parameters can be transmitted in two ways: Value passing and address passing.
When the function parameter is of the original data type (string, value, Boolean value), the parameter is transmitted as a value. That is to say, modifying the parameter value in the function body does not affect the function exterior.
var a = 1; function keith(num) { num = 5; } keith(a); console.log(a); //1
In the code above, global variable a is a value of the original type. The input function keith is used to pass the value. Therefore, in a function, the value of a is a copy of the original value. No matter how it is modified, it does not affect the original value.
However, if the function parameter is a composite value (array, object, or other functions), the transfer method is pass by reference ). That is to say, the input function is the address of the original value. Therefore, modifying the parameter inside the function will affect the original value.
var arr = [2, 5]; function keith(Arr) { Arr[0] = 3; } keith(arr); console.log(arr[0]); //3
In the code above, the input function keith is the address of the parameter object arr. Therefore, modifying the first value of arr within the function affects the original value.
Note: If a function is modified internally, instead of replacing the entire parameter, it does not affect the original value.
var arr = [2, 3, 5]; function keith(Arr) { Arr = [1, 2, 3]; } keith(arr); console.log(arr); // [2,3,5]
In the code above, in the function keith, the parameter object arr is replaced with another value. The original value is not affected. This is because the formal parameter (Arr) has a value assignment relationship with the actual parameter arr.
1.5: parameters with the same name
If a parameter of the same name exists, take the value that appears at the end. If the value of the last parameter is not provided, the value is undefined.
function keith(a, a) { return a; } console.log(keith(1, 3)); //3 console.log(keith(1)); //undefined
If you want to access the first parameter of the same name, use the arguments object.
function keith(a, a) { return arguments[0]; } console.log(keith(2)); //2
1.6 arguments object
Each function in JavaScript can access a special variable arguments. This variable maintains the list of all parameters passed to this function.
The arguments object contains all the parameters for the function runtime. arguments [0] is the first parameter, arguments [1] is the second parameter, and so on. This object can be used only within the function body.
You can access the length attribute of the arguments object to determine which parameters are included in the function call.
function keith(a, b, c) { console.log(arguments[0]); //1 console.log(arguments[2]); //3 console.log(arguments.length); //4 } keith(1, 2, 3, 4);
Relationship between arguments object and array
The arguments object is not an Array ). Although it has an Array-related attribute length in syntax, it does not inherit from Array. prototype. In fact, it is an Array-like object. Therefore, you cannot use standard array methods for arguments variables, such as push, pop, or slice. However, you can use the length attribute in the array.
The following method is usually used to convert an arguments object to an array.
var arr = Array.prototype.slice.call(arguments);
2. Closure
2.1: Closure Definition
To understand closures, you must first understand the differences between global scopes and local scopes. The function can access global variables defined in the global scope, but the function cannot access local variables defined in the internal scope of the function.
var a = 1;function keith() { return a; var b = 2; } console.log(keith()); //1 console.log(b); //ReferenceError: b is not defined
In the code above, global variable a can be accessed within function keith. However, local variable B cannot be accessed outside the function.
If you need to obtain the local variables inside the function, you can only define a function within the function.
function keith(){ var a=1; function rascal(){ return a; } return rascal; } var result=keith(); console.log(result()); //1 function keith(){ var a=1; return function(){ return a; }; } var result=keith(); console.log(result()) //1
In the above Code, the two statements are the same, and the only difference is whether internal functions are anonymous functions. The function rascal is inside the function keith, and all local variables inside keith are visible to rascal. However, the local variables in rascal are invisible to keith. This is the "chain scope" structure exclusive to the JavaScript language. The sub-object will first look up the variables of all parent objects. Therefore, all variables of the parent object are visible to the child object, and vice versa. The Return Value of the function keith is the function rascal. Because rascal can read the internal variables of keith, you can obtain the internal variables of keith externally.
The closure is the rascal function, that is, the function that can read the internal variables of other functions. In JavaScript, only the internal sub-functions of a function can read internal variables. Therefore, you can simply interpret a closure as a function defined in a function ". The biggest feature of a closure is that it can "remember" The environment where it was born. For example, rascal remembers its native environment, keith, so rascal can get the internal variables of keith.
A closure can make its birth environment always exist. Taking the following example, the closure enables internal variables to remember the operation results of the last call.
function keith(num) { return function() { return num++; }; } var result = keith(2); console.log(result()) //2 console.log(result()) //3 console.log(result()) //4
In the code above, the parameter num is actually equivalent to the local variable defined in the function keith. With the closure, the num state is retained, and each call is calculated based on the previous call. We can see that the closure result keeps the internal environment of the function keith.
Through the above example, we will summarize the features of the closure:
1: Define another function within a function and return the internal function or execute the internal function immediately.
2: internal functions can read local variables defined by external functions.
3: Keep local variables in the memory. That is to say, a closure can make its birth environment always exist.
Another use of closures is to encapsulate the private attributes and private methods of objects.
function Keith(name) { var age; function setAge(n) { age = n; } function getAge() { return age; } return { name: name, setAge: setAge, getAge: getAge }; } var person = Keith('keith'); person.setAge(21); console.log(person.name); // 'keith' console.log(person.getAge()); //21
2.2: function expression called immediately (IIFE)
Generally, this "immediate function expression" is used only for anonymous functions ". There are two purposes: first, you do not need to name the function to avoid global variables contamination; second, IIFE has a separate scope, which can encapsulate private variables that cannot be read from the outside.
Closure in Loop
A common error occurs when the closure is used in the loop. Suppose we need to call the loop serial number in each loop.
for(var i=0;i<10;i++){ setTimeout(function(){ console.log(i); //10 }, 1000) }
In the above Code, the number 0-9 is not output as expected. Instead, the number is output 10 times.
When an anonymous function is called, the anonymous function maintains a reference to the global variable I, that is, the result of the I loop is remembered. At this time, the for loop ends and the I value is changed to 10.
To get the desired effect and avoid referencing errors, we should use IIFE to create a copy of the full-board variable I in each loop.
for(var i = 0; i < 10; i++) { (function(e) { setTimeout(function() { console.log(e); //1,2,3,....,10 }, 1000); })(i); }
External anonymous functions are executed immediately and I is used as its parameter. In this case, the e variable in the function has a copy of I. When the anonymous function passed to setTimeout is executed, it has a reference to e, and this value will not be changed cyclically.
The above is all the content of this article. I hope this article will help you in your study or work. I also hope to provide more support to the customer's home!