认识 arguments

什么是 arguments

arguments 是一个对应于传递给函数的参数的类数组对象。(MDN)

  • 类数组对象,就说明它本质上是一个对象类型

  • 类数组表示它长得像数组,并且拥有数组的一些特性,比如说 length,可以通过 index 访问

    但是却没有数组的一些方法,比如说 forEach,map 等

function foo() {
// 会帮你接收所有传递给函数的参数
console.log(arguments); // [Arguments] { '0': 10, '1': 20, '2': 30 }

// 获取参数的长度
console.log(arguments.length); // 3
// 根据索引值获取某一个参数
console.log(arguments[1]); // 20
// 获取当前 arguments 所在的函数
console.log(arguments.callee); // [Function: foo]

// arguments.forEach() 是不可以的
}

foo(10,20,30)

arguments 转成数组

如果我们需要遍历里面的参数呢?或者说使用一些数组的方法呢?

所以在开发中,我们经常会把 arguments 转成数组

第一种方法: 自己遍历
function foo() {
// 我们可以通过索引值拿到 arguments 的每一个值
// 然后添加到新的数组
let newArr = []
for (let i = 0; i < arguments.length; i++) {
newArr.push(arguments[i])
}
console.log(newArr); // [ 10, 20, 30, 40, 50 ]
}
foo(10, 20, 30, 40, 50)
第二种方法:Array.prototype.slice
function foo() {
let newArr = Array.prototype.slice.call(arguments)
console.log(newArr); // [1, 2, 3, 4, 5, 6]
}

foo(1,2,3,4,5,6)

Array.prototype.slice.call(arguments) ?什么意思呀?

首先,我们一般使用 slice 的时候,是 arr.slice(start, end),那如果没有这个arr呢?我们怎么才能拿到 slice 这个方法

是不是可以在 Array 的原型上面找这个方法,所以 Array.prototype.slice()

那为什么要用 call 来调用?

我们先来模拟一下 Array 中的 slice 是怎么实现的

Array.prototype.myslice = function(start, end) {
// 如果我们直接 Array.prototype.myslice() 这样调用的话, this 指向的就是prototype了
// 而我们希望的是, 这里的 this 是指向调用 slice 这个方法的数组
let arr = this
start = start || 0
end = end || arr.length

let newArray = []
// 从start到end(不包括end),把元素添加到数组
for (let i = start; i < end; i++) {
newArray.push(arr[i])
}
return newArray
}

所以,我们要使用 call 来显式绑定这个 this,让this指向数组

let newArr = Array.prototype.myslice.call([1,2,3,4,5,6])
console.log(newArr); // [1, 2, 3, 4, 5, 6]

// 当然可以传递参数
let newArr2 = Array.prototype.myslice.call([1,2,3,4,5,6], 2, 4)
console.log(newArr2); // [3, 4]

那跟我们 arguments 有什么关系?

Array内部 slice 的实现只不过是对 this,也就是需要使用 slice 的数组进行遍历,然后把需要的部分加入到新数组

那遍历 arguments 也可以啊,把元素一个个加入到一个数组里面,再把这个数组返回,最后不就实现了 arguments 转数组了吗

function foo() {
let newArr = Array.prototype.slice.call(arguments)
console.log(newArr); // [1, 2, 3, 4, 5, 6]

// 同样道理的还有一种方法, 我们目的就是拿到 slice 这个方法,并且让 this 绑定 arguments,让内部遍历arguments
let newArr2 = [].slice.call(arguments)
}

foo(1,2,3,4,5,6)

再看回这个,应该理解了吧

Array.from (ES6)

Array.from() 方法对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例(MDN)

function foo() {
let newArr = Array.from(arguments)
console.log(newArr); // [1, 2, 3, 4, 5, 6]
}
foo(1,2,3,4,5,6)
展开运算符 (ES6)
function foo() {
// 因为展开运算符实际上也是遍历,把遍历的元素一个个放到数组
let newArr = [...arguments]
console.log(newArr); // [1, 2, 3, 4, 5, 6]
}
foo(1,2,3,4,5,6)

箭头函数没有 arguments

箭头函数是不绑定 arguments 的,如果在箭头函数中使用 arguments,会去找上层作用域中的arguments

注意,全局作用域是没有 arguments 的

var foo = () => {
// 找上层作用域,找到 window
console.log(arguments); // arguments is not defined
}

foo()
function foo() {
// arguments 有 123
console.log(arguments); // Arguments [123]

var bar = () => {
console.log(arguments); // Arguments [123]
}
return bar
}

var fn = foo(123)
fn()

那如果想传递多个参数呢?用 ES6 的剩余参数

var foo = (a, b, ...args) => {
console.log(a, b); // 1 2
console.log(args); // [3,4,5,6]
}

foo(1,2,3,4,5,6)