javascript 知识点整理 05 闭包

这部分内容的整理都来自于《js高级程序设计》

函数表达式

闭包

模仿块级作用域

私有变量

函数表达式

理解函数表达式

1
2
3
4
5
6
7
8
9
//函数表达式
var func = function () {
statement
}
//函数声明
function func () {
statement
}


函数声明提升

函数调用时,执行环境初始化会将变量声明、函数声明和创建形参提升到函数执行的最前端,然后才是执行代码。


递归

传统递归

传统方式需要依赖函数名

1
2
3
4
5
6
7
function sum(num) {
if(num <= 1) {
return 1;
}else{
return num * sum(num - 1);
}
}


arguments.callee

callee是一个指向正在执行的函数的指针,因此使用这个属性可以不用明确函数名,适合在匿名函数中使用

1
2
3
4
5
6
7
function sum(num) {
if(num <= 1) {
return 1;
}else{
return num * arguments.callee(num - 1);
}
}

函数还有一个实例属性caller,指向当前函数的调用者,可以与arguments.callee连用


闭包

理解闭包

  • 简单来说,闭包即一个可以访问其他函数内部变量的函数

  • 闭包的作用域链包括自身活动对象、包含函数活动对象和全局活动对象。闭包会引用包含函数的活动对象(可以访问包含函数的所有变量),就算包含函数执行结束,闭包的作用域链依然保有这个活动对象,直到闭包不存在

  • 闭包引用到的外部变量如果有多次赋值或改变引用,只引用最后一次

  • 创建方式:在函数内部创建函数

1
2
3
4
5
6
7
8
9
10
11
12
var func = function () {
var funcProp = 1;
return {
instanceMethod: function(){
//引用了funcProp
funcProp ++;
console.log(funcProp);
};
};
}();
func.instanceMethod();//2
func.instanceMethod();//3


闭包与arguments this

  • 每个函数在调用时会自动取得arguments this这两个特殊变量,内部函数在作用域链上搜寻这两个变量时,只会在当前活动对象搜寻,不会在包含函数中搜寻

  • 要让闭包访问到包含函数或外部函数的arguments this,必须把这两个创建一个闭包能够访问的变量来引用这两个变量


模仿块级作用域(私有作用域)

  • 创建并立即执行一个函数
1
2
3
(function(){
statement
})();


私有变量

创建可以访问私有变量和私有方法的特权方法
创建一个对象,让它通过公有方法访问私有变量、私有方法

构造器方法

1
2
3
4
5
6
7
8
9
10
function MyObject (){
var objVariable = 1;
function objMethod (){return false};
this.publicMethod = function() {
objVariable++;
return objMethod();
}
}

原型方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(function(){
var objVariable = 1;
function objMethod() {
return false;
}
MyObject = function(){
};
MyObject.prototype.publicMethod = function () {
objVariable++;
return objMethod();
}
})();

模块模式

单例字面量对象

1
2
3
4
5
6
7
8
9
10
11
12
var single = function(){
var objVariable = 1;
function objMethod (){return false};
return {
publicMethod: function() {
objVariable++;
return objMethod();
}
}
}

增强模块

指定单例类型并添加实例属性方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var single = function(){
var objVariable = 1;
function objMethod (){return false};
var sing = new MyObject();
sing.publicMethod = function() {
objVariable++;
return objMethod();
}
return sing;
}