深入理解ES6-3.函数(1)

41 阅读3分钟

在js中,无论在函数定义中声明了多少形参,都可以传入任意数量的参数。当已定义的形参无对应传入实参时,可以为其指定默认值。

默认参数

// 当不为有默认值的参数传值或传入undefined的时候,会使用其默认值
function A(name, age = 8, nation) {}

默认参数对arguments对象的影响

在es5的非严格模式下,命名参数(实参有传递)的变化会同步更新到arguments对象中。但在严格模式下,无论参数如何变化,arguments对象不再随之改变。

function mixArgs(first,second){       
    console.log(arguments.length);        //1
    console.log(first == arguments[0]);   //true
    
    console.log(second);                  //undefined,没有传递值的命名参数自动赋值undefined
    console.log(arguments[1]);            //undefined,arguments是类数组,超出数组长度的下标值为undefined
    console.log(second == arguments[1]);  //true
    
    first = 'c';
    second = 'd';
    console.log(first == arguments[0]);   //true
    
    console.log(second);                  //d
    console.log(arguments[1]);            //undefined
    console.log(second == arguments[1]);  //false
}
mixArgs('a');

function mixArgs(first,second){    
    'use strict';   
    console.log(arguments.length);        //1
    console.log(first == arguments[0]);   //true
    console.log(second == arguments[1]);  //true
    
    first = 'c';
    second = 'd';
    console.log(first == arguments[0]);   //false
    console.log(second == arguments[1]);  //false
}
mixArgs('a');

在es6中,如果一个函数使用了默认参数值,其行为都和es5严格模式一致,也就是无论参数如何变化,arguments对象不再随之改变。

function mixArgs(first,second = 'b'){
    // 'use strict';   //默认值与严格模式冲突了,如果在函数中使用严格模式,那么函数的参数就不能有默认值
    console.log(arguments.length);        //1
    console.log(first == arguments[0]);   //true
    console.log(second == arguments[1]);  //false
    first = 'c';
    second = 'd';
    console.log(first == arguments[0]);   //false
    console.log(second == arguments[1]);  //false
}

mixArgs('a');

默认参数表达式

默认参数的值不一定非要是一个常量,也可以通过函数执行的到默认参数的值。

function getValue() {return 5}
function add(first,second = getValue()) {return first + second}

由于默认参数是在函数调用的时候求值的,所以可以使用先定义的参数作为后定义参数的默认值。

function add(first,second = first) {return first + second}

但不可以在先定义的参数上访问后定义的参数,这是会报错的,因为此时后定义的参数正处于临时死区。

不定参数

由于js中形参和传入实参的个数没有限制,当形参个数 > 实参个数,我们可以使用默认参数来设置多余形参的默认值,当形参个数 < 实参个数,我们也可以使用不定参数。

// pick函数从传进来的对象中获取指定key的合集
function pick(object){       
    let result = Object.create(null);
    for(let i =1,len = arguments.length;i<len;i++){
        result[arguments[i]] = object[arguments[i]];  
    }                                                
    return result;
}
let book = {
    title:"Understanding ECMAScript 6",
    autor:"Nicholas C. Zakas",
    year:2016
}
let bookData = pick(book,"autor","year")

但是上述代码会有两个问题:

  1. 单独看pick函数,只有一个参数,对于可以传入多个参数看起来不明朗
  2. 调用时传入了三个参数,只有第一个参数有命名形参,后面两个都是无命名参数,取的时候只能遍历arguments,且不是从下标0开始

为了解决这些问题,es6引入了不定参数,在命名参数前添加三个点(...),该参数为一个数组,包含自它之后传入的所有参数。

function pick(object,...keys){        
    let result = Object.create(null);
    for(let i =0,len = keys.length;i<len;i++){
        result[keys[i]] = object[keys[i]];  
    }                                                  
    return result;
}

使用限制

  1. 一个函数最多只能声明一个不定参数,且一定要放在所有参数的末尾
  2. 不定参数不可以用在对象字面量setter中

增强的Function构造函数

es6中,Function构造函数也支持参数默认值和不定参数

new Function("first", "second=first", "return first+second")
new Function("...args", "return args[0]")

展开运算符

展开运算符可以让你指定一个数组,将它们打散后作为独立的参数传入函数。

//Math.max不支持传入数组,但支持传入多个参数
let num1 = Math.max(25,50,75,100);
let values = [25,50,75,100];

//apply可将数组解析成一个一个的参数列表
let num2 = Math.max.apply(Math,values);

//用apply不清晰,es6加入不定参数
let num3 = Math.max(...values);