arguments使用
arguments 是一个对应于传递给函数的参数的类数组对象
function fn() {
console.log(arguments[0]) // aa
console.log(arguments[1]) // bb
console.log(arguments[2]) // cc
argumnets[2] = 'new value'
/**
* {
* 0: 'aa',
* 1: 'bb',
* 2: 'new value',
* length: 3 // 必须有length
* }
*/
console.log(argumnets)
// 转成正在的数组
var args = Array.prototype.slice.call(arguments)
var args2 = [].slice.call(arguments)
// ES5
var args3 = Array.from(arguments)
var args4 = [...arguments]
var args5 = Array.apply(null, arguments)
console.log(args) // ['aa', 'bb', 'cc']
console.log(args2) // ['aa', 'bb', 'cc']
console.log(args3) // ['aa', 'bb', 'cc']
console.log(args4) // ['aa', 'bb', 'cc']
console.log(args5) // ['aa', 'bb', 'cc']
}
fn('aa','bb','cc')
对参数的使用
function test (a) {
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)
注意
警告:对参数使用slice会阻止某些JavaScript引擎中的优化;如果你关心性能,尝试通过遍历arguments对象来构造一个新的数组。
试例
- 遍历参数求和
function add() {
var sum =0,
len = arguments.length;
for(var i=0; i<len; i++){
sum += arguments[i];
}
return sum;
}
add() // 0
add(1) // 1
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("; ", "elephant", "giraffe", "lion", "cheetah")) // "elephant; giraffe; lion; cheetah"
console.log(myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley")) // "sage. basil. oregano. pepper. parsley"
}
- 剩余参数、默认参数和解构赋值参数
- 严格模式下, delete运算符后跟随非法标识符(即delete 不存在的标识符),会抛出语法错误; 非严格模式下,会静默失败并返回false
- 严格模式中,对象中定义同名属性会抛出语法错误; 非严格模式不会报错
- 严格模式中,arguments对象是传入函数内实参列表的静态副本;非严格模式下,arguments对象里的元素和对应的实参是指向同一个值的引用
- 严格模式不允许八进制整数直接量(如:023)
- 严格模式中,函数形参存在同名的,抛出错误; 非严格模式不会
- 严格模式中 eval和arguments当做关键字,它们不能被赋值和用作变量声明
- 严格模式会限制对调用栈的检测能力,访问arguments.callee.caller会抛出异常
- 严格模式 变量必须先声明,直接给变量赋值,不会隐式创建全局变量,不能用with
- 严格模式中 call apply传入null undefined保持原样不被转换为window
- 判断是否为严格模式,在函数内部打印this;非严格模式:函数的调用上下文(this)是全局对象(Window);严格模式:调用上下文(this)是undefined
// 'use strict' // 整个 js 都是严格模式
// arguments对象可以与剩余参数、默认参数和解构赋值参数结合使用。
function foo(...args) {
// 'use strict' // 函数内是严格模式
return args
}
console.log(foo(1, 2, 3)) // [1,2,3]
// 当非严格模式中的函数没有包含剩余参数、默认参数和解构赋值,那么arguments对象中的值会跟踪参数的值
function func(a) {
arguments[0] = 99 // 更新了arguments[0] 同样更新了a
console.log('a', a)
}
func(10) // 99
function func2(a) {
a = 88 // 更新了a 同样更新了arguments[0]
console.log(arguments[0])
}
func2(10) // 88
// -------------------------------------------------------------------------------------------------------------
// 当非严格模式中的函数有包含剩余参数、默认参数和解构赋值,那么arguments对象中的值不会跟踪参数的值(函数的参数有默认值)
function func3(a = 55) {
arguments[0] = 99; // 更新 arguments[0] 不会同时更新 a
console.log(a);
}
func3(10); // 10
function func4(a = 55) {
a = 99; // 更新 a 不会同事更新 arguments[0]
console.log(arguments[0]);
}
func4(11); // 11
function func5(a = 55) {
console.log(arguments[0]);
}
func5(); // undefined
- 箭头函数
let slice = (arr) => Array.prototype.slice.call(arr);
var b ="12345678"
console.log(slice(b)) // [1,2,3,4,5,6,7,8]
- 定义创建HTML列表的方法
function list(type) {
var result = '<' + type + 'l><li>'
var args = Array.prototype.slice.call(arguments, 1)
result += args.join('</li><li>')
result += '</li></' + type + 'l>'
return result
}
var listHTML = list('u', 'One', 'Two', 'Three')
console.log(listHTML) // <ul><li>One</li><li>Two</li><li>Three</li></ul>
- callee
function foo(a, b) {
console.log(arguments.length) // 10 获取实参的个数
console.log(arguments.callee.length) // 2 获取形参的个数
}
foo(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
- caller
调用当前正在执行函数 的函数
caller 是一个函数被另一个函数调用生成的,指向的是 调用者 。
如果函数没有被其他函数调用,或该函数是又顶层调用,那么 caller 为 null。
arguments.caller 已被弃用所以用 arguments.callee
function c() {
if (arguments.callee.caller) {
console.log(arguments.callee.caller.toString()) // 函数 p 的文本
} else {
console.log('顶层调用')
}
}
console.log(c.caller) // null
c() // 顶层调用(arguments.callee.caller 的值 为null)
function p() {
c() // 函数 c 被函数 p 调用,这个时候的 arguments.callee.caller 的值 为函数 p 本身
}
p() // 函数 p 的文本
// ---------------------------------------------------
// 下方示例
function runCaller() {
// 因为是顶级调用,又没有其他函数调用它,所以值为 null
console.log('runCaller1:', runCaller.caller) // null
}
function runCaller2() {
// runCaller2 也是顶级调用,但是在 callerChild2 内部有函数 callerChild 并且执行了 callerChild
function callerChild() {
console.log(callerChild.caller) // 因为是在runCaller2内部调用了它的 所以在这里的 caller 就指向 runCaller2 整个函数
}
//
callerChild()
}
function runCaller3() {
callerChild()
}
function callerChild() {
console.log(callerChild.caller) // 指向调用它的父级函数 runCaller3
}
runCaller()
runCaller2()
runCaller3()
- 通过改变 arguments.length 改变实参个数
function foo() {
arguments.length = 2
for (let i = 0; i < arguments.length; i++) {
console.log(arguments[i])
}
}
foo(3) // 3, undefined
foo(1, 2, 3) // 1, 2