第三章、函数
1、函数形参可以指定默认值,并且默认值所在的形参不会自动添加到arguments对象中。
2、函数形参可以用表达式作为默认值,也可以用先定义的形参作为后定义的形参的默认值,
但不能用后定义的形参作为先定义的形参的默认值,否则会进入函数默认参数的临时死区。
3、函数参数有自己的作用域和临时死区,其与函数体的作用域是各自独立的,即参数的默认值不可访问函数体内声明的变量。
4、函数形参使用不定参数接收额外的不确定的参数。
1、不定参数的使用限制:
①、每个函数只能声明一个不定参数,而且一定要放在最后
②、不定参数不能用于对象字面量setter之中,因为对象字面量setter的参数有且只能有一个。
2、不定参数对arguments的影响:无论是否使用不定参数,arguments对象总是包含所有传入函数的参数。
5、展开运算符:与不定参数恰好相反。不定参数将多个参数收纳进类数组对象中,展开运算符将类数组对象的各项打散展开。
6、函数name属性的特殊情况:
1、getter函数的name属性带有前缀"get",setter函数的name属性带有前缀"set"
2、通过bind()函数创建的函数,其name属性带有前缀"bound"
3、通过Function构造函数创建的函数, 其name属性是"anonymous"
切记:不能使用name属性的值来获取对于函数的引用
7、函数的多重用途:通过new关键字调用或直接调用
原因:
JavaScript函数有两个不同的内部方法:[[call]]和[[Construct]]
当通过new关键字调用函数时,执行的是[[construct]]函数,它负责创建一个被称作实例的新对象,然后载执行函数体,
将this绑定动实例上;如果不通过new关键字调用函数,则执行[[call]]函数,从而直接执行函数体。
具有[[construct]]方法的函数被称为构造函数。
切记:不是所有的函数都有[[construct]]方法,即不是所有函数都能用new关键字调用(例如箭头函数)。
判断函数是否通过new关键字调用:
判断new.target的值
如果函数是通过new关键字调用的,new.target的值是实例化的新对象;如果不是,new.target的值为"undefined"
8、块级函数:
在代码块中声明块级函数,函数声明会被提升至块的顶部,而用let定义的函数表达式不会被提升。
9、箭头函数:
箭头函数特性:
1、没有this、super、arguments和new.target绑定
箭头函数中的this、super、arguments和new.target这些值由外围最近一层的非箭头函数决定。
2、不能通过new关键字调用
箭头函数没有[[construct]]方法,所以不能被用作构造函数,如果通过new关键字调用函数,程序报错。
3、没有原型
由于不能通过new关键字调用箭头函数,所以箭头函数没有prototype这个属性。
4、不可以改变this的绑定
箭头函数内部的this值不可以被改变,在函数的生命周期内始终保持一致。
5、不支持arguments对象
箭头函数没有arguments绑定,所以只能通过命名参数和不定参数两种形式访问函数的参数。
6、不支持重复的命名参数
箭头函数不支持重复的命名参数。
注意:箭头函数同样也有name属性!
10、尾调用优化
尾调用:函数作为另一个函数的最后一条语句被执行。
es5中尾调用如正常函数调用一样,创建一个栈帧并将其推入调用栈,即未调用完成的栈帧都保存在内存中,
如果调用栈过大就会导致程序出现问题。
es6严格模式下尾调用自动优化:如果满足以下条件,将不再创建新的栈帧,而是清除并重用当前栈帧:
1、尾调用不访问当前栈帧的变量,即函数不是一个闭包。
2、在函数内部,尾调用是最后一条语句。
3、尾调用的结果作为函数值返回。
尾调用优化主要应用在递归函数,例如以下阶乘:
function factorial(n){
if(n <= 1){
return 1;
}else{
return n * factorial(n-1);
}
}
上面这个阶乘,引擎就不会自动优化,因为在返回结果后执行了乘n操作,优化如下:
function factorial(n,r=1){
if(n <= 1){
return 1* r;
}else{
return factorial(n-1,r);
}
}