call/apply的作用:在特定的作用域中调用函数,设置函数体内this对象的值,以扩充函数的作用域(调用函数的同时设置内部this指针的指向)
一般用法如下:
Func.call(context, arg1, arg2, arg3...)
Func.apply(context, [arg1,arg2,arg3])
Func.apply(context, arguments)
context、arg1、arguments等参数都是可选的
当call/apply中不传入参数时,即使用 Func.call() / Func.apply()时,context默认被指向全局对象(window),无参数传入
apply可以使用arguments,而arguments不是数组,是一个 类数组对象(类数组对象不一定可迭代,但可迭代一定是数组 or 类数组对象)
那么什么样的对象是类数组对象呢?
- 拥有length属性,其他属性(索引,非数字不考虑)为非负整数
- 不是数组
类数组判断(来自《javascript权威指南》):
function isArrayLike(o) {
if (o && // o is not null, undefined, etc.
typeof o === 'object' && // o is an object
isFinite(o.length) && // o.length is a finite number
o.length >= 0 && // o.length is non-negative
o.length === Math.floor(o.length) && // o.length is an integer
o.length < 4294967296) // o.length < 2^32
return true; // Then o is array-like
else
return false; // Otherwise it is not
}
(简单判断就是 0<=length<+∞ 的对象)
应用示例:
1. Array.apply(null, {length: 10})
VS
2. Array.apply(null, [10]) / Array.call(null, 10)
方法1生成的是一个每项都为undefined的数组
方法2生成的是一个每项都未初始化(empty)的数组
而ES中map、forEach、for in、reduce等遍历方法(for循环会遍历)不会去遍历未初始化的项(delete的项也会变成empty),这时方法2无法满足需求,就需要用到我们的类数组方式了
欢迎关注、点赞