JavaScript advanced programming (version 3rd) study notes 9 js functions (Part 2)

Source: Internet
Author: User

Then let's look at the function-an object with magical colors.

9. functions as values

In a general programming language, if you want to use a function as a value, you must use a method similar to a function pointer or proxy. However, in ECMAScript, a function is an object, has all the features of a general object. In addition to functions, they can have their own attributes and methods. They can also be used as a reference type value, in fact, in the previous example, we have already used a function as the value of an object property. For example, a function can also be used as a parameter or return value of another function, the callback function in asynchronous processing is a typical usage.

Copy codeThe Code is as follows: var name = 'linjisong ';
Var person = {name: 'external '};
Function getName (){
Return this. name;
}
Function sum (){
Var total = 0,
L = arguments. length;
For (; l --)
{
Total + = arguments L-1 1];
}
Return total;
}

// Define the function that calls the function, using the function as the form parameter
Function callFn (fn, arguments, scope ){
Arguments = arguments | [];
Scope = scope | window;
Return fn. apply (scope, arguments );
}
// Call callFn and use the function as the actual Parameter
Console.info (callFn (getName); // linjisong
Console.info (callFn (getName, '', person); // oulinhai
Console.info (callFn (sum, [1, 2, 3, 4]); // 10

Let's look at a typical example of using a function as the return value. This example is from Chapter 5th of the original book:Copy codeThe Code is as follows: function createComparisonFunction (propertyName ){
Return function (object1, object2 ){
Var value1 = object1 [propertyName];
Var value2 = object2 [propertyName];

If (value1 <value2 ){
Return-1;
} Else if (value1> value2 ){
Return 1;
} Else {
Return 0;
}
};
}

Var data = [{name: "Zachary", age: 28 },{ name: "Nicolas", age: 29}];

Data. sort (createComparisonFunction ("name "));
Console.info (data [0]. name); // Nicolas

Data. sort (createComparisonFunction ("age "));
Console.info (data [0]. name); // Zachary

10. Closure)

A closure is a function that has the right to access variables in another function scope. Objects are data with functions, while closures are functions with data.

First, closure is a function, and then closure is a function with data. So what data does it contain? Let's look up the example of a function as the return value. An anonymous function is returned. As this anonymous function is returned, the code of the createComparisonFunction () function on the outer layer is executed. According to the preceding conclusion, the execution environment of the outer function will pop up and destroy the stack. However, in the subsequent sorting, we can see that the returned anonymous function can still access the propertyName in the scope of createComparisonFunction, this indicates that although the execution environment corresponding to createComparisonFunction () has been destroyed, the activity objects corresponding to the execution environment have not been destroyed, instead, it serves as an object in the scope chain of the returned anonymous function. In other words, the data contained in the closure of the returned anonymous function is the corresponding activity object of the outer function. Because the attributes of the activity object (that is, the variables, functions, and form parameters defined in the outer function) change with the code execution of the outer function, therefore, the closure composed of anonymous functions that are finally returned contains data that is the activity object after the code of the outer function is executed, that is, the final state.

I hope to understand the above paragraph and try again and again. Although I have tried my best to describe more easily, the concept of closure is still somewhat abstract. Here is an example. This example is from Chapter 7th of the original book:Copy codeThe Code is as follows: function createFunctions (){
Var result = new Array ();
For (var I = 0; I <10; I ++ ){
Result [I] = function (){
Return I;
};
}
Return result;
}

Var funcs = createFunctions ();
For (var I = 0, l = funcs. length; I <l; I ++ ){
Console.info (funcs [I] (); // each function outputs 10
}

Here, because the data contained in the closure is the final state of the createFunctions corresponding activity object, after the createFunctions () code is executed, the property I of the activity object has changed to 10, therefore, every function returned in the following call outputs 10. To solve this problem, you can use the anonymous function scope to save the status:Copy codeThe Code is as follows: function createFunctions (){
Var result = new Array ();
For (var I = 0; I <10; I ++ ){
Result [I] = (function (num ){
Return function (){
Return num;
};
}) (I );
}
Return result;
}

Each status is saved using an anonymous function that is called immediately (stored in the active object corresponding to the anonymous function), and when the final returned function is called, you can use the data contained in the closure (the data in the corresponding anonymous function activity object) to access the data correctly. The output result is 0, 1 ,... 9. Of course, in this way, 10 closures are created, which has a great impact on the performance. Therefore, we recommend that you do not abuse closures. In addition, since the closure will save the activity objects of other execution environments as a part of its own scope chain, this may also cause memory leakage. Although the closure has potential efficiency and memory risks, the closure function is too powerful. Let's take a look at the closure application-First let's go back to the function binding method bind () mentioned yesterday ().

(1) function binding and currying)

A. Let's look at this again. Let's look at an example (chapter 1 of the original book ):Copy codeThe Code is as follows: <button id = 'my-btn 'title = 'click'> Hello </Button>
<Script type = "text/javascript">
Var handler = {
Title: 'event ',
HandleClick: function (event ){
Console.info (this. title );
}
};
Var btn = document. getElementById ('My-btn '); // get the page button
Btn. onclick = handler. handleClick; // Add an event handler to the page button
</Script>

If you click "Hello", what is printed on the console? It turns out to be a Button, rather than the expected Event, because this points to the Button object when you click the Button. You can use closures to solve this problem:Copy codeThe Code is as follows: btn. onclick = function (event ){
Handler. handleClick (event); // form a closure. The handler object is called to call the function. The internal attribute of this function points to the handler object, so the Event is output}

B. The above solution is not elegant. In ES5, the function binding method bind () is added. We use this method to rewrite it:Copy codeThe Code is as follows: if (! Function. prototype. bind) {// bind is added to es5. to ensure normal operation, add this method to an unsupported browser.
Function. prototype. bind = function (scope ){
Var that = this; // The function object that calls the bind () method
Return function (){
That. apply (scope, arguments); // use the apply method to specify the internal attribute of that function object this
};
};
}
Btn. onclick = handler. handleClick. bind (handler); // you only need to use one statement to use the bind () method.

In the bind () method added here, the main technique is to create a closure and save the binding parameters as the internal attribute of the function during actual calling. this. If you are not sure whether the browser supports bind () or the bind () Here, you can remove the condition of Feature Detection and try another method name.
C. When the preceding functions use the bind () method, only the first parameter is used. If bind () is called () when multiple parameters are passed in and 2nd parameters are used as the parameters for the actual function call, We can bind the default parameters to the function.Copy codeThe Code is as follows: if (! Function. prototype. bind ){
Function. prototype. bind = function (scope ){
Var that = this; // The function object that calls the bind () method
Var args = Array. prototype. slice. call (arguments, 1); // a parameter Array consisting of 2nd Parameters
Return function (){
Var innerArgs = Array. prototype. slice. apply (arguments );
That. apply (scope, args. concat (innerArgs); // use the apply method to specify the internal attribute this of the function object and fill in the parameters passed in when binding.
};
};
}

D. colialization: During the above binding, the first parameter is used to set the internal attribute this during function calling. If all the parameters used for binding are used as pre-filled parameters, it is called the function kernelization.Copy codeThe Code is as follows: if (! Function. prototype. curry ){
Function. prototype. curry = function (){
Var that = this; // The function object that calls the curry () method.
Var args = Array. prototype. slice. call (arguments); // pre-filled parameter Array
Return function (){
Var innerArgs = Array. prototype. slice. apply (arguments); // Array of parameters for actual calls
That. apply (this, args. concat (innerArgs); // use the apply method and add the pre-filled Parameter
};
};
}

(2) Use closure Cache

Do you still remember the previous function that uses recursion to implement the Fibonacci series? Use the closure cache to rewrite it:Copy codeThe Code is as follows: var fibonacci = (function () {// use the closure cache, recursively
Var cache = [];
Function f (n ){
If (1 = n | 2 = n ){
Return 1;
} Else {
Cache [n] = cache [n] | (f (n-1) + f (n-2 ));
Return cache [n];
}
}
Return f;
})();

Var f2 = function (n) {// do not use closure cache, direct Recursion
If (1 = n | 2 = n ){
Return 1;
} Else {
Return f2 (n-1) + f2 (n-2 );
}
};

The following is the test code and the running result on my machine:Copy codeThe Code is as follows: var test = function (n ){
Var start = new Date (). getTime ();
Console.info (maid (n ));
Lele.info (new Date (). getTime ()-start );

Start = new Date (). getTime ();
Console.info (f2 (n ));
Lele.info (new Date (). getTime ()-start );
};
Test (10); // 55,2, 55,2
Test (20); // 6765,1, 6765,7
Test (30); // 832040,643

As you can see, the larger the value of n, the more obvious the advantage of using cache computing. As an exercise, you can try to modify the factorial function by yourself.

(3) Imitating block-level scope

In ECMAScript, there are statement blocks, but there is no corresponding block-level scope. However, we can use closures to simulate block-level scopes. The general format is:Copy codeThe Code is as follows: (function (){
// Here is the block statement
})();

The above pattern is also called the function expression for immediate call. This pattern is very popular, especially because jQuery source code uses this pattern and is widely used.
Closures also have many interesting applications, such as imitating private variables, private functions, and module patterns. We will not discuss them here. We will look at these content after understanding the object in depth.

Let's talk about functions first. There are also a lot of great articles on the Internet. If you are interested, you can search and read them by yourself. Here we recommend an article, translated by the translator of JavaScript advanced programming (version 3rd): Exploring the name function expressions.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.