If the object is a room, the function is a room with a magic effect. The function is an object first, and the function object has many magical functions.
Variable type
Before talking about functions, let's talk about variable types.
1. variables: variables are essentially named memory space.
2. Data Type of the variable: it refers to the Data Type of the value that the variable can store, such as the Number type, Boolean type, and Object type. In ECMAScript, the data type of the variable is dynamic. You can change the data type of the variable at runtime.
3. Variable type: it refers to the type of the variable itself. In ECMAScript, there are only two types of variables: Value Type and reference type. When the data type of a variable is a simple data type, the variable type is the value type. When the Data Type of a variable is an object type, the variable type is the reference type. Without ambiguity, the Data Type of a variable can also be called the variable type.
So what is the difference between the value type and the reference type? The most important one is that when the variable type is the value type, the variable stores the variable value itself. When the variable type is the reference type, the variable is not stored as the variable value, it is just a pointer to the variable value. When accessing the variable value of the reference type, the pointer is obtained first, and then the variable value is obtained based on the pointer. If a variable value of the reference type is assigned to another variable, the final result is that the two variables point to a variable value at the same time. If you modify one of the variables, it will be modified to the other:
The Code is as follows:
Var a = {
Name: 'linjisong ',
Age: 29
};
Var B = a; // assign variable a of the reference type to variable B. both a and B point to the object starting with.
B. name = 'external'; // modify the object to which B points, that is, the object to which a points.
Console.info (a. name); // oulinhai
B = {// assign a value to the variable again, but the object originally pointed to by B has not changed, that is, the object pointed to by a has not changed.
Name: 'hujin ',
Age: 23
};
Console.info (a. name); // oulinhai
Well, let's talk about the variable type first. If we continue to store the data structure in the memory, we will not be able to sink down.
Function
If the object is a room, the function is a room with a magic effect. A function is an object first, and this function object also has many magical functions ......
1. Functions
(1) The function is an object.
A Function is also an object. A Function used to create a Function object instance is a built-in Function () Function. To create an object instance, a Function is required. A Function is an object instance, are you confused about having a chicken or an egg? Don't drill the corners, as long as the chicken can give up eggs, the eggs can hatch the chicken, who should leave it to the philosophers first), but functions such objects are very different from general objects, so that when typeof is used for function object instances, the returned function is not an object but a function.
(2) The function name is a reference type variable pointing to the function object.
The Code is as follows:
Function fn (p ){
Console.info (p );
}
Console.info (fn); // fn (p), which can be accessed using fn as a general variable
Var B = fn;
B ('function'); // function, which can be called by function B. It indicates that the object pointed to by B (that is, the object pointed to by fn) is a function.
Note: For function names, eval and arguments are no longer allowed in strict ES5 mode. Of course, neither of the two parameter names can be used. (unless you are a professional hacker, you will not use these two names as identifiers ).
2. Create a function
(1) As an object, a Function can be created in a way similar to a common object. Using new to call the constructor Function (), a Function can accept any number of parameters, the last parameter is used as the function body, and all the preceding parameters are used as the function form parameters. The preceding form parameters can also be separated by commas (,) and passed in as a parameter. Generally, the form is:
The Code is as follows:
Var fn = new Function (p1, p2,..., pn, body );
// Or
Var fn = Function (p1, p2,..., pn, body );
// Or
Var fn = new Function ("p1, p2,..., pn", q1, q2,..., qn, body );
// Or
Var fn = Function ("p1, p2,..., pn", q1, q2,..., qn, body );
For example:
The Code is as follows:
Var add = new Function ('A', 'B', 'Return a + B ;');
Console.info (add (2, 1); // 3
Var subtract = Function ('A', 'B', 'Return a-B ;');
Console.info (subtract (2, 1); // 1
Var sum = new Function ('a, B ', 'C', 'Return a + B + c ;');
Console.info (sum (1, 2, 3); // 6
When a function is created in this way, the code is parsed twice, and the function body is parsed at a normal time, which may affect the efficiency. However, this method is more suitable for dynamic compilation of the function body.
(2) because of the special nature of the function object, we can also use the keyword function to create a function:
The Code is as follows:
Function add (a, B ){
Return a + B;
}
Console.info (add (2, 1); // 3
Var subtract = function (a, B ){
Return a-B;
};
Console.info (subtract (2, 1); // 1
As shown in the preceding figure, you can use the function keyword to create a function in two ways: function declaration and function expression. The two methods can achieve what we want. What is the difference between them? This is what we will talk about below.
3. function declaration and function expression
(1) from the form of distinction, in the specification of the ECMA-262, you can see:
The Code is as follows:
Function declaration: function Identifier (parameter list (optional) {function body}
Function expression: function Identifier (optional) (parameter list (optional) {function body}
There is no difference except that the identifier (function name) of the function expression is optional, but we can also know that the function expression is not available. Of course, if there is a function name, we can only judge it from context.
(2) Distinguish from context. This is simple to say: only the context in which an expression appears must be a function expression, and only the context that can be declared must be a function declaration. For example:
The Code is as follows:
Function fn () {}; // function declaration
// Function fn () {} (); // exception. function declaration cannot be called directly.
Var fn = function fn () {}; // function expression
(Function fn () {}); // function expression, within the grouping Operator
+ Function fn () {console.info (1) ;}(); // 1, a function expression that appears after the operator +, so you can call it directly. Here, you can also use other operators, such as new
New function fn () {console.info (2) ;}(); // 2, function expression, after the new operator
(Function (){
Function fn () {}; // function declaration
});
(3) Difference: Why do we need to make so much effort to distinguish between function declarations and function expressions? Naturally, because of their differences, the biggest difference between them is that the declaration will be upgraded. In the previous article on the basic syntax, I have discussed the Declaration escalation in the global scope. Let's review the conclusions here:
A. when parsing, the engine will first parse the function declaration, then parse the variable Declaration (the type will not be overwritten during parsing), and then execute the Code;
B. when parsing a function declaration, it will parse the type (function) at the same time, but it will not be executed. when parsing the variable declaration, it will only parse the variable and will not initialize it.
There are some examples for demonstration (recall), but there is no declaration example with the same name. Here we will add:
The Code is as follows:
Lele.info (typeof fn); // function, which declares to be upgraded. The function prevails.
Var fn = '';
Function fn (){
}
Console.info (typeof fn); // string, because the code has been executed, the fn type is changed to string
Try {
Fn (); // It is already of the string type and cannot be called. A type exception is thrown.
} Catch (e ){
Lele.info (e); // TypeError
}
Fn = function () {lele.info ('fn ') ;}; // if you want to call fn, you can only assign a value to fn using a function expression.
Fn (); // fn, which can be called
Console.info (typeof gn); // function
Function gn (){
}
Var gn = '';
Console.info (typeof gn); // string
We can see that, no matter whether the variable declaration is in the front or back, the function declaration takes precedence over the Declaration escalation. However, after the declaration escalation, the variable Initialization is required, function declaration is no longer initialized (the function type is parsed when it is upgraded), so it becomes a String type when it is output later.
The above 3rd rows define a function, and then 7th rows will be called immediately, and the result will not work! You should understand the importance of keeping the global namespace clean. Otherwise, you may encounter a ghost like "I clearly defined a function in the Code but cannot call it, if you want to make sure that the defined function is available, you 'd better use a function expression to define it. Of course, to do so, you need to risk cracking others' code.
There is another question: how can we determine that the variable type is changed during initialization rather than During Variable declaration elevation? See the following code:
The Code is as follows:
Console.info (typeof fn); // function
Function fn (){
}
Var fn;
Console.info (typeof fn); // function
We can see that the declared upgraded type is function, and the final type is not changed because no initialization code is available.
For more information about function declarations and function expressions, see the following code:
The Code is as follows:
If (true ){
Function fn (){
Return 1;
}
} Else {
Function fn (){
Return 2;
}
}
Console.info (fn (); // output 1 in Firefox, 2 in Opera, declare upgrade in Opera, and the subsequent declaration will overwrite the previous declaration of the same level.
If (true ){
Gn = function (){
Return 1;
};
} Else {
Gn = function (){
Return 2;
};
}
Console.info (gn (); // 1, all browsers output 1
In the ECMAScript specification, the identifier of the name function expression belongs to the internal scope, and the identifier of the function declaration belongs to the defined scope.
The Code is as follows:
Var sum = function fn (){
Var total = 0,
L = arguments. length;
For (; l --)
{
Total + = arguments L-1 1];
}
Console.info (typeof fn );
Return total;
}
Console.info (sum (1, 2, 3, 4); // function, 10
Console.info (fn (1, 2, 3, 4); // ReferenceError
The above is the running result of a naming function expression in FireFox. This name can be accessed within the function scope, but a reference exception occurs during access in the global scope. However, the name function expression will be parsed as a function declaration and function expression in IE browser before IE9, and two objects will be created. Fortunately, IE9 has been corrected.
In addition to the global scope, there is also a function scope. In the function scope, there are also function parameters involved in the declaration and promotion competition. First, it should be clear that the function scope does not exist when the function is defined. Function scope is available only when the function is actually called.
The Code is as follows:
// Parameter and internal variable, parameter priority
Function fn (inner ){
Console.info (inner); // param
Lele.info (other); // undefined
Var inner = 'inner ';
Var other = 'other ';
Console.info (inner); // inner
Lele.info (other); // other
}
Fn ('param ');
// Parameter and internal function, internal function first
Function gn (inner ){
Lele.info (inner); // inner () function
Console.info (inner (); // undefined
Function inner (){
Return other;
}
Var other = 'other ';
Lele.info (inner); // inner () function
Console.info (inner (); // other
}
Gn ('param ');
Through the above output result, we get the priority: internal function declaration> function parameters> internal variable declaration.
Here, the process is: first, the internal function declaration is upgraded, and the type of the function name is set to the function type, then the function parameter is parsed, And the passed actual parameter value is assigned to the form parameter, finally, the internal variable declaration is promoted. Only the declaration is promoted without initialization. If there is a duplicate name, the same priority will be followed by the previous one, and the different priorities will not be overwritten (the higher priority has been resolved, ).
This is just my inference based on the output results. As for the background implementation, the steps may be completely opposite, and each step overwrites the results of the previous step, or even starts from the middle, then, make a priority flag to determine whether to overwrite the data. Of course, from the perspective of efficiency, it should be that the process I infer will be better. In addition, the global scope is actually a simplified version of the function scope without function parameters.
Here we will not give a comprehensive example. We suggest reading this article together with the previous basic syntax, which may be better. The following question is also raised about priority and coverage.
4. Function Overloading
A function is an object, and a function name is a reference type variable pointing to a function object. This makes it impossible for us to implement overload as in general object-oriented languages:
The Code is as follows:
Function fn (){
Return;
}
Function fn (a, B ){
Return a + B;
}
Console.info (fn (1); // NaN
Console.info (fn (1, 2); // 3
Do not be surprised about the output NaN of 8th actions, because the function name is only a variable. The two function declarations will be parsed in sequence, and the final function that the variable points to is the second function, in row 8th, only one parameter is input. In the function, B is automatically assigned an undefined value and then added to 1. The result is NaN. If you replace it with a function expression, you may have a better understanding of it. It's just a matter of assigning values twice. Naturally, the subsequent values will overwrite the previous values:
The Code is as follows:
Var fn = function (a) {return ;}
Fn = function (a, B) {return a + B ;}
In ECMAScript, how does one implement overloading? Recall that a simple data type packaging object (Boolean, Number, String) can be used to create an object as a constructor or as a conversion function to convert the data type. This is a typical overload. This overload was actually discussed in the previous article:
(1) overload Based on the function. The general format of this method is:
The Code is as follows:
Function fn (){
If (this instanceof fn)
{
// Function 1
} Else
{
// Function 2
}
}
Although this method is feasible, it is obviously limited. For example, you can only reload twice and only include constructors. Of course, you can use the bind () added in apply (), call (), or ES5 to dynamically bind the this value in the function to expand the overload, however, this means that the function is overloaded based on the internal attributes of the function.
(2) overload based on the internal properties of the Function
The Code is as follows:
Function fn (){
Var length = arguments. length;
If (0 = length) // put the literal to the left is a habit from Java, because if the comparison operator is written as the value assignment operator (0 = length, the compiler prompts me an error. If you are not used to this method, please forgive me
{
Return 0;
} Else if (1 = length)
{
Return + arguments [0];
} Else {
Return (+ arguments [0]) + (+ arguments [1]);
}
}
Console.info (fn (); // 0
Console.info (fn (1); // 1
Console.info (fn (true); // 1
Console.info (fn (1, 2); // 3
Console.info (fn ('1', '2'); // 3
Here, the arguments attribute in the function is used for overloading. Of course, there are multiple methods of internal overloading. You can also use typeof, instanceof, and other operators to implement the functions you want. What is the internal attribute arguments? This is what we will talk about below.
5. arguments
To put it simply, the internal attribute of a function is the attribute that can only be accessed in the function body. Because the function body is executed only when the function is called, therefore, the internal attributes of a function can be parsed only when the function is called. Each call has a corresponding resolution, so it has dynamic characteristics. These attributes are: this and arguments. Here we will first look at arguments and talk about this in the next article.
(1) The parameter list in the function definition is called a formal parameter, and the actual parameter actually passed in when the function is called an actual parameter. In general C language, the actual parameters must be the same as the formal parameters during function calling, but in ECMAScript, there is no limit between the two, you can have two formal parameters when defining them, and two actual parameters when calling them, but you can also input three actual parameters, you can also pass in only one actual parameter, even if you do not pass any parameter. This feature is the basis for using the internal attributes of a function to implement overloading.
(2) formal parameters can even have the same name, only the following values will be taken as the values of the form parameters during actual input (in this case, you can use arguments to access the actual parameters above ):
The Code is as follows:
Function gn (a, ){
Console.info ();
Console.info (arguments [0]);
Console.info (arguments [1]);
}
Gn (1, 2); // 2, 1, 2
Gn (1); // undefined, 1, undefined
In fact, this can also be explained by the conclusion above about the declaration of improvement: the latter of the same priority overwrites the former, and the value is resolved at the same time when the function parameter is parsed. Of course, security becomes very problematic. Therefore, in the strict ES5 mode, duplicate parameters are forbidden.
(3) The actual parameter value is accepted by the formal parameter, but what if the actual parameter and the formal parameter are inconsistent? The answer is to use arguments for storage. In fact, even if the actual parameters are the same as the formal parameters, the arguments object exists, and the synchronization between them and the formal parameters that have accepted the actual parameters is maintained. I will elaborate on this sentence to understand it:
• Arguments is an array object of the class. You can access the arguments elements, such as arguments [0] And arugments [1], by using square brackets and indexes as you access the array elements.
• Arguments is a class array Object. In addition to inheriting the attributes and methods of the Object (some methods have been rewritten), arguments also has its own attributes, such as length, callee, and caller, here, length indicates the number of actual parameters (number of formal parameters? That is, the function property length). callee indicates the current function object, and caller is defined to distinguish it from the function property caller. Its value is undefined.
• Arguments is a class Array object, but it is not a real Array object. You cannot directly call the Array object method for arguments. To call arguments, you can use Array first. prototype. slice. call (arguments) is first converted to an array object.
• Arguments stores the actual parameters passed in when the function is called, the first actual parameter is saved for 0th elements, the second actual parameter is saved for 1st elements, and so on.
• Arguments stores the actual parameter value, while the formal parameter also saves the actual parameter value. There is a synchronization relationship between the two, and one and the other will be modified accordingly.
• The synchronization between arguments and the formal parameters exists only when the formal parameters actually receive the actual parameters. This synchronization relationship does not exist for the formal parameters that do not receive the actual parameters.
• Although the arguments object is powerful, there is a certain amount of loss in terms of performance. Therefore, if not necessary, do not use it. We recommend that you use formal parameters first.
The Code is as follows:
Fn (0,-1 );
Function fn (para1, para2, para3, para4 ){
Console.info (fn. length); // 4, number of formal parameters
Console.info (arguments. length); // 2, the actual number of parameters
Console.info (arguments. callee = fn); // true, the callee object points to the fn itself
Lele.info (arguments. caller); // undefined
Console.info (arguments. constructor); // Object () instead of Array ()
Try {
Arguments. sort (); // The class array is not an array after all. You cannot directly call the array method and throw an exception.
} Catch (e ){
Lele.info (e); // TypeError
}
Var arr = Array. prototype. slice. call (arguments); // convert it to an Array first.
Console.info (arr. sort (); // [-1, 0], sorted
Console.info (para1); // 0
Arguments [0] = 1;
Console.info (para1); // 1. Modify arguments [0] and the format parameter para1 will be modified simultaneously.
Console.info (arguments [1]); //-1
Para2 = 2;
Console.info (arguments [1]); // 2. The format parameter para2 is modified synchronously. arguments [1]
Console.info (para3); // undefined. The format parameter undefined is not input.
Arguments [2] = 3;
Console.info (arguments [2]); // 3
Console.info (para3); // undefined. The actual parameter format is not accepted and there is no synchronization relationship between the parameters.
Console.info (arguments [3]); // undefined. The actual parameter is not input and the value is undefined.
Para4 = 4;
Console.info (para4); // 4
Lele.info (arguments [3]); // undefined, which is an input parameter and will not be synchronized
}
After testing, the synchronization between arguments and form parameters is bidirectional, but in JavaScript advanced programming (version 3rd), page 66th is unidirectional: modifying form parameters does not change arguments. This may be another Bug in the original book, or it may be that FireFox has extended the specification. However, this also makes us know that, even in classic cases, there is still a possibility of bugs. The actual operation prevails.
• Combined with arguments and Its Attribute callee, You can decouple the function name when calling the function itself, so that even if the function is assigned to another variable, the function name (not forget, it is also a variable) in addition, the assigned value can ensure that the operation is correct. Typical examples include factorial functions and Fibonacci series.
The Code is as follows:
// Calculate the factorial
Function factorial (num ){
If (num <= 1)
{
Return 1;
} Else {
Return num * factorial (num-1 );
}
}
Var fn = factorial;
Factorial = null;
Try {
Fn (2); // an exception is thrown because the function recursively calls factorial and factorial has been assigned null.
} Catch (e ){
Lele.info (e); // TypeError
}
// Fibonacci sequence
Function fibonacci (num ){
If (1 = num | 2 = num ){
Return 1;
} Else {
Return arguments. callee (num-1) + arguments. callee (num-2 );
}
}
Var gn = maid;
Fibonacci = null;
Console.info (gn (9); // 34. using arguments. callee, the function object and function name are decoupled and can be executed normally.
Recursive Algorithms are very concise, but they are not very efficient to maintain the running stack. There are also many very smooth algorithms for Recursive optimization, which will not be further explored here.
It should be noted that arguments. callee has been disabled in the strict ES5 mode. In this case, you can use the named function expression to achieve the same effect:
The Code is as follows:
// Fibonacci sequence
Var maid = (function f (num ){
Return num <= 2? 1: (f (num-1) + f (num-2 ));
});
Var gn = maid;
Fibonacci = null;
Console.info (gn (9); // 34. The namefunction expression is used to decouple the function object from the function name and can be executed normally.