arguments
arguments 是一个对应于传递给函数的参数的类数组对象。
小试牛刀
function func1(a, b, c) {
console.log(arguments)
console.log(arguments[0]) // 1
console.log(arguments[1]) // 2
console.log(arguments[2]) // 3
}
func1(1, 2, 3)
“类数组” 意味着 arguments 有 长度 属性 并且属性的索引是从零开始的, 但是它没有 Array的 内置方法, 例如 forEach() 和 map()都是没有的
arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引0处。例如,如果一个函数传递了三个参数,你可以以如下方式引用他们:
arguments[0]
arguments[1]
参数也可以被设置:
arguments[1] = 'new value'
arguments对象不是一个 Array 。它类似于Array,但除了length属性和索引元素之外没有任何Array属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的Array:
var args = Array.prototype.slice.call(arguments)
var args = [].slice.call(arguments)
// ES6
const args = Array.from(arguments)
const args = [...arguments]
如果调用的参数多于正式声明接受的参数,则可以使用arguments对象。这种技术对于可以传递可变数量的参数的函数很有用。使用 arguments.length来确定传递给函数参数的个数,然后使用arguments对象来处理每个参数。要确定函数签名中(输入)参数的数量,请使用Function.length属性。
typeof arguments返回 ‘object’。
console.log(typeof arguments) // undefined
// arguments 对象只能在函数内使用
function test(a) {
console.log(typeof arguments) // object
console.log(a, Object.prototype.toString.call(arguments)) // 1 '[object Arguments]'
console.log(arguments[0], arguments[1]) // 1 undefined
console.log(typeof arguments[0]) // number
}
test(1)
可以使用索引确定单个参数的类型。
console.log(typeof arguments[0])
属性
- arguments.callee——指向参数所属的当前执行的函数。
- arguments.length——传递给函数的参数数量。
- arguments[@@iterator]——返回一个新的Array 迭代器 对象,该对象包含参数中每个索引的值。
在严格模式下,arguments对象已与过往不同。arguments[@@iterator]不再与函数的实际形参之间共享,同时caller属性也被移除。
应用
遍历参数求和
function add() {
var sum = 0, len = arguments.length
for(var i = 0;i < len;i++){
sum += arguments[i]
}
return sum
}
console.log(add(1)) // 1
console.log(add(1,2,3,4)) // 10
定义连接字符串的函数
这个例子定义了一个函数来连接字符串。这个函数唯一正式声明了的参数是一个字符串,该参数指定一个字符作为衔接点来连接字符串。你可以传递任意数量的参数到该函数,并使用每个参数作为列表中的项创建列表。该函数定义如下:
function myConcat(separator) {
var args = Array.prototype.slice.call(arguments, 1)
return args.join(separator)
}
console.log(myConcat(",", "red", "orange", "blue")) // 'red,orange,blue'
console.log(myConcat(".", "a", "b", "c")) // 'a.b.c'
为了在arguments对象上使用Array方法,它必须首先被转换为一个真正的数组。
function sortArguments() {
var args = Array.prototype.slice.call(arguments)
return args.sort()
}
console.log(sortArguments(5, 3, 7, 1)) // [1, 3, 5, 7]
剩余参数、默认参数和解构赋值参数
arguments对象可以与剩余参数、默认参数和解构赋值参数结合使用。
在严格模式下,剩余参数、默认参数和解构赋值参数的存在不会改变 arguments对象的行为,但是在非严格模式下就有所不同了。
当非严格模式中的函数没有包含剩余参数、默认参数和解构赋值,那么arguments对象中的值会跟踪参数的值(反之亦然)。看下面的代码:
function func(a) {
arguments[0] = 99 // 更新了arguments[0] 同样更新了a
console.log(a) // 99
}
func(10)
并且
function func(a) {
a = 99 // 更新了a 同样更新了arguments[0]
console.log(arguments[0]) // 99
}
func(10)
当非严格模式中的函数有包含剩余参数、默认参数和解构赋值,那么arguments对象中的值不会跟踪参数的值(反之亦然)。相反, arguments反映了调用时提供的参数:
function func(a = 55) {
arguments[0] = 99 // 更新了arguments[0] 不会同时更新a
console.log(a) // 10
}
func(10)
并且
function func(a = 55) {
a = 99 // 更新了a 不会同时更新arguments[0]
console.log(arguments[0]) // 10
}
func(10)
并且
function func(a = 55) {
console.log(arguments[0]) // undefined
}
func()
剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
牛刀小试
function sum(...theArgs) {
console.log(theArgs) // [1, 2, 3, 4]
return theArgs.reduce((previous, item) => {
return previous + item
})
}
console.log(sum(1, 2, 3, 4)) // 10
语法
function(a, b, ...theArgs) {
// ...
}
描述
如果函数的最后一个命名参数以…为前缀,则它将成为一个由剩余参数组成的真数组,其中从0(包括)到theArgs.length(排除)的元素由传递给函数的实际参数提供。
在上面的例子中,theArgs将收集该函数的第三个参数(因为第一个参数被映射到a,而第二个参数映射到b)和所有后续参数。
剩余参数和 arguments对象的区别
剩余参数和 arguments对象之间的区别主要有三个:
- 剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参。
- arguments对象不是一个真正的数组,而剩余参数是真正的 Array实例,也就是说你能够在它上面直接使用所有的数组方法,比如 sort,map,forEach或pop。
- arguments对象还有一些附加的属性 (如callee属性)。
解构剩余参数
剩余参数可以被解构,这意味着他们的数据可以被解包到不同的变量中。
function f(...[a, b, c]) {
return a + b + c
}
console.log(f(1)) // NaN (b and c are undefined)
console.log(f(1, 2, 3)) // 6
console.log(f(1, 2, 3, 4)) // 6 (the fourth parameter is not destructured)
应用
因为theArgs是个数组,所以你可以使用length属性得到剩余参数的个数:
function fun1(...theArgs) {
console.log(theArgs.length);
}
fun1() // 0, 因为theArgs没有元素
fun1(5, 6, 7) // 3, 因为theArgs有三个元素
下例中,剩余参数包含了从第二个到最后的所有实参,然后用第一个实参依次乘以它们:
function multiply(multiplier, ...theArgs) {
return theArgs.map(function (item) {
return multiplier * item
})
}
var arr = multiply(2, 1, 2, 3)
console.log(arr) // [2, 4, 6]
下例演示了你可以在剩余参数上使用任意的数组方法,而arguments对象不可以:
function sortRestArgs(...theArgs) {
return theArgs.sort()
}
console.log(sortRestArgs(5,3,7,1)) // [1, 3, 5, 7]
function sortArguments() {
var sortedArgs = arguments.sort() // TypeError: arguments.sort is not a function
return sortedArgs // 不会执行到这里
}
console.log(sortArguments(5,3,7,1))
默认参数值
函数默认参数允许在没有值或undefined被传入时使用默认形参。
小牛试刀
function multiply(a, b = 1) {
return a * b
}
console.log(multiply(5, 2)) // 10
console.log(multiply(5)) // 5
语法
function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) {
statements
}
描述
JavaScript 中函数的参数默认是undefined。然而,在某些情况下可能需要设置一个不同的默认值。这是默认参数可以帮助的地方。
以前,一般设置默认参数的方法是在函数体测试参数是否为undefined,如果是的话就设置为默认的值。
下面的例子中,如果在调用multiply时,参数b的值没有提供,那么它的值就为undefined。如果直接执行a * b,函数会返回 NaN。
function multiply(a, b) {
return a * b
}
console.log(multiply(5, 2)) // 10
console.log(multiply(5)) // NaN
为了防止这种情况,第二行代码解决了这个问题,其中如果只使用一个参数调用multiply,则b设置为1:
function multiply(a, b) {
b = (typeof b !== 'undefined') ? b : 1
return a * b
}
console.log(multiply(5, 2)) // 10
console.log(multiply(5)) // 5
有了默认参数,我们不需要再在函数体内做不必要的检查。现在你可以在函数头将b的默认值置为1:
function multiply(a, b = 1) {
return a * b
}
console.log(multiply(5, 2)) // 10
console.log(multiply(5)) // 5
应用
传入 undefined vs 其他假值
在第二次调用中,即使第一个参数在调用时显式设置为undefined(虽然不是null或其他falsy值),但是num参数的值是默认值。
function test(num = 1) {
console.log(typeof num);
}
test() // number (num is set to 1)
test(undefined) // number (num is set to 1 too)
// test with other falsy values:
test('') // string (num is set to '')
test(null) // object (num is set to null)
调用时解析
在函数被调用时,参数默认值会被解析,每次函数调用时都会创建一个新的参数对象。
function append(value, array = []) {
array.push(value)
return array
}
console.log(append(1)) // [1]
console.log(append(2)) // [2], not [1, 2]
默认参数可用于后面的默认参数
已经遇到的参数可用于以后的默认参数:
function greet(name, greeting, message = greeting + ' ' + name) {
return [name, greeting, message]
}
console.log(greet('David', 'Hi')) // ['David', 'Hi', 'Hi David']
console.log(greet('David', 'Hi', 'Happy Birthday!')) // ['David', 'Hi', 'Happy Birthday!']