温故系列のES6扩展:方便的形参不定参数

92 阅读1分钟

我正在参加「掘金·启航计划」

不定参数

无论函数已定义的命名参数有多少,都不限制调用时传入的实际参数数量,调用时总是可以传入任意数量的参数。当传入更少数量的参数时,默认参数值的特性可以有效简化函数声明的代码;当传入更多数量的参数时,ES6同样也提供了更好的方案。

【ES5】早先,Javascript提供arguments对象来检查函数的所有参数,从而不必定义每一个要用的参数。尽管arguments对象检査在大多数情况下运行良好,但是实际使用起来却有些笨重,[吐槽:我们现在的项目就是使用这种方式]

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: "ES6",
    author: "huochai",
    year: 2017
};
let bookData = pick(book, "author", "year");
console.log(bookData.author); // "huochai"
console.log(bookData.year); // 2017

这个函数模仿了Underscore.js库中的pick()方法,返回一个给定对象的副本,包含原始对象属性的特定子集。在这个示例中只定义了一个参数,第一个参数传入的是被复制属性的源对象,其他参数为被复制属性的名称

关于pick()函数应该注意这样几件事情:首先,并不容易发现这个函数可以接受任意数量的参数,当然,可以定义更多的参数,但是怎么也达不到要求;其次,因为第一个参数为命名参数且已被使用,要查找需要拷贝的属性名称时,不得不从索引1而不是索引0开始遍历arguments对象

【ES6】在ES6中,通过引入不定参数(rest parameters)的特性可以解决这些问题,不定参数也称为剩余参数或rest参数

在函数的命名参数前添加三个点(...)就表明这是一个不定参数,该参数为一个数组,包含着自它之后传入的所有参数,通过这个数组名即可逐一访问里面的参数

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;
}

在这个函数中,不定参数keys包含的是object之后传入的所有参数,而arguments对象包含的则是所有传入的参数,包括object。这样一来,就可以放心地遍历keys对象了。这种方法还有另一个好处,只需看一眼函数就可以知道该函数可以处理的参数数量

【使用限制】不定参数有两条使用限制

1、每个函数最多只能声明一个不定参数,而且一定要放在所有参数的末尾

// 语法错误:不能在剩余参数后使用具名参数
function pick(object, ...keys, last) {
    let result = Object.create(null);
    for (let i = 0, len = keys.length; i < len; i++) {
        result[keys[i]] = object[keys[i]];
    }
    return result;
}

2、不定参数不能在对象字面量的 setter 属性中使用

let object = {
    // 语法错误:不能在 setter 中使用剩余参数
    set name(...value) {
        // 一些操作
    }
};

之所以存在这条限制,是因为对象字面量setter的参数有且只能有一个。而在不定参数的定义中,参数的数量可以无限多,所以在当前上下文中不允许使用不定参数

【arguments】

不定参数的设计初衷是代替JS的arguments对象。起初,在ES4草案中,arguments对象被移除并添加了不定参数的特性,从而可以传入不限数量的参数。但是ES4从未被标准化,这个想法被搁置下来,直到重新引入了ES6标准,唯一的区别是arguments对象依然存在

function checkArgs(n,...args) {
    console.log(args.length);//2
    console.log(arguments.length);//3
    console.log(args);//['b','c']
    console.log(arguments);//['a','b','c']
}
checkArgs("a", "b", "c");

【应用】不定参数中的变量代表一个数组,所以数组特有的方法都可以用于这个变量

// arguments变量的写法
function sortNumbers() {
  return Array.prototype.slice.call(arguments).sort();
}

// 不定参数的写法
const sortNumbers = (...numbers) => numbers.sort();