箭头函数;
函数表达式;
递归;
尾调用优化;
参数扩展与收集;
this;
特权方法;
闭包(这块本书较晦涩,you don’t konw js更好);
模块模式;
new.target;
书摘&心得
1 概述
定义函数的方式有两种,一种是函数声明,另一种是函数表达式。
函数声明
函数声明的语法:

函数声明提升:在执行代码之前会先读取函数声明。
函数表达式
常用形式:

这种情况下创建的函数叫做匿名函数(也叫拉姆达函数),匿名函数的name属性是空字符串。
- 不存在函数声明提升。
- 能够创建函数再赋值给变量,也就能够把函数作为其他函数的返回值。
2 递归
1、递归函数是在一个函数通过名字调用自身的情况下构成的
但由于函数名可变这种方式不是很稳定
2、也可以通过arguments.callee实现对函数的递归调用。
- 严格模式下不可访问arguments.callee
3 闭包
3.1 定义
闭包是指有权访问另一个函数作用域中的变量的函数。
创建闭包的常见方式:在一个函数内部创建另一个函数。
3. 2 原理
1、作用域链
当某个函数被调用时,会创建一个执行环境及相应的作用域链。
有compare函数:
function compare(value1, value2){
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
}
var result = compare(5, 10);
其作用域链如下图:
- 后台的每个执行环境都有一个表示变量的对象——变量对象。在函数执行过程中,会在作用域链中查找变量。
- 全局环境的变量对象始终存在,而compare函数这样的局部环境的变量对象只在函数执行的过程中存在。
- 在创建compare()函数时,会创建一个预先包含全局变量对象的作用域链,被保存在内部的[[Scope]]属性中。
- 在调用compare()函数时,会为函数创建一个执行环境,然后复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链。
作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。
2、闭包的作用域链
在另一个函数内部定义的函数会将外部函数(包含函数)的活动对象添加到它的作用域链中。

以上述闭包为例,下图展示了闭包中外部函数与内部匿名函数的作用域链。

闭包只能取得外部函数中任何变量的最终值

- 上述函数每个都返回10
- 考试最爱出这种题
利用参数按值传递的特性可以强行让闭包的行为符合预期

3、关于this对象
匿名函数的执行环境具有全局性,其this对象通常指向window
- 运行时基于函数的执行环境绑定。
每个函数被调用时都会自动获取2个变量:this、arguments
通常有垃圾回收机制所以不必过于担心。
本书中对内存泄露的讨论比较浅显,只涉及了低版本IE浏览器下的DOM内存泄露问题。
4 模仿块级作用域
匿名函数可以模仿块级作用域

-
5 私有变量
5.1 我的笔记
5.1.1 关于特权方法
在上述函数内部有3个私有变量,在函数内部可以访问这几个变量,在外部则不能访问它们。
- 如果在这个函数内部创建一个闭包,那么闭包通过自己的作用域链也可以访问这些变量。利用这一点,就可以创建用于访问私有变量的共有方法。
将上述公有方法称为特权方法。有两种创建特权方法的方式
- 一种方式是使用静态私有变量来实现特权方法,详见书章节7.4.1。
另一种是在构造函数中定义特权方法,在创建MyObject实例后,除了使用publicMethod()这一个途径外,没有任何办法可以直接访问privateVariable和privateFunction():

5.1.2 模块模式
模块模式是为单例创建私有变量的特权方法
- 单例是指只有一个实例的对象
如果必须创建一个对象并以某些数据对其初始化,同时还要公开一些能够访问这些私有数据的方法,就可以使用模块模式

返回的对象字面量中包含可以公开的属性和方法,由于这个对象是在匿名函数内部定义的,因此它的公有方法有权访问私有变量和函数。
- 从本质上来讲,这个对象字面量定义的是单例的公共接口。
简而言之,如果必须创建一个对象并以某些数据对其初始化,同时还要公开一些能够访问这些私有数据的方法,那么就使用模块模式。
5.1.3 其他笔记
5.2 读后感
5.2.1 静态私有变量
关键词:全局变量、全局作用域、所有实例共享
应用度:较低
和其他高级语言中的静态变量有些像,但是js需要通过一种很晦涩的方式来实现。5.2.2 模块模式
应用度:造轮子可参考
简而言之,如果必须创建一个对象并以某些数据对其初始化,同时还要公开一些能够访问这些私有数据的方法,那么久使用模块模式。5.2.3 增强的模块模式
应用度:造轮子可以参考
适合单例必须是某种类型的实例,同时还必须添加某些属性和方法对其加以增强的情况。
详见章节7.4.36 第四版新增
6.1 箭头函数
ES6新增
- 箭头函数也可以不用大括号,不用大括号时直接返回表达式计算值
- 箭头函数不能使用arguments、super和new.target,也不能用作构造函数。
-
6.2 扩展与收集
扩展
// arr is an array
fn(...arr);
收集
收集的参数必须在末尾
function aa(...params) {
// params is an array
}
6.3 new.target
- 如果函数是正常调用的,则new.target的值是undefined;
如果是使用new关键字调用的,则new.target将引用被调用的构造函数。
6.4 尾调用优化
一项内存管理优化机制,让JavaScript引擎在满足条件时可以重用栈帧。
- “尾调用”:外部函数的返回值是一个内部函数的返回值。
- 尾调用优化条件
- ❑ 代码在严格模式下执行;
- ❑ 外部函数的返回值是对尾调用函数的调用;
- ❑ 尾调用函数返回后不需要执行额外的逻辑;
- ❑ 尾调用函数不是引用外部函数作用域中自由变量的闭包。
这个优化在递归场景下的效果是最明显的,因为递归代码最容易在栈内存中迅速产生大量栈帧
闭包的普通特性,保存词法环境
- 闭包的应用
- 模仿块级作用域
- 在对象中创建私有变量