1.arguments[]对象在函数代码中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们。还可以用 arguments 对象检测函数的参数个数,引用属性 arguments.length
2function对象的length属性ECMAScript 定义的属性 length 声明了函数期望的参数个数
3Function 对象也有与所有对象共享的 valueOf() 方法和 toString() 方法。这两个方法返回的都是函数的源代码,在调试时尤其有用
4闭包:
什么时候需要用到闭包:
1.需要在一个函数外部,访问函数内部的变量的时候(也就是说在函数运行完之后,你想要把变量保存下来,待需要的时候调用。而不是通过垃圾回收机制消除(garbage collection))。
2.保护变量安全。一个函数的内部变量,只能内部函数引用。
如何定义闭包:在一个函数内部,定义一个函数,并返回一个函数的引用。
3. 先看下闭包的两种形式:
//第一种形式:
function outer(){
var i = 7;
function inner(){
alert(i);
}
inner(); //可以用setInteval(inner,5000);实现每5秒执行一次inner函数
}
//第二种形式:
function outer(){
var i = 7;
function inner(){
alert(i);
}
return inner(); //函数是一种特殊的对象, 这里直接返回函数的引用
}
var f = outer(); //使用f接受返回的内层函数的引用
f(); //调用内层函数
在第一种情况时: outer函数定义局部变量i, 函数inner(), 之后又调用了inner函数. 注意看inner()函数,
inner函数中 并没有定义变量i, 这个i是来自于outer函数的局部变量. 当在inner函数被引用的时候,
由于内层的inner函数需要使用变量i, 因此这个运行时定义的变量i不能被释放, 从而在inner()函数执行时就可以取得这个变量的值.
当第二种情况时: 执行outer()函数之后, 将返回inner()函数的引用, 由于外部变量f引用了内部函数inner(),
由于inner()函数同样需要使用变量i, 这个局部变量i也将被外部变量f所引用, 因此变量i依然不能被释放. 与第一种形式的区别是:
我们可以再outer()函数执行之后访问到变量i的值. 如果我们将alert(i); 改成 alert(++i); 那么在函数的外部, 我们执行f(); 此时变量i并没有释放, 结果应该是8,
如果再调用一次f(); 则结果变成9。但是: 如果我们再次调用outer();函数后将会创建一个新的局部变量, 之后再调用f();
结果则变成了8. 也就是说只要外层函数没有再次创建新变量, 原来的变量i将一直有效.
4闭包可以用在许多地方。它的最大用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。
怎么来理解这句话呢?请看下面的代码。
Js代码
function f1(){
var n=999;
nAdd=function(){n+=1}
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
nAdd();
result(); // 1000
在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。
为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。
这段代码中另一个值得注意的地方,就是“nAdd=function(){n+=1}”这一行,首先在nAdd前面没有使用var关键字,因此 nAdd是一个全局变量,而不是局部变量。其次,nAdd的值是一个匿名函数(anonymous function),而这个
匿名函数本身也是一个闭包,所以nAdd相当于是一个setter,可以在函数外部对函数内部的局部变量进行操作。
4闭包的注意点:
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。
2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。
5闭包的应用场景
保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
- 在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
- 通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)
私有属性和方法在Constructor外是无法被访问的
function Constructor(...) {
var that = this;
var membername = value;
function membername(...) {...}
}
以上3点是闭包最基本的应用场景,很多经典案例都源于此。
6Javascript的垃圾回收机制
在Javascript中,如果一个对象不再被引用,那么这个对象就会被GC回收。如果两个对象互相引用,而不再被第3者所引用,那么这两个互相引用的对象也会被回收。因为函数a被b引用,b又被a外的c引用,这就是为什么函数a执行后不会被回收的原因。