function factorial(num){ if(num<=1){ return 1; }else { return num * arguments.callee(num-1); } } console.log(factorial(4));
可是若是代码是在严格模式下开发:闭包
"use strict"; function factorial(num){ if(num<=1){ return 1; }else { return num * arguments.callee(num-1); } } console.log(factorial(4));
结果:Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
函数
在严格模式下不能经过脚本访问arguments.callee
,访问这个属性会报错,那么能够使用命名函数表达式来达到相同的结果:this
"use strict"; var factorial = (function f(num){ if(num<=1){ return 1; }else { return num * f(num-1); } }) console.log(factorial(4)); //24
以上代码建立了一个名为f()的命名函数表达式,而后将它赋值给变量factorial
,便是把函数赋值给另一个变量,函数的名字仍然有效。spa
闭包是指有权访问另外一个函数做用域中的变量的函数。prototype
做用域链的这种配置机制引出了一个值得注意的反作用,即闭包只能取得包含函数中任何变量的最后一个值。别忘了闭包所保存的是整个变量对象,而不是某个特殊的变量。code
function createFunctions(){ var result = new Array(); for (var i=0; i<10; i++){ result[i] = function(){ return i; } } return result; }
咱们能够经过建立另外一个匿名函数强制让闭包的行为符合预期。对象
function createFunctions(){ var result = new Array(); for (var i=0; i<10; i++){ result[i] = function(num){ return function(){ return num; }; }(i); } return result; }
在全局函数中,this等于window,而当函数被做为某个对象的方法调用时,this等于那个对象。不过,匿名函数的执行环境具备全局性,所以其this对象一般指向window。blog
var name = "The window"; var object = { name: "My Object", getNameFunc: function(){ return function(){ return this.name; }; } }; console.log(object.getNameFunc()()); // The window
不过,把外部做用域中的this对象保存在一个闭包可以访问到的变量里,就可让闭包访问该对象了。递归
var name = "The window"; var object = { name: "My Object", getNameFunc: function(){ var that = this; return function(){ return that.name; }; } }; console.log(object.getNameFunc()()); // My Object
看下面代码:内存
var name = "The window"; var object = { name: "My Object", getName: function(){ console.log(this.name); } } object.getName(); // My Object (object.getName)(); // My Object (object.getName = object.getName)(); // The window
来分析下调用的结果:
第一行代码跟日常同样调用了object.getName()
返回了My Object
,由于this.name就是object.name。
第二行代码在调用这个方法以前给它加了一个括号。虽然加了一个括号后,就好像只是在引用一个函数,可是this的值获得了维持,由于object.getName
和(object.getName)
的定义是相同的。
第三行代码先执行了一条赋值语句,而后再调用赋值后的结果。由于这个赋值表达式的值是函数自己,因此this的值不能获得维持,结果就返回了The window
。
固然你不大可能像第二行和第三行代码同样调用这个方法。这个例子只是说明了一个细微的语法变化,都有可能意外的改变this
的值。
function assignHandler(){ var element=document.getElementById('someElement'); element.onclick=function(){ alert(element.id); } }
上述代码它所占用的内存不会永远消失。修改一下代码以下解决:
function assignHandler(){ var element = document.getElementById('someElement'); var id = element.id; element.onclick = function(){ alert(id); } element = null; }
用块级做用域(一般称为私用做用域)的匿名函数的语法以下所示:
(function(){ })();
function add(num1,num2){ var sum=num1+num2; return sum; }
在这个函数内部,有三个私有变量:sum,num1,num2。在函数内部能够访问这几个变量。可是在函数外部则不能访问它们。若是在这个函数内部建立一个闭包,那么闭包能够经过本身的做用域链也能够访问这些变量。而利用这一点,就能够建立用于访问私有变量的公有方法。
咱们把有权访问私有变量和私有函数的公有方法称为特权方法。有两种在对象上建立特权方法的方式。第一种是在构造函数中定义特权方法。基本模式以下:
function myObejct(){ //私有变量和私有函数 var privateVariable=10; function privateFunction(){ return false; } //特权方法 this.publicMethod=function(){ privateVariable++; return privateFunction(); } }
利用私有和特权成员,能够隐藏那些不该该被直接修改的数据,例如:
function Person(name){ this.getName=function(){ return name; } this.setName=function(value){ name=value; } } var person=new Person("Nicholas"); alert(person.getName());//Nicholas person.setName("Greg"); alert(person.getName());//Greg
经过在私有做用域中定义私有变量或函数,一样也能够建立特权方法。其基本模式以下:
(function(){ //私有变量和私有函数 var privateVariable=10; function privateFunction(){ return false; } //构造函数 MyObject=function(){ }; //公有/特权方法 MyObject.prototype.publicMethod=function(){ privateVariable++; return privateFunction(); } })();
再看一个例子:
(function(){ var name = ""; Person = function(value){ name = value; }; Person.prototype.getName = function(){ return name; }; Person.prototype.setName = function(value){ name = value; }; })(); var person1 = new Person("Nicholas"); console.log(person1.getName()); //Nicholas person1.setName('Grey'); console.log(person1.getName()); //Grey var person2 = new Person("Michael"); console.log(person1.getName()); //Michael console.log(person2.getName()); //Michael
在一个实例上调用setName()会影响全部的实例。
模块模式是为单例建立私有变量和特权方法。所谓单例,指的就是只有一个实例的对象。按照惯例,js是以对象字面量的方式来建立单例对象的。
var singleton={ name:value, method:function(){ //这里是方法的代码 } };
模块模式经过为单例添加私有变量和特权方法可以使其获得加强。其语法形式以下:
var singleton=function(){ //私有变量和私有函数 var privateVariable=10; function privateFunction(){ return false; } //特权/公有属性和方法 return { publicProperty:true, publicMethod:function(){ privateVariable++; return privateFunction(); } } }();
var singleton=function(){ //私有变量和私有函数 var privateVariable=10; function privateFunction(){ return false; } //建立对象 var object=new CustomType(); //添加特权/公有属性和方法 object.publicProperty=true; object.publicMethod=function(){ privateVariable++; return privateFunction(); } //返回这个对象 return object; }();