call()和apply()实际上是用来欺骗方法处理类似数组的对象的

What do call() and apply() actually do to fool methods into working on array-like objects

本文关键字:处理 数组 对象 方法 apply 实际上 call 欺骗      更新时间:2023-09-26

关于调用、应用和绑定之间的差异,有很多信息,但我很难找到关于调用和应用方法如何欺骗现有函数(通常接受数组)接受类似数组的对象的信息。

据我所知,对这种方法的完全引用是关于在哪里找到方法的指示。然后,call/apply方法将"this"参数更改为指向类似数组的对象。

我到处找JS源代码,但都没有找到。

在Math.max.apply(Math,arguments)中,如果我们可以重新调整函数的用途,期望数组在类似数组的对象上工作,部分原因是因为更新了"this"参数,那么只将Math作为上下文来给出有什么意义呢。

调用和应用的特殊之处在于,它欺骗方法处理类似数组的对象??

<script type="text/javascript">
function multiMax(multi){
    return multi  * Math.max.apply(Math,
        Array.prototype.slice.call(arguments,1));
}
assert(multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by  largest.)");
</script>

callapply不能欺骗函数。

相反,当您使用它们在类似数组的对象上调用数组方法时,这是有效的,因为数组方法是有意通用的。

函数是有意通用的;它不要求其CCD_ 3值是Array对象。因此它可以被转移其他类型的对象用作方法。

Math函数的情况下,由于它们根本不使用this值,因此可以使用任何您想要的值。

所有数组都是对象。唯一能阻止方法处理类似数组的对象的是显式检查该对象是否为数组。这根本不是通过可以处理类似数组的对象的方法来实现的。事实上,您甚至不需要使用callbind来实现这一点;您可以将该方法附加到一个类似数组的对象上,并像通常那样调用它(不过我可能不建议使用它)。

应用和调用不执行任何操作,也不愚弄任何操作来处理类似数组的元素。他们只是做(工作),因为他们公开了成员的索引。

数组方法通过索引访问成员;如果一个成员对于给定的数组方法是正确的类型,那么它将以与自己相同的方式对其进行操作。但是,如果成员不是可以由给定数组方法处理的类型,那么您自然会得到一个错误。

在早期版本的JavaScript中,您可以将感兴趣的对象作为参数传递给say Array对象的属性函数,而无需使用调用或应用方法。

如:Array.split( collection );

我认为其他答案描述得很好,但也许这段说明性的代码也可以为这个主题提供一些启示。这是一个关于普通推送及其人造邪恶双胞胎的故事:

// create plain object
var obj = {}
// give it ability to `push` by simple assignment from some poor one-time array instance
obj.PSH = [].push
// poor array will be lost in garbage: we should have used Array.prototype instead, but nevermind
console.log(obj)
// => Object {}
// (Chrome console does not show method, but we can see it in inspection or in for-in loop:)
for(var prop in obj) console.log(prop,':',obj[prop])
// => PSH : push() { [native code] }
// ah, 'native code', how enigmatic.
// let's use it
obj.PSH('zero')
obj.PSH('one')
console.log(obj)
// => Object {0: "zero", 1: "one", length: 2}
// now we see it created numbered properties and `length` property on our object 
// what happens if we alter that `length` and call PSH after?
obj.length = 10
obj.PSH('TEN')
console.log(obj)
// => Object {0: "zero", 1: "one", 10: "TEN", length: 11}
// ah, predictable
// now we know what that native code most probably does, so we can create evil twin
function prankpush (what) {
    var where = this.length || 0
    this[where] = what      // insert that to to the last index
    this.length = where + 2 // but lets make it more interesting
}
// this time we will call it, so we will not taint out obj with another method
prankpush.call(obj,'prank2')
prankpush.call(obj,'prank3')
console.log(obj)
// => Object {0: "zero", 1: "one", 10: "TEN", 11: "prank1", 13: "prank2", length: 15}
// no 12 and length is bigger, what an evil success!
// but we could have as well do one time method assignment, call (like we did with native push in the beginning) …
obj.prankpush = prankpush
obj.prankpush('prank4')
// … and this time cover our tracks so prankpush will not be present in for-in-loop
delete obj.prankpush
console.log(obj)
// => Object {0: "zero", 1: "one", 10: "TEN", 11: "prank2", 13: "prank3", 15: "prank4", 17: "prank4", length: 19}