Arguments
arguments是一个可在函数内部可访问,包含传递给函数参数值的对象;
function test (a, b ,c) {
console.log(arguments[0], arguments[1], arguments[2])
}
test(1, 2 ,3) // 1, 2, 3
知识点:
1、arguments对象仅在函数内部可使用,且函数不能为arrow function;
2、虽然arguments是类数组,但是我们可以使用索引去访问元素,并且它有一个length属性,值为参数的个数;
function test (a, b, c) {
console.log(arguments.length)
}
test(1) //1
test(1, 2, 3) //3
3、arguments对象包含函数调用期间传递的所有参数,即使函数声明中没有那么多;
function test(a, b) {
console.log(a, b, arguments)
}
test(1, 2, 3, 4, 5, 6)
// 1, 2, Arrguments[1, 2, 3, 4, 5 ,6, callee: f, length: 6, Symbol(Symbol: iterator): f]
这里可以顺便看到arguments对象的属性:
callee:指向参数所属的当前执行的函数
length: 传递给函数的参数数量
iterator:迭代器对象
arguments类数组转数组
1、方法1: Array.prototype.slice.call(arguments) 或 [].slice.call(arguments)
这里插播一下为什么这里能够转化为数组:
首先从网上扒一下大佬们对slice源码的简化版:
function slice(start, end) {
var startToUse = start || 0,
endToUse = end || ToUint32(this.length),
result = [];
for(var i = startToUse; i < endToUse; i++) {
result.push(this[i]);
}
return result;
}
可见其关键还是slice的实现机制有关,对于满足一定条件的对象(有length属性,key值为数字)即可通过slice转化为返回一个数组; 如
const arrayLike = {
'0: 'a',
'1: 'b',
'2': 'c',
length: 3
}
const arr = [].slice.call(arrayLike) //['a', 'b', 'c']
插播结束....
2、方法2: Array.form(arguments)
3、方法3: [...arguments]
在arguments上使用typeof
typeof arguments // 'object'
注意点:
1、要安全使用函数内部的arguments参数,不能将其泄露或者传递出去,such as:
// Leaking arguments example1:
function getArgs() {
return arguments;
}
// Leaking arguments example2:
function getArgs() {
const args = [].slice.call(arguments);
return args;
}
// Leaking arguments example3:
function getArgs() {
const args = arguments;
return function() {
return args;
};
}
解决方法:创建成一个新数组再返回;
function getArgs() {
const args = new Array(arguments.length);
for(let i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}
return args;
引用: 我们每次使用 arguments 时通常第一步都会将其转换为数组,同时 arguments 使用不当还容易导致性能损失,那么为什么不将 arguments 直接设计成数组对象呢?
这需要从这门语言的一开始说起。arguments 在语言的早期就引入了,当时的 Array 对象具有 4 个方法: toString、 join、 reverse 和 sort。arguments 继承于 Object 的很大原因是不需要这四个方法。而现在,Array 添加了很多强大的方法,比如 forEach、map、filter 等等。那为什么现在不在新的版本里让 arguments 重新继承自 Array呢?其实 ES5 的草案中就包含这一点,但为了向前兼容,最终还是被委员会否决了。
2、在sloppy mode下可以对参数进行修改会影响到arguments object,但是在use strict下两者没有联系
3、需要将参数从一个函数传给另一个函数时,推荐通过apply方法:
function foo() {
bar.apply(this, arguments);
}
function bar(a, b, c) {
}
3、可利用arguments进行模拟函数重载(所谓重载:即函数根据参数的不同而产生不同的调用)
关于arguments的知识点与使用还有很多就不一一说明了,目前留下个疑问:
为什么将arguments传递出去会造成泄露,导致V8引擎没有优化,网上看有人回答说是因为会一直保持对arguments对象的使用,导致V8必须实例化其为JavaScript对象而不是优化为堆栈变量,那以下两种方式为什么会保留了对arguments对象的引用呢?
// Leaking arguments example1:
function getArgs() {
return arguments;
}
// Leaking arguments example2:
function getArgs() {
const args = [].slice.call(arguments);
return args;
}
剩余参数(Rest Parameters)
说明:剩余参数主要是ECMAScript用来替换arguments,可以拿到函数除开始参数外的多余参数;该对象是自定义的普通标识符,只是需要在前面加上三个点:...;
描述:如果函数的最后一个命名参数以...为前缀,则它将成为一个由剩余参数组成的真数组,其中从0(包括)到theArgs.length(排除)的元素由传递给函数的实际参数提供
如果函数的最后一个命名参数以...为前缀,则它将成为一个由剩余参数组成的真数组,其中从0(包括)到theArgs.length(排除)的元素由传递给函数的实际参数提供;
提取重点:
1、以...开头,位置上必须在最后一个参数
2、是一个数组;
const testFun = function (...theArgs) {
console.log(theArgs) // [1, 2, 3, 4, 5, 6]
}
还可以对theArgs进行解构:
function (...[a, b, c]) {
return a + b + c
}
f(1, 2, 3, 4) // 6
尾语
由于剩余参数是用来替换arguments的,所以用法基本无差,主要是属性有差别,所以今日的熟悉就到这里了,整体并不难,难点为arguments的optimization!!!等我变厉害了再回来补充~~~~