arguments、剩余参数和默认参数值

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!']
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端吕小布

您的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值