将在ECMAScript 6中添加的rest参数的用途是什么?
例如,在ECMAScript 5中,您可以执行以下操作以从第二个元素开始获取参数数组:
// ES 5
store('Joe', 'money');
store('Jane', 'letters', 'certificates');
function store(name) {
var items = [].slice.call(arguments, 1); //['money'] in first case
items.forEach(function (item) {
vault.customer[name].push(item);
});
}
,这将等同于ECMAScript 6中的以下代码:
// ES 6
store('Joe', 'money');
store('Jane', 'letters', 'certificates');
function store(name, ...items) {
items.forEach(function (item) {
vault.customer[name].push(items)
});
}
它们之间的差异只是语法还是存在性能问题?
也适用于点差运算符(...)
//in ecmascript5
var max = Math.max.apply(null, [14, 3, 77]);
//but in ecmascript6
var max = Math.max(...[14, 3, 77]);
这只是语法更改还是性能问题?
答案 0 :(得分:19)
它们之间的差异只是语法还是存在性能问题?
两者,还有更多...
休息参数:
slice
相比)。答案 1 :(得分:18)
除了@kangax的回复之外,我还会详细说明,在调用arguments
对象时,性能和正确性会出现问题。如果将arguments
对象传递给另一个函数,则会向其传递修改范围中相应局部变量的权利。
function foo(arg) {
bar(arguments);
return arg;
}
function bar(args) {
args[0] = 20;
}
foo(10) // 20
此功能的存在使函数内的局部推理无效,这使得JIT优化更加困难并且引入了某些安全隐患。专为速度而设计的程序必须使用比Array.prototype.slice.call(arguments)
惯用语更复杂的样板代码解决此问题,并且在安全上下文中,必须严格禁止arguments
的传递。
消除使用arguments
对象提取可变参数的需要是新语法的众多优势之一。
答案 2 :(得分:4)
在您给出的示例中,您直接传递对象文字。虽然仍然是语义的,但它似乎与扩展运算符的应用类似。 IMO,当列出每个参数会破坏代码的可读性(以及替换传统的push,splice,concat方法时的可维护性)时,扩展运算符的值变得明显。
let nums = [1.25,5.44,7.15,4.22,6.18,3.11];
function add(a, b, ...nums){
let sum = parseInt(a + b);
nums.forEach(function(num) {
sum += num;
})
return parseInt(sum);
}
console.log(add(1, 2, ...nums)); //30
ES6Fiddle demo(由traceur-compiler编译)
var nums = [1.25,5.44,7.15,4.22,6.18,3.11];
function add(a, b, nums){
var sum = parseInt(a + b);
nums.forEach(function(num) {
sum += num;
})
return parseInt(sum);
}
console.log(add(1, 2, nums)); //30
<强> JSFiddle demo 强>
最后,我认为使用扩展运算符不会改善或阻碍性能,但它确实提供了改进的代码可读性,并且可以说是可维护性。遗憾的是,ES6尚未得到广泛实施,我将断断续续地推测,浏览器支持需要一段时间才能实现。
有趣的事实:PHP 5.6引入了与 variadic functions 类似的功能,这将使func_get_args()
变得多余。
答案 3 :(得分:3)
我认为rest参数的主要区别是:
答案 4 :(得分:3)
当您在函数参数定义中使用点时,rest
参数将收集单个参数到数组中,而当使用function call
中的点时,展开运算符将数组扩展为单个参数。
如果您想将单个参数收集到数组中,可以在函数参数定义中使用rest
运算符。
let sum = (...numbers) => {
let result = 0;
numbers.forEach(function(n){
result += n;
});
return result;
};
console.log(sum(1,2,3));
在嵌套函数中处理arguments
对象变得非常棘手,让我们访问下面的情况,我们的内部函数需要访问传递的arguments
对象。
如果我们的inner function filterNumbers
需要访问参数,则必须将其存储在variable
之上,然后再传递它,因为每个函数都有自己的arguments
对象,这是一个类似的数组对象
function sumOnlyNumbers() {
var args = arguments;
var numbers = filterNumbers();
return numbers.reduce((sum, element) => sum + element);
function filterNumbers() {
return Array.prototype.filter.call(args,
element => typeof element === 'number'
);
}
}
sumOnlyNumbers(1, 'Hello', 5, false);
这种方法有效,但它太冗长了。可以省略var args = arguments
,并使用Array.prototype.filter.call(args)
参数将args.filter()
转换为rest
。
function sumOnlyNumbers(...args) {
var numbers = filterNumbers();
return numbers.reduce((sum, element) => sum + element);
function filterNumbers() {
return args.filter(element => typeof element === 'number');
}
}
sumOnlyNumbers(1, 'Hello', 5, false); // => 6
如果您想将数组扩展为单个参数,可以在函数调用中使用扩展运算符。
let sum = (a,b,c) => {
return a + b + c;
};
console.log(sum(...[1,2,3]));
在上面的代码中,点差运算符将“spread”
parameters a, b, and c
上的三个值的数组spread
。 array
运算符还可以展开数组以在var a = [4, 5, 6];
var b = [1, 2, 3, ...a, 7, 8, 9]
console.log(b);
字面值中创建单个元素。
ES5
改进了ES6中的函数调用
.apply()
在函数对象上提供.apply()
方法来解决此问题。不幸的是,这种技术有3个问题:
似乎无关紧要的是在let countries = ['India', 'USA'];
let otherCountries = ['China', 'Japan'];
countries.push.apply(countries, otherCountries);
console.log(countries); // => ['India', 'USA', 'China', 'Japan']
第二次表明背景国家使其更加冗长。
spread
function
运算符使用array
中的值填充let countries = ['India', 'USA'];
let otherCountries = ['China', 'Japan'];
countries.push(...otherCountries);
console.log(countries); // => ['Moldova', 'Ukraine', 'USA', 'Japan']
调用参数。让我们用扩展运算符改进上面的例子:
Spread
.apply()
运算符从数组中配置构造函数调用参数,这在使用class Actor {
constructor(name, country) {
this.name = name;
this.country = country;
}
getDescription() {
return `${this.name} leads ${this.country}`;
}
}
var details = ['RajiniKanth the Great', 'India'];
var Alexander = new Actor(...details);
console.log(Alexander.getDescription()); // => 'RajiniKanth the Great leads India'
时会有点复杂和困难。
spread
此外,您可以在同一个调用中组合多个var numbers = [1, 2];
var evenNumbers = [4, 8];
const zero = 0;
numbers.splice(0, 2, ...evenNumbers, zero);
console.log(numbers); // => [4, 8, 0]
运算符和常规参数。以下示例是从数组中删除现有元素,然后添加其他数组和元素:
var words = ['Hi', 'Hello', 'Good day'];
var otherWords = [...words];
console.log(otherWords); // => ['Hi', 'Hello', 'Good day']
console.log(otherWords === words); // => false
克隆数组实例:
otherWords
<div id="nav">
<ul>
<li><a href="./index"><div>About Me</div></a>
<ul>
<li><a href="./index">Bio</a></li>
<li><a href="./Resume">Resume</a></li>
</ul>
</li>
<li><a href="https://github.com/user_name" target="_blank"><div>Github</div></a></li>
</ul>
</div>
</div>
是单词数组的克隆版本。请注意,克隆只发生在数组本身,而不是发生在包含的元素上(即它不是深层克隆)。
答案 5 :(得分:1)
其他运营商
function sumOfNumber(...args) {
return args.reduce((a, b) => {
return a + b
})
}
console.log(sumOfNumber(1, 2, 3, 4))
传播算子
function sumOfNumber(args) {
console.log(...args)
}
sumOfNumber([1, 2, 3, 4])