函数形参默认值
ES5默认形参
ES5中模拟默认形参
但是这种方法也有缺陷,如果第二个值我们传0,会被视为一个假值,函数timeout最后取值却为2000。
更好的做法是:
ES6默认形参
ES6做法:
注意: 当timeout传值为undefined时,最终取值为默认值2000;
对arguments影响
ES5非严格模式下,形参值被改变,arguments对应的也跟着改变:
严格模式下,无论形参如何被赋值,arguments不再跟着改变;
ES6中,如果使用了默认参数,则无论是否显式定义了严格模式,arguments行为与ES5严格模式下保持一致;
默认参数表达式
默认参数也可以使用表达式;
默认参数表达式求值条件:当调用函数不传入默认参数对应位置的值时才会调用;
|
|
默认参数临时死区(TDZ)
默认参数也类似let有默认死区,后面的参数不能用在之前参数的默认值上:
无命名参数
由于之前当有多个无命名参数时,我们需要利用arguments参数来处理,有一个问题是需要记录从哪个索引开始,比较麻烦;
ES6做法:
|
|
不定参数使用限制:最多只能一个不定参数,而且一定要放在所有参数的最后;
|
|
增强的Function构造函数
Function构造函数也可以使用默认参数和无命名参数:
|
|
展开运算符
|
|
name属性
|
|
注意:
- 命名函数(doSomethingElse)并且赋值了一个变量(doSomething),取命名的名字doSomethingElse;
- get属性的函数前面会有一个get; // chrome是返回undefined,需要确认是不是实现不一致;
- 利用bind生成的新函数前面有一个bound
- Function构造函数生成的函数为anonymous
明确函数的多重用途
JS函数有两个不同的内部方法: [[Call]]和[[Construct]]。当通过new关键字调用函数时,执行的是[[Construct]],它负责创建一个通常被称为实例的新对象,然后再执行函数体,将this绑定到新实例上;如果不通过new关键字调用函数,则执行[[Call]]函数,从而直接执行代码中的函数体。具有[[Construct]]方法的函数被统称为构造函数。
注意:不是所有的函数都有[[Construct]]方法,例如箭头函数就没有[[Construct]]方法,所以箭头函数不能使用new关键字调用;
之前ES5判断一个函数是不是通过’new’调用会判断this的原型, 但是这也有问题,函数执行没有用new但使用call来改变this同样可以不报错:
元属性new.target
为了解决判断函数是否通过new关键字调用的问题,ES6引入了new.target这个元属性;
元属性是指非对象的属性,其可以提供非对象目标的补充信息;当调用函数的[[Construct]]方法时,new.target被赋值为new操作符的目标,通常是新创建对象实例,也就是函数体内this的构造函数,如果调用[[Call]]方法,则new.target的值为undefined。则判断一个函数是否是通过new关键字调用的,可以这样:
|
|
在函数体外使用new.target是一个语法错误
块级函数
ES5严格模式下声明块级函数会抛出错误;ES6中,会将块级函数视作一个块级声明,从而在代码块内可以访问和调用;但是块级函数会被提升至顶部;
|
|
如果要真正的定义块级函数,可以使用let表达式,这样函数表达式就不会提升了;并且有临时死区的情况,如:
箭头函数
- 无this super arguments和new.target绑定
这些值由外围最近一层非箭头函数决定;
- 不能通过new关键字调用
正如之前提到过的箭头函数没有[[Constructor]]方法,不能通过new关键字调用,;
|
|
- 没有原型
|
|
- 不可以改变this的绑定
|
|
- 不支持arguments对象
绑定的arguments是外围非箭头函数的arguments
|
|
- 不支持重复的命名参数
传统函数,只有严格模式不能使用重名的参数;
箭头函数中,不支持重复的命名参数
尾调用优化
ES6缩减了严格模式下尾调用栈的大小(非严格模式下不影响),如果满足以下条件,尾调用不再创建新的栈帧,而是清楚并重用当前栈帧:
- 尾调用不访问当前栈帧的变量;(函数不是一个闭包)
- 在函数内部,尾调用是最后一条语句;
- 尾调用的结果作为函数值返回;
满足条件的尾调用:
不满足第一个条件
不满足第二个条件
不满足第三个条件