函数的扩展
1.函数参数的默认值
ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
image.png
注意:
(1)参数变量是默认声明的,不能用let和const再次声明
(2)默认参数值不是单纯的传值的而是惰性求值的
2.与解构赋值默认值结合使用
function foo({x,y=5}){
console.log(x,y)
}
foo({})
VM782:2 undefined 5
undefined
foo({x:3})
VM782:2 3 5
undefined
foo({x:3,y:8})
VM782:2 3 8
undefined
foo()
VM782:1 Uncaught TypeError: Cannot destructure property `x` of 'undefined' or 'null'.
因为函数没有提供默认值,当调用函数时参数为空或者不为对象类型时就会报错,这里只是用了对象的解构赋值的默认值
function foo({x,y=5} = {})
{
console.log(x,y)
}
foo() // undefined 5
参数默认值的位置
参数默认值一般应该是尾参数,如果不是尾参数,一般是无法省略的,需要显式输入undefined ,输入undefined可以触发默认值,输入null则没有这个效果
函数的length属性
length属性的含义是,该函数预期传入的参数个数。函数指定了默认值后,预传入的参数个数就不包括这个参数了。rest参数也不会计入length属性
另外如果默认值不是尾参数,那么length属性将不会再计算默认值后面的参数了
作用域
一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
二、rest参数
ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。
res参数后面不能再有其他参数了
length属性,不包括rest参数
三、严格模式
es6只要函数参数使用了默认值、解构赋值、或者扩展运算符,函数内部就不能显示设定为严格模式
因为只能在函数体中设置严格模式,然而参数却是优先于函数体执行的,所以就矛盾了
四、name属性
函数的name属性,返回该函数的函数名。
var f = function(){}//后面是匿名函数
es5 name会返'回'
es6 name会返回‘f’
五、箭头函数
注意
1.箭头函数直接返回一个对象,必须要在对象外面加一个括号
2.箭头函数可以和变量解构结合使用
箭头函数有几个使用注意点。
(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
function foo(){
setTimeout(()=>{
console.log(this.id)
},100)
}
function fbb(){
setTimeout(function(){
console.log(this.id)
},100)
}
var id = 21
foo.call({id:42}) ///42
fbb.call({id:42}) /// 21
(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
箭头函数没有自己的this,所以不能用call()、apply()、bind()这些方法去改变this的指向
六、双冒号运算符
函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。
七、尾调用优化
尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。
尾调用不一定出现在函数尾部,只要是最后一步操作即可。
function f() {
let m = 1;
let n = 2;
return g(m + n);
}
f();
// 等同于
function f() {
return g(3);
}
f();
// 等同于
g(3);
上面代码中,如果函数g不是尾调用,函数f就需要保存内部变量m和n的值、g的调用位置等信息。但由于调用g之后,函数f就结束了,所以执行到最后一步,完全可以删除f(x)的调用帧,只保留g(3)的调用帧。
这就叫做“尾调用优化”(Tail call optimization),即只保留内层函数的调用帧。如果所有函数都是尾调用,那么完全可以做到每次执行时,调用帧只有一项,这将大大节省内存。这就是“尾调用优化”的意义。
八、尾逗号
因此新的语法允许定义和调用时,尾部直接有一个逗号。