闭包
词法作用域:函数的执行依赖于作用域,这个作用域是在函数定义时决定的,而不是在函数调用时决定的。
定义:当调用函数时的作用域和定义函数时的作用域不是同个作用域,就叫闭包。
var scoped = 'global scoped';
function getScoped () {
var scoped = 'local scoped';
function func () {
return scoped;
}
return func();
}
getScoped(); //'local scoped'
var scoped = 'global scoped';
function getScoped () {
var scoped = 'local scoped';
function func () {
return scoped;
}
return func;
}
getScoped()(); //'local scoped'
这就验证了词法作用域的原则:作用域链是在定义函数时决定的,所以作用域链还是指向局部变量。
何为作用域链?
作用域链可以理解为一个对象列表。每次调用函数的时候,会创建一个保存局部变量的新对象,并把这个对象添加至作用域链中。
当函数返回时,从作用域链中把这个绑定变量的对象删除。如果不存在嵌套的函数,也没有其他引用指向这个绑定对象,它就会被当成垃圾回收。如果存在嵌套的函数,每个嵌套的函数都有对应的作用域链,并且这个作用域链指向一个绑定变量的对象。但如果这些变量在外部函数被保存下来,那么它们也会和它们绑定的变量对象被回收。
如果这个函数定义了嵌套函数,并将它作为返回值返回或者存储在某个属性中,这是就有一个外部引用指向这个嵌套的函数,它就不会被当成垃圾回收,并且它指向的绑定变量对象也不会被回收。
闭包经典问题:
function constFunc (v) { return function () {return v;} };
var funcs = [];
for (var i = 0;i < 10;i++) {
funcs[i] = constFunc(i);
}
funcs[5](); //5
var funcs = [];
for (var i = 0;i < 10;i++) {
funcs[i] = function () {return i;};
}
funcs[5](); //10
函数属性、方法和构造函数
length属性
arguments代表函数的实参列表
arguments.callee代表函数本身,在使用匿名函数递归的时候,可以使用该属性调用本身
arguments代表函数的实参个数
arguments.callee.length代表函数形参个数
prototype属性
每个函数都包含一个prototype属性,这个属性是对这个对象的引用,成为原型对象。当用构造函数创建对象的时候,新创建的对象的原型会指向函数的原型对象。
call()和apply()方法
call和apply方法的第一个实参是要调用函数的母对象,它是调用上下文,在函数体内通过this来获得它的引用。
通过对象o调用函数f()
f.call(o,1,2);
f.apply(o,[1,2]);
类似于
o.m = f;
o.m();
delete o.m;
bind()方法
当函数f()上调用bind()方法并传入一个对象o作为参数,这个方法将返回一个新的函数。
toString()方法
大多数函数的toString方法返回的是函数完整的源码
内置函数的toString方法返回的是"[native code]"的字符串
函数的构造函数为Function函数
允许JavaScript动态地创建并编译函数
var f = new Function('x', 'y', 'return x + y;');
var f = function(x, y) {return x + y;}
检测函数对象
function isFunction (x) {
return Object.prototype.toString,call(x) === '[object Function]';
}