简体   繁体   English

为什么必须显式调用JavaScript的`function.call`?

[英]Why does JavaScript's `function.call` have to be called explicitly?

I have a string, " test " . 我有一个字符串" test " It's a really ugly string, so let's trim it. 这是一个非常丑陋的字符串,所以让我们对其进行修剪。

" test ".trim() returns "test" . " test ".trim()返回"test" Nice! 太好了!

Now let's try to do it with that string as an argument. 现在,让我们尝试使用该字符串作为参数。

String.prototype.trim.call(" test ") also returns "test" . String.prototype.trim.call(" test ")也返回"test" Nice again! 再次好!

Oh, that means I can use String.prototype.trim.call to map an array of ugly strings by their trimmed counterparts, right? 哦,这意味着我可以使用String.prototype.trim.call来按修剪后的对应字符串映射难看的字符串数组,对吗?

[" test "].map(String.prototype.trim.call) does not return ["test"] . [" test "].map(String.prototype.trim.call)不返回["test"]

It throws TypeError: undefined is not a function . 它引发TypeError: undefined is not a function

Why is this not allowed? 为什么不允许这样做?

All function call methods are the same function value: 所有函数call方法都具有相同的函数值:

> String.prototype.trim.call === Function.prototype.call
true

> String.prototype.trim.call === alert.call
true

The function to be called is passed to Function.prototype.call as its this value. 要调用的Function.prototype.call作为this值传递给Function.prototype.call The this value for a function call varies depending on how the call is made : 函数调用的this取决于调用方式

f();             // calls f with this === undefined
x.f();           // calls x.f with this === x
x['f']();        // same as previous
f.call(y);       // calls f with this === y
f.apply(y, []);  // same as previous

When referencing a function in all cases that aren't calls, there is no this value involved. 在所有调用情况下引用函数时, 涉及this值。

const f = x.f;   // no association with x is maintained
x();             // calls f with this === undefined

So, when you pass String.prototype.trim.call to Array#map , you're passing the function Function.prototype.call , with no relationship to String.prototype.trim . 因此,当您将String.prototype.trim.call传递给Array#map ,您传递的是函数Function.prototype.call ,而与String.prototype.trim没有任何关系。 Array#map then calls it with the thisArg given as the second argument ( undefined , since you only passed one argument). 然后, Array#map使用thisArg 作为第二个参数undefined ,因为您仅传递了一个参数)来调用它。 Function.prototype.call calls the this value it was given, as it does, and fails because it can't call undefined . Function.prototype.call确实会调用给定的this值,但失败了,因为它无法调用undefined

The code is fixable by passing the correct value of this as thisArg : 通过将this的正确值作为thisArg传递,可以thisArg

["  test "].map(String.prototype.trim.call, String.prototype.trim)

Pretty verbose, huh? 很冗长,是吗? You can abuse the fact that all methods from prototypes are equal to make it shorter ( Set being a built-in function with a short name): 您可能会滥用这样一个事实,即原型中的所有方法都等同于使它更短( Set是一个内置函数,简称):

["  test "].map(Set.call, ''.trim)

but even that's no shorter than the usual, readable way: 但即使如此,它也不会比通常的可读方式短:

["  test "].map(x => x.trim())

which has the bonus of not forwarding unexpected arguments . 它具有不转发意外参数的好处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM