使用 JS .call() 方法的原因?
Posted
技术标签:
【中文标题】使用 JS .call() 方法的原因?【英文标题】:The reason to use JS .call() method? 【发布时间】:2012-02-18 14:02:21 【问题描述】:我对 JS 中有 call() 方法的原因很感兴趣。它似乎重复了调用this
的常用方法。
例如,我有一个带有 call() 的代码。
var obj =
objType: "Dog"
f = function(did_what, what)
alert(this.objType + " " + did_what + " " + what);
f.call(obj, "ate", "food");
输出是“狗吃了食物”。但同样的结果,我可以将函数分配给对象。
var obj =
objType: "Dog"
f = function(did_what, what)
alert(this.objType + " " + did_what + " " + what);
obj.a = f;
obj.a("ate", "food");
结果是一样的。但是这种方式更容易理解,使用起来更方便。为什么需要 call()?
【问题讨论】:
好吧,您不能在所有情况下都将函数分配给对象。例如。如果您创建一个接受回调的函数并且还允许传递上下文,您可以将回调分配给对象并直接调用它,但您会选择哪个名称?您可能会覆盖现有方法。call
提供了一种解决该问题的简单方法。
【参考方案1】:
call
用于控制将在调用的函数中使用的范围。您可能希望 this
关键字不是您分配函数的范围,在这些情况下,您可以使用 call
或 apply
以您自己的范围调用函数。
F.ex,它还允许您在范围之外调用实用程序方法,例如使用“私有”函数时:
var obj = (function()
var privateFn = function()
alert(this.id);
return
id: 123,
publicFn: function()
privateFn.call(this);
;
());
obj.publicFn();
在上面的例子中,privateFn
没有暴露在 obj
中,但它仍然可以像公共范围的一部分一样被构造(以同样的方式使用 this
)。
【讨论】:
但是控制范围是 bind 的作用,所以你可以改为 privateFn.bind(this)();那么调用是必要的还是只是看起来更好? @Curtis 在此示例中,您别无选择,请尝试将publicFn: function() ...
行替换为 publicFn: privateFn.bind(this)
。在您定义函数时,您返回的对象尚未创建,因此上下文将只是 window
,因为此时没有其他上下文。
publicFn: function() privateFn.bind(this)();好吧,您可以这样做,因此调用不需要存在于 javascript 中,因为您通常使用括号调用函数,并且永远不需要调用。
@Curtis bind
创建函数的新副本,而 call
不会。此外,fn.bind(this)('foo')
是 fn.call(this, 'foo')
的可读性较差的版本【参考方案2】:
您可能会在示例中使用第二种方式,但有时您想在另一个对象上使用一个对象的函数。一个例子是在类似数组的对象上使用Array
方法,比如NodeList
s
var el = document.getElementById("foo");
[].forEach.call(el.children, function(child, index)
//Iterate over an element's children, performing an action on each one
);
【讨论】:
【参考方案3】:这与first class function 的概念有关。基本上,像 Javascript 这样的语言允许您将函数视为自己的东西。函数可以存储在变量中或传递给其他函数。
call()
提供了一种执行不附加到任何其他对象的独立功能的方法。
【讨论】:
你能提供一个例子吗? (“一种执行独立功能的方法”)。没有call()
就不能调用函数吗?【参考方案4】:
2017 年更新
Function.prototype 的所有函数都有.call
方法。之所以使用.call()
,是为了指定变量“this
”所指的对象。
MDN 指定:
call()
方法调用具有给定 this 值的函数,并且 单独提供的参数。
考虑以下几点:
function x()
return this;
x()
在严格模式下x()
返回undefined
在非严格模式下它在浏览器上下文中返回全局对象Window
。
以.call()
为例,我们告诉它“this
”指的是什么:
function x()
return this;
var obj =
myName : 'Robert',
myLocation : 'Earth'
x.call(obj);
结果:myName: "Robert", myLocation: "Earth"
。在上面的例子中,我们将 obj
对象指定为函数 x()
内的 this
的值
它可以用来模拟OOP中的继承。
例子:
var Robert =
name: "Robert Rocha",
age: 12,
height: "5,1",
sex: "male",
describe: function()
return "This is me " + this.name + " " + this.age + " " + this.height + " " + this.sex;
;
假设上面是一个主对象(原型),你想在另一个对象中继承函数describe
:
var Richard =
name: "Richard Sash",
age: 25,
height: "6,4",
sex: "male",
Richard
对象没有描述功能,您只想简单地继承,可以说是该功能。你会这样做:
console.log( Robert.describe.call( Richard ) );
输出:This is me Richard Sash 25 6,4 male
【讨论】:
谢谢。你的答案很容易理解。 这个答案没有解释this
方法中是否有this
参数,例如:Robert.describe.call(this,Richard)
。 this
在这里的作用是什么?
@TomSawyer 在此示例中的 this
指的是当前对象,即调用对象。使用.call()
,您可以编写一个方法并在您选择的另一个对象中继承它,而无需再次编写它,同时遵循 DRY 原则。
拥有一个带有原型函数describe
的Person
对象不是更有意义,然后Robert/Richard可以基于这个对象(即var Robert = new Person(...);
)...我猜你上面提到罗伯特是一个主对象,所以我想我们会在需要将另一个对象的函数用于另一个对象的地方使用.call
?
很好的解释!谢谢!【参考方案5】:
读完后,我明白为什么了。
新 JavaScript 程序员的一个常见错误是从对象中提取方法,然后调用该函数并期望它使用原始对象作为其this
(例如,通过在基于回调的代码中使用该方法)。
但是,如果不特别小心,原始对象通常会丢失。从函数中创建一个绑定函数,使用原始对象,巧妙地解决了这个问题:
this.x = 9; // 'this' refers to global 'window' object here in a browser
const module =
x: 81,
getX: function() return this.x;
;
module.getX();
// returns 81
const retrieveX = module.getX;
retrieveX();
// returns 9; the function gets invoked at the global scope
// Create a new function with 'this' bound to module
// New programmers might confuse the
// global variable 'x' with module's property 'x'
const boundGetX = retrieveX.bind(module);
boundGetX();
// returns 81
来源是here
【讨论】:
以上是关于使用 JS .call() 方法的原因?的主要内容,如果未能解决你的问题,请参考以下文章