JS匿名函数

函数声明与函数表达式的区别:(2点)

前者会在代码执行以前被加载到作用域中,而后者则是代码被执行到那一行时才会有定义。

函数声明会给函数指定一个名字,而函数表达式则是创建一个匿名函数,然后将这个匿名函数赋给一个变量。

递归

arguments.callee是一个指向正在执行的函数的指针。

1 //经典的递归阶乘函数
2 function factorial(num) {
3     if (num<=1) {
4         return 1;
5     }else {
6         return num * arguments.callee(num-1);
7     }
8 }
9 debug(factorial(4));

闭包

闭包的概念很简单:一个闭包是一个函数及定义它的环境的组合。

例如,在一个函数A内部定义其他函数B时,就创建了闭包。闭包有权访问包含函数(A)内部的所有变量。

 1 //返回一个函数
 2 function createComparison(propertyName) {
 3     return function(obj1, obj2) {
 4         var value1 = obj1[propertyName],
 5             value2 = obj2[propertyName];
 6         //return value1 - value2;
 7         if (value1 > value2) {
 8             return 1;
 9         }else if(value1 < value2) {
10             return -1;
11         }else {
12             return 0;
13         }
14     }
15 }
16 var compareName = createComparison('name');
17 debug(compareName({name:'mack'},{name:'an'}));        //1
18 compareName = null;        //解除对匿名函数的引用,释放内存

由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存

  1. 闭包与变量

a. 当某个函数第一次被调用时,会创建一个执行环境及相应的作用域链,并把作用域链赋给一个特殊的内部属性([[scope]])。

b. 然后使用this、arguments和其他命名参数的值来初始化函数的活动对象。在作用域链中外部函数的活动对象处于第二位……

c. 在函数执行过程中,为读取和写入变量的值,需要在作用域链中查找变量。

 1 闭包只能取得包含函数中任何变量的最后一个值:
 2 function createFunctions() {
 3     var result = new Array();
 4     for (var i=0; i<10; i++) {
 5         result[i] = function() {
 6             return i;
 7         }
 8     }
 9     return result;
10 }
11 //funcs 存储的是10个匿名函数
12 var funcs = createFunctions();
13 //debug(funcs);
14 //输出数组中的元素值(全部都是10)
15 for (var i=0; i < funcs.length; i++) {
16     debug(funcs[i]());
17 };
18 更改写法:
19 function createFunctions() {
20     var result = new Array();
21     for (var i=0; i<10; i++) {
22         //把i的当前值赋值给局部变量
23         result[i] = function(num) {
24             return function() {
25                 return num;
26             }
27         }(i);
28     }
29     return result;
30 }
31 //funcs 存储的是10个匿名函数
32 var funcs = createFunctions();
33 //输出数组中的元素值(0.1..9)
34 for (var i=0; i < funcs.length; i++) {
35     debug(funcs[i]());
36 }

      2.关于this对象

关于this对象(arguments存在同样的问题)

this对象是在运行时基于函数的执行环境绑定的,但匿名函数的执行环境具有全局性,因此this对象指向window.

 1 var name = 'The Window';
 2 var obj = {
 3     name: 'mackxu',
 4     getName: function() {
 5         return function() {
 6             return this.name;
 7         }
 8     }
 9 };
10 debug(obj.getName()());        //The Window
11 //把外部作用域的this对象保存在一个闭包能够访问到的变量中
12 var name = 'The Window';
13 var obj = {
14     name: 'mackxu',
15     getName: function() {
16         var that = this;
17         return function() {
18             return that.name;
19         }
20     }
21 };
22 debug(obj.getName()());        //mackxu

    3.IE中的内存泄露

如果闭包作用域链中保存着一个HTML元素,那么就意味着该元素将无法被销毁

 1 function assignHandler() {
 2         //无法减少对element 的引用数
 3 var element = document.getElementById(‘#id’);
 4         element.onclick = function() {
 5     debug(element.id);
 6 };
 7 }
 8 解决办法:
 9 function assignHandler() {
10 var element = document.getElementById(‘#id’);
11 var id = element.id;
12         element.onclick = function() {
13     debug(id);
14 };
15 element = null;
16 }

模仿块级作用域

Js没有块级作用域的概念

 1 Js没有块级作用域的概念
 2 function output() {
 3     //在for中定义的变量i,可以在for外面访问
 4     for (var i=0; i<10; i++) {
 5         //...
 6     }
 7     debug(i);        //output:10
 8 }
 9 output();
10 私有作用域:用作块级作用域的匿名函数,函数被执行后,里面的变量会马上销毁
11 (function(){
12     //这里是块级作用域
13 })();
14 改写上一个例子:
15 function output() {
16     //匿名函数被执行后,i变量将被销毁
17     (function(){
18         for (var i=0; i<10; i++) {
19             //...
20         }
21     })();
22     debug(i);        //error
23 }

这种技术经常在全局作用域中被用在函数外面,限制向全局作用中添加过多的变量和函数。

私有变量

任何在函数中定义的变量,可认为是私有变量,因为不能在函数外部访问这些变量。

私有变量包括函数的参数、局部变量、在函数内定义的其他函数。

特权方法:有权访问私有变量和私有函数的公有方法。

 1 function MyObject() {
 2     var private_var = 10;        //函数的私有变量
 3     //函数的私有方法
 4     function private_method() {
 5         return private_var;        //闭包能访问所在函数的所有属性
 6         //return 'private_method;
 7     }
 8     //特权方法[能访问私有变量、方法的公有方法]
 9     this.public_method = function() {
10         private_var ++;
11         return private_method();
12     }
13 }
14 
15 var obj = new MyObject();
16 debug(obj.public_method());
  1. 静态私有变量[避免每个实例都要创建同一组新方法]

在私有作用域中定义私有变量或函数,同样也可以创建特权方法

 1 (function() {
 2     //私有变量和函数
 3     //根据作用域链,private_var相对于特权方法(闭包)是外部函数的变量
 4     //其会变成一个静态的、由所有实例共享的属性[可以想象原型链继承父类的属性]
 5     var private_var = 10;
 6     function private_func() {
 7         return 'private function';
 8     }
 9     //没有被var声明,会自动添加到全局对象中
10     MyObject = function() {};
11     MyObject.prototype.public_method = function() {
12         private_var ++;
13         private_func();
14         return 'OK';
15     };
16 })();
17 //可以在私有作用域外,访问MyObject
18 var obj = new MyObject();
19 debug(obj.public_method());
20 送上一个实例说明:
21 (function() {
22     var name = '';        //静态私有变量
23     
24     Person = function(value) {
25         name = value;
26     };
27     Person.prototype.getName = function() {
28         return name;
29     };
30     Person.prototype.setName = function(value) {
31         name = value;
32     };
33 })();
34 
35 var p1 = new Person('mackxu');
36 debug(p1.getName());        //mackxu
37 var p2 = new Person('zhangsan');
38 debug(p2.getName());        //zhangsan
39 p2.setName('anan');
40 debug(p1.getName());        //anan

模块模式 

JavaScript是以对象字面量的方式来创建单例对象的。

 1 //函数返回的是对象
 2 var singleton = function() {
 3     //私有变量和方法
 4     var private_var = 10;
 5     function private_func() {
 6         return 'private function';
 7     }
 8     
 9     //返回公有方法和属性
10     return {
11         public_var: 22,
12         public_method: function() {
13             //访问私有变量和函数
14             private_var ++;
15             return private_func();
16         }
17     };
18 }();
19 debug(singleton.public_method());

这个模式在需要对单例进行某些初始化,同时又需要维护其私有变量时很有用。

增强的模块模式

单例必须是某种类型的实例

 1 function CustomType() {
 2     //...
 3 }
 4 //函数返回的是对象
 5 var singleton = function() {
 6     //私有变量和方法
 7     var private_var = 10;
 8     function private_func() {
 9         return 'private function';
10     }
11     
12     //创建特定类型的对象,并返回
13     var obj = new CustomType();
14     //添加公有方法和属性
15     obj.public_var = true;
16     obj.public_method = function() {
17         private_var++;
18         return private_func();
19     }
20     return obj;
21 }();
22 
23 debug(singleton.public_method());
24 debug(singleton instanceof CustomType);        //true
原文地址:https://www.cnblogs.com/mackxu/p/closure.html