This article mainly introduces information about function expression recursion and closure functions in javascript advanced programming. If you need them, you can refer to the following two methods to define function expressions: function declaration and function expression.
The function declaration is as follows:
Function functionName (arg0, arg1, arg2) {// function body}
The first is the function keyword, and then the function name.
FF, Safrai, Chrome, and Opera both define a non-standard name attribute for the function, through which the specified name can be accessed. the value of this function is always the identifier following the function keyword.
// Only effective alert (functionName. name) in FF, Safari, Chrome, and Opera // functionName
Function declaration features function declaration elevation (function declaration hoisting), which means that the function declaration will be read before the code is executed. This means that the function declaration can be placed behind the statement that calls it.
sayHi();function sayHi(){ alert("Hi!");}
This example will not throw an error because the function declaration will be read before the code is executed.
The second is a function expression.
Var functionName = function (arg0, arg0, arg2) {// function body}
This form looks like a regular variable assignment statement, that is, creating a function and assigning it to the variable functionName. in this case, the created function is called an anonymous function because the function keyword is not followed by an identifier. (anonymous functions are also called Lambda functions .) the name attribute of an anonymous function is a null string.
Function expressions, like other expressions, must be assigned a value before use.
The following code causes an error:
syaHi();//Uncaught ReferenceError: syaHi is not definedvar sayHi=function(){ alert("Hi!");}
Do not write code like the following. This is invalid syntax in ECMAScript. the JavaScript engine will try to correct the error, but different browsers will modify the error.
// Do not do this if (condition) {function sayHi () {alert ("Hi! ") ;}} Else {function sayHi () {alert (" Yo! ");}}
If you use a function expression, there is no problem.
// Var sayHi; if (condition) {sayHi = function () {alert ("Hi! ") ;}} Else {sayHi = function () {alert (" Yo! ");}}
If you can create a function and assign it to a variable, you can return the function as the value of another function.
function creatComparisonFunction(propertyName){ return function(object1,object2){ var value1=object1[propertyName]; var value2=object2[propertyName]; if(value1
value2){ return 1; }else{ return 0; } };}
CreatComparisonFunction () returns an anonymous function. the returned function may be assigned a variable or called in other ways. However, it is anonymous within the creatComparisonFunction () function. you can use anonymous functions when using functions as values.
7.1 Recursion
A recursive function is constructed when a function calls itself by name.
function factorial(num){ if(num<=1){ return 1; }else{ return num*factorial(num-1); }}
The above is a classic recursive factorial function. The code below may cause errors.
var anotherFactorial=factorial;factorial=null;alert(anotherFactorial(4));//Uncaught TypeError: factorial is not a function
The above code first saves the factorial () function in the variable anotherFactorial, and then sets the factorial variable to null. The result points to only one original reference. when you call anotherFactorial (), factorial () is no longer a function because factorial () must be executed.
In this case, arguments. callee can be used to solve the problem.
Arguments. callee is a pointer to the function being executed. Therefore, it can be used to implement recursive calls to the function.
function factorial(num){ if(num<=1){ return 1; }else{ return num*arguments.callee(num-1); }}
When writing a recursive function, it is safer to use arguments. callee than to use the function name, because it ensures that no problem occurs when you call the function.
However, in strict mode, arguments. callee.
However, function expressions can be used to achieve the same results.
var factorial=(function f(num){ if(num<=1){ return 1; }else{ return num*f(num-1); }});console.log(factorial(4));//24
7.2 Closure
A closure is a function that has the right to access the variables in another function scope. A common way to create a closure is to create another function within a function.
function creatComparisonFunction(propertyName){ return function(object1,object2){ var value1=object1[propertyName]; var value2=object2[propertyName]; if(value1
value2){ return 1; }else{ return 0; } };}
The bold two lines of code are the code in the internal function (an anonymous function). These two lines of code access the propertyName variable in the external function. even if this internal function is returned and called elsewhere, it can still access the variable propertyName. the reason why the variable can be accessed is that the scope chain of the internal function contains the scope of creatComparisonFunction.
When a function is called, an execution environment (execution context) and corresponding scope chain are created. then, use the values of arguments and other named parameters to initialize the activation object of the function ). however, in the scope chain, the activity object of the external function is always in the second place, and the activity object of the external function is in the third place ,.... the global execution environment that serves as the end of the scope chain.
During function execution, to read and write the value of a variable, you need to find the variable in the scope chain.
function compare(value1,value2){ if(value1
value2){ return 1; }else{ return 0; } } var result=compare(5,10) console.log(result)//-1
The above code first defines the compare () function, and then calls it in the global scope. when compare () is called, an activity object containing arguments, value1, and value2 is created. the variable objects (including result and compare) in the global execution environment are second in the scope chain of the compare () execution environment.
Each execution environment in the background has an object that represents a variable-a variable object. variable objects in the global environment always exist, while variable objects in local environments such as the compare () function only exist during function execution. when you create the compare () function, a Scope chain containing the global variable object is created. This Scope chain is saved in the internal [[Scope] attribute. when the compare () function is called, an execution environment is created for the function, and then the Scope chain of the execution environment is constructed by copying the objects in the [[Scope] attribute of the function. then, an activity object (used as a variable object here) is created and pushed to the front end of the execution environment scope chain.
The scope chain is essentially a pointer list pointing to a variable object. It only references but does not actually contain the variable object.
Whenever a variable is accessed in a function, the variable with the corresponding name is searched from the scope chain. generally, after the function is executed, the partial activity object is destroyed, and only the global scope is saved in the memory (the variable object in the global execution environment ). however, the closure is different.
The function defined in another function adds the activity object containing the function (that is, the external function) to its scope.
var compare=creatComparisonFunction("name");var result=comapre({name:"Nicholas"},{name:"Greg"});
Shows the scope of the above code execution, including the function and internal anonymous function.
When the createComparisonFunction () function returns, the scope of its execution environment will be destroyed, but its activity object will remain in the memory. After the anonymous function is destroyed, createComparisonFunction () will be destroyed.
// Create a function var compare = creatComparisonFunction ("name"); // call the function var result = comapre ({name: "Nicolas" },{ name: "Greg "}); // unreference anonymous functions (to release memory) compareNames = null;
By setting compareNames to null to release the reference of this function, it is equal to notifying the garbage collection routine to clear it. as the scope chain of an anonymous function is destroyed, other scopes (except the global scope) can be safely destroyed.
Since the closure will carry the scope of the function that contains it, it will occupy more memory than other functions. Excessive use of the closure may cause excessive memory usage. Use the closure with caution.
7.2.1 closures and variables
This configuration mechanism of the scope chain leads to a noteworthy side effect, that is, the closure can only obtain the last value of any variable in the function.
The closure stores the entire variable object instead of a special variable.
function createFunctions(){ var result=new Array(); for(var i=0;i<10;i++){ result[i]=function(){ return i; }; } return result;}
In the code above, this function returns an array of functions. on the surface, it seems that every function should return its own index value, but in fact, every function returns 10. because the scope chain of each function stores the activity objects of the createFunctions () function, they reference the same variable I. when the createFunction () function returns, the value of variable I is 10. At this time, each function references the same variable object that saves variable I, therefore, the I value in each function is 10.
However, we can create another anonymous function to force the closure to behave as expected.
function createFunctions(){ var result=new Array(); for(var i=0;i<10;i++){ result[i]=function(num){ return function(){ return num; } }(i); } return result;}
After rewriting, each function returns different index values. in this version, we did not directly assign the closure value to the array. Instead, we defined an anonymous function and assigned the result of immediately executing the anonymous function to the array. here, the anonymous function has a parameter num, that is, the value to be returned by the final function. when calling each anonymous function, we input the variable I. because function parameters are passed by value, the current value of variable I is copied to the parameter num. in this anonymous function, a closure accessing num is created and returned. in this case, each function in the result array has a copy of its own num variable, so different values can be returned.
7.2.2 about this object
This object is bound to the execution environment of the basic function at runtime: in a global function, this equals to window. When a function is called as a method of an object, this equals to that object. however, the execution environment of anonymous functions is global, so this object usually points to window.
Var name = "the window"; var object = {name: "my object", getNameFunc: function () {return this. name ;}}}; alert (object. getNameFunc (); // the window (in non-strict Mode)
When a function is called, two special variables are automatically obtained: this and arguments. when an internal function searches for these two variables, it only searches for their active objects. Therefore, it is never possible to directly access these two variables in an external function.
However, you can store this object in an external scope in a variable that can be accessed by a closure to allow the closure to access this object.
var name="the window";var object={ name:"my object", getNameFunc:function(){ var that=this; return function(){ return that.name; }; }};alert(object.getNameFunc()());//my object
Before defining an anonymous function, we assigned this object to a variable named that. after the closure is defined, the closure can also access this variable, because it is a variable that we specifically declare in the include function. even after the function returns, that still references the object, so the object is called. getNameFunc () returns my object.
Note: this and arguments have the same problem. To access the arguments object in the scope, you must save the reference to this object to the variable that can be accessed by another closure.
var name="the window";var object={ name:"my object", getName:function(){ return this.name; }};console.log(object.getName());//my objectconsole.log((object.getName)());//my objectconsole.log((object.getName=object.getName)());//the window
The last line of code first executes a value assignment statement, and then calls the value assignment result. because the value of the value assignment expression is the function itself, the value of this cannot be maintained, and the result returns "this window ".
7.2.3 Memory leakage
Since earlier versions of IE9 use different garbage collection routines for JScript objects and COM objects, closures may cause some special problems in these versions of IE. specifically, if an HTML element is stored in the scope chain of the closure, the element cannot be destroyed.
function assignHandlet(){ var element=document.getElementById("someElement"); element.onclick=function(){ alert(element.id); };}
The code above creates a closure that acts as the element event handler, and this closure creates a circular reference. because the anonymous function saves a reference to the active object of assignHandler (), it cannot reduce the number of element references. as long as an anonymous function exists, the reference number of element is at least 1, so the memory occupied by it will never be recycled. however, this problem can be solved by slightly modifying the code.
function assignHandlet(){ var element=document.getElementById("someElement"); var id=element.id; element.onclick=function(){ alert(id); }; element=null;}
In the code above, a copy of element. id is saved in a variable, and the variable is referenced in the closure to eliminate circular references.
A friendly reminder: the closure will reference the entire activity object containing the function, which contains the element. even if the closure does not directly reference the element, the active object containing the function will still save a reference. therefore, it is necessary to set the element variable to null. in this way, the reference to the DOM object can be removed, the number of references can be reduced smoothly, and the memory occupied by the DOM object can be recycled normally.
The following describes the function expressions.
In JavaScript programming, function expressions are very useful. You do not need to name a function to implement dynamic programming. Anonymous functions, also known as Lambda functions, are a powerful way to use JavaScript Functions. The following summarizes the features of function expressions.
Function expressions are different from function declarations. Function Declaration requires a name, but the function expression does not. A function expression without a name is also called an anonymous function.
When you cannot determine how to reference a function, recursive functions become more complex. recursive functions should always use arguments. callee is used to call itself recursively. Do not use the function name-the function name may change.
When other functions are defined in the function, the closure is created. The closure has the right to access all variables in the function.
As follows.
In the background execution environment, the scope chain of a closure contains its own scope, the scope of the function, and the global scope. Generally, the function scope and all its variables are destroyed after the function is executed.
However, when a function returns a closure, the function's scope will remain in the memory until the closure does not exist.
Using closures can mimic block-level scopes in JavaScript (JavaScript itself does not have block-level scopes). The main points are as follows.
Create and call a function immediately, so that you can execute the code and leave no reference to the function in the memory.
The result is that all variables in the function are immediately destroyed unless some variables are assigned to variables in the include scope (that is, the external scope.
Closures can also be used to create private variables in objects. The related concepts and key points are as follows. Even if JavaScript does not have the formal concept of private object attributes, it can implement public methods by using closures, while public methods can access variables defined in the scope of inclusion.
The public method that has the permission to access private variables is called the privileged method.
You can use the constructor mode and prototype mode to implement custom privileged methods. You can also use the module mode and enhanced module mode to implement the single-instance privileged methods.
Function expressions and closures in JavaScript are extremely useful and can be used to implement many functions. However, because the creation of closures must maintain additional scopes, excessive use of them may occupy a large amount of memory.