function expression
There are two ways to define a function: One is a function declaration and the other is a function expression.
A function declaration brings the effect of a function declaration promotion , and the latter part of the function expression is actually an anonymous function. An anonymous function is the equivalent of a value that can be used in cases where the function is used as a value.
1 recursion
Recursive call itself we will use Arguments.callee () instead of the function name to facilitate reuse, but in strict mode, this property cannot be accessed through scripting. Therefore, the same result can be achieved with a function expression.
var factorial = function f (num) { if1) { return1 }else { return1);} }
2. Closures
Closures are functions that have access to variables in another function scope.
function Creatcomparision (peopertyname) { return function (object1,object2) { var value1 = Object1[propertyname]; var value2 = Object2[propertyname]; return value1- value2;} ;}
This internal function is returned, and it can still be accessed to the variable propertyname when it is called elsewhere. This is because it contains the scope of the creatcomparision in its scope chain.
Generally speaking, when the function is finished, the local active object is destroyed, only the global scope exists in memory, but the case of the closure is different.
In the example above, when the returned anonymous function is executed externally, the first layer of its scope chain is the active object of the closure, then the active object of the creatcomparision, and finally the global activity object.
In other words, after the creatcomparision () function completes, the scope chain of the creatcomparision is destroyed, but its active object retains the scope chain that provides the constituent closures.
Therefore, after calling this anonymous function externally using a function expression, you should explicitly touch the reference to the anonymous function in order to free up memory.
Closures and variables
The action mechanism of the scope chain causes the problem that the closure retains its active object in the scope chain, and the variables in the closure reflect the actual values in the active object, causing any variable to have only the last value.
function Creatfunctions () { varnew Array (); for (var0; i++) { = function () { return i; } } return result; // [10,10,10,10,10,10,10,10,10,10]}
To solve this problem, let the variables in the closure not refer directly to the active object, but instead indirectly through another anonymous function package:
function Creatfunctions () { varnew Array (); for (var0; i++) {= function (num) { return function () { return i; } } (i); } return result; // [1,2,3,4,5,6,7,8,9,10]}
In this case, I first pass to the NUM parameter in the scope, because the function parameter is passed by value, so I have a save for Each loop's I variable.
About this object
Simply understood, the execution environment of an anonymous function is global without regard to call () and apply (). (See my other article for details. The This of the anonymous function points to why window?)
So when you use an anonymous function in a closure, this does not follow the execution environment of the closure, so some work needs to be done.
varName ='Window';var Object={name:'Eric', Getname:function () {varthat = This;//the current execution environment this is passed to a variable so that referencing the variable in the closure does not cause this to be different from the expected returnfunction () {returnThat.name;//' Eric ' }; }}
There is another point of thinking about this, the above code actually does not need to use closures, that does not use the closure of the anonymous function is not to cause this problem?
varName ='Window';var Object={name:'Eric', Getname:function () {return This. Name; }}Object. GetName ();//' Eric '(Object. GetName) ();//' Eric '(1,Object. GetName) ();//' Window '(Object. GetName =Object. GetName) ();//' Window '
In fact, in the function execution statement ' object.getname () ', the left side of the parentheses is a referencetype whose base property provides a reference to the execution environment this.
Any operation that causes Referencetype to GetValue in advance will cause the base property to be destroyed (for example, the grouping operator and the assignment of line fourth on the third line of the function execution), thus this = null, which in this case points to the global environment.
Memory Leaks
In browsers that use reference counting as a garbage collection policy, closures can also cause problems in which the count cannot be cleared, except for circular references. For example, an HTML element is saved in the scope chain of a closure, and the element is referenced in the closure, which means that the element cannot be destroyed.
To solve this problem, we need to resolve the way to refer to this element, instead of directly referencing it as an indirect reference:
function Assignhander () { var element = document.getElementById ('baba') ); var id = element; // before entering the closure, copy the required values so that no direct reference to the element is required in the closure. Element.onclick = function () { alert (ID); } NULL ;}
Note: In fact, we find that the problem caused by closures is, in other words, the problem of the scope chain, and the idea of solving the problem is to remove the coupling relationship by replacing the reference before entering the closure.
3. Mimic block-level scopes
(function () { //mimic block-level scope, this is called private scope for(vari =0; I <Ten; i++) {alert (i); }}) ();(function () { //Take advantage of private action, you can execute a function without taking up space, and will not cause duplicate name problems (when multiple groups are in development). varnow =NewDate (); if(Now.getmonth () = =0&& now.getdate () = =1) {alert ('Happy New year!'); }})();
Because there is no reference to an anonymous function, the function destroys its scope chain after it has finished executing.
4. Private variables
Because the variables inside the function or outside of the method are inaccessible, so based on this principle, we can implement the private variable using the function, the simplest is to use the constructor to implement:
function MyObject () {varName ="Eric";//This is not the same as THIS.name = "Eric", which is defining a variable rather than adding a property. varSayname =function () {alert ( This. name);//note the This in the anonymous function }; This. Publicmethod =function () {
Console.log (name); //' Eric ' console.log ( This. name);//UndefinedSayname ();//' Window ' }}varObject1 =NewMyobject;object1.publicmethod ();
instance, you can only access the name and sayname through the privileged Method Publicmethod (), and cannot directly access them, thus completing the implementation of the private variable.
However, the problem left by the constructor is still unresolved, that is, each instance must replicate all the properties, methods, and waste a lot of space.
Static private variables
To solve the problem that an instance of a simple constructor cannot use the same attribute method, we introduce a prototype model.
In order to resolve variables outside of the invisible, become private variables, we introduce a private scope.
(function() {//mimics block-level scopes, making external invisible name and Sayname varname = ' Eric '; varSayname =function() {alert (name); }; MyObject=function() {};//to make calls outside the constructor, you cannot use Var or the way the function is declared, because they all make the constructor valid only internally. MyObject.prototype.publicMethod=function() {//for the common method to have the same reference, use the prototype patternConsole.log (name); Sayname (); }})();varObject1 =NewMyObject (); Object1.publicmethod ();
Also, in the above function, the privileged method, as a closure, always holds a reference to the containing scope. Therefore, this private scope is not destroyed.
This pattern improves code reuse, but each instance does not have its own private variable.
Module mode
In the case of a singleton, it is useful to maintain its private variables using module mode, and some initialization is required.
Instead of creating the singleton in a literal way, it is enhanced by adding private variables and privileged methods to the singleton.
varApplication =function() { //defining private variables and methods varcomponents =NewArray (); //InitializeComponents.push (NewBasecomponent ());//basecomponent () returns an array containing the base class object //Privileged Methods return{getcomponentslength:function() { returncomponents.length; }, RegisterComponent:function(component) {if(typeof(component) = = ' Object ') {Components.push (component); } } };} ();
Enhanced Module mode
If the singleton must be an instance of some type, you must also add some properties and methods to enhance it.
For example above, application must be an example of basecomponent.
varApplication =function() { //defining private variables and methods varcomponents =NewArray (); //InitializeComponents.push (NewBasecomponent ());//basecomponent () returns an array containing the base class object //create an object, a local copy of application varApp =Newbasecomponent (); //Privileged MethodsApp.getcomponentslength =function() { returncomponents.length; }; App.registercomponent=function(component) {if(typeof(component) = = ' Object ') {Components.push (component); } }; //return this copy returnapp; }();
In this mode, application is an instance of Basecomponent and has its own private variables and methods that can be accessed through privileged functions.
JavaScript Learning (V): function expressions