【JavaScript】JavaScript高级程序设计 第七章 函数表达式

定义函数的方式:①函数声明 ②函数表达式

①函数声明

重要特征:函数声明提升:在执行代码之前会先读取函数声明。

②函数表达式

函数表达式在使用前必须先赋值。

把函数当成值来使用时,都可以使用匿名函数。

7.1 递归

递归函数:一个函数通过名字调用自身。

问题:如果在通过名字调用函数前,函数被修改了,会导致问题。

解决:①arguments.callee一个指向正在执行的函数的指针。(严格模式下出错)

​ ②命名函数表达式

1
2
3
4
5
6
7
8
9
/*递归函数*/
var factorial = (function f(num){
if (num <=1) {
return 1;
} else{
return num * f(num-1);
}
})

7.2 闭包

闭包函数:有权访问另一个函数作用域的变量的函数。

创建方式:在一个函数内部创建另一个函数。

FVVxZ4.png

每个执行环境都有一个表示变量的对象。

全局环境的变量对象始终存在,局部变量对象只在执行过程中存在。

作用域链本质:一个指向变量对象的指针列表,它只引用不包含变量对象。

一般来说:当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域。但闭包不同。

闭包函数:闭包函数会将包含函数的活动对象添加到它的作用域链中。

7.2.1 闭包与变量

闭包只能取得包含函数中任何变量的最后一个值。

闭包所保存的是整个变量对象,而不是某个变量。

7.2.2 关于this对象

this对象:在运行时基于函数的执行环境绑定的。全局函数中:this = window;函数被当做某个对象的方法调用:this = 某个对象;匿名函数:this=window;通过call()/apply():this指向对象。

目的:在闭包函数中(通常是匿名函数)使用this,希望this返回的是外部函数对象。

方法:把外部作用域中的this对象保存在一个闭包能访问到的变量里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*闭包函数访问的包含函数对象*/
var name = "The Window";
var object = {
name: "My object",
getNameFunc: function(){
var that = this;
return function(){
return that.name;
}
}
}
alert(object.getNameFunc()());

7.2.3 内存泄漏

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

7.3 模仿块级作用域

js没有块级作用域:在块语句中定义的变量,实际上是在包含函数中而非语句中创建的。

重复声明:js会忽略后续声明,但会执行后续声明中的变量初始化。

私有作用域:用作块级作用域的匿名函数

(function(){

​ // 这里是块级作用域

})();

定义并立即调用一个匿名函数。将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而之后的另一对圆括号会立即调用这个函数。

在匿名函数中定义的任何变量,都会在执行结束时被销毁。

用法:用在全局作用域中的函数外部,从而限制向全局作用域中添加过多的变量和函数。

7.4 私有变量

js中没有私有成员的概念,所有对象属性都是公有的。但是有一个私有变量的概念。

私有变量:任何在函数中定义的局部变量、函数的参数和函数内部定义的其他函数。

特权方法:

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

创建特权方式的方法①:

在构造函数中定义特权方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*在构造函数中定义特权方法*/
function MyObject(){
//私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
//特权方法
this.publicMethod = function(){
privateVariable++;
return privateFunction();
}
}

缺点就是使用构造函数的通病:每个实例都会创建同样一组新方法。

7.4.1 静态私有变量

创建特权方式的方法②:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*静态私有变量*/
(function(){
//私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
//构造函数 使用函数表达式 因为函数声明只能创建局部函数
MyObect = function(){};
//公有/特权方法
MyObect.prototype.publicMethod = function(){
privateVariable++;
return privateFunction();
}
})();

缺点:每个实例都没有自己的私有变量。

7.4.2 模块模式

7.4.3 增强的模块模式