我怎么知道何时在JS中的函数上使用.bind()? [英] How do I know when to use .bind() on a function in JS?
问题描述
(我知道这个问题,但是答案并不能完全告诉我我需要知道的内容.)
(I'm aware of this question, but the answers don't quite tell me what I need to know.)
我遇到了需要使用 .bind()
以便将this
或本地/类变量传递给函数.但是,我仍然不太清楚何时需要它.
I've come across cases where I need to use .bind()
on a function in JavaScript in order to pass this
or local/class variables to a function. However, I still don't really know when it's needed.
确切地知道什么时候this
或局部/类变量何时将在函数中可用的标准是什么?您对此有何看法?
What is the criteria for knowing when this
or local/class variables will or will not be available in a function, exactly? How do you reason about this?
例如:
- 创建,包装或传递新的匿名
function() { }
时是什么? - 使用
class
成员函数,class
getter/setter函数或老式的prototype.function
成员函数"(作为类的函数)时? - 在全球范围内?
- 在
for
或forEach
循环中,还是在它们的任何变体中? - 在闭包中是外部函数还是内部函数?
- 在各种JS操作中,例如
Array.prototype.forEach.call()
或[].forEach.call()
? - 在各种JS库和脚本中,它们可能具有自己的事物自定义实现?
- When a new anonymous
function() { }
is created, wrapped, or passed around? - When using a
class
member function, aclass
getter/setter function, or an oldschoolprototype.function
"member function" (of a function acting as a class)? - In the global scope?
- In a
for
orforEach
loop, or any of their variants? - In a closure outer or inner function?
- In various JS operations like
Array.prototype.forEach.call()
or[].forEach.call()
? - In various JS libraries and scripts, which may have their own custom implementation of things?
我问的主要原因是要意识到潜在的陷阱,避免不得不依靠反复试验.
The main reason I ask is to be aware of potential pitfalls and to avoid having to rely on trial and error.
推荐答案
信用至 T.J. Crowder 和 Zapparatus 给出了答案,它们提供了有用的信息.这四个答案/文章也很有帮助: 1 3 4
Credit to T.J. Crowder and Zapparatus for their answers, which provided helpful info. Also helpful were these 4 answers/articles: 1 2 3 4
但是,这些要么不完全完整和/或very之以鼻.因此,我决定将我的所有发现以及代码示例组合成一个答案.
在确定this
或局部/类变量在函数中是否可用时,需要考虑多个因素:
There are several considerations to factor in when determining whether this
or local/class variables will be available in a function:
- 函数的包含范围
- 呼叫链的直接前辈
- 该函数是直接调用还是间接调用
注意:还存在严格模式(产生undefined
而不是window
对象)和箭头功能(不会从包含范围更改this
).
Note: there is also strict mode (which yields undefined
's rather than window
objects) and arrow functions (which do not change this
from the containing scope).
以下是明确的规则:
- 默认情况下,
this
是全局对象,在浏览器世界中为window
. - 在全局范围内的函数中,
this
仍为window
,不会更改. - 在
class
或函数类(new function() { }
)中的成员函数内部,函数类的原型(funcClass.prototype.func = function() { }
)中,在相邻成员函数使用this
调用的函数内部或内部映射到对象({ key: function() { } }
)或存储在数组([ function() { } ]
)中的函数,如果直接使用类/对象/数组作为调用链中的前身直接调用该函数 (class.func()
,this.func()
,obj.func()
或arr[0]()
),this
引用类/对象/数组实例. - 在任何闭包的内部函数(函数中的任何函数)内部,返回的函数内部,在以普通变量引用作为其调用链中前身的函数之前的函数内(无论其实际位于何处!)或在间接调用的函数(即传递给函数(例如
.forEach(function() { })
)或设置为处理事件的函数)内,this
还原为window
或调用者可能已将其绑定到(例如,事件可能会将其绑定到触发对象实例).- 但是...有一个例外...:如果在
class
的成员函数中(并且仅在class
,而不是函数类中),如果其中的函数丢失了this
上下文(例如,通过作为闭包的内部函数),它变为undefined
,而不是window
...
- By default,
this
is the global object, which in browser world iswindow
. - Inside a function in the global scope,
this
will still bewindow
, it does not change. - Inside a member function within a
class
or function-class (new function() { }
), inside a function-class's prototype (funcClass.prototype.func = function() { }
), inside a function called by a neighboring member function withthis
, or inside a function mapped in an object ({ key: function() { } }
) or stored in an array ([ function() { } ]
), if the function is called directly with the class/object/array as the immediate predecessor in the call chain (class.func()
,this.func()
,obj.func()
, orarr[0]()
),this
refers to the class/object/array instance. - Inside any closure's inner function (any function within a function), inside a returned function, inside a function called with a plain variable reference as its immediate predecessor in the call chain (regardless of where it actually lives!), or inside a function called indirectly (i.e. passed to a function (e.g.
.forEach(function() { })
) or set to handle an event),this
reverts back towindow
or to whatever the caller may have bound it to (e.g. events may bind it to the triggering object instance).- There is... however... one exception...: if inside a
class
's member function (and only aclass
, not a function-class), if a function within that loses itsthis
context (e.g. by being a closure's inner function), it becomesundefined
, rather thanwindow
...
这是 JSFiddle ,其中包含大量代码示例:
Here is a JSFiddle with a bunch of code examples:
outputBox = document.getElementById("outputBox"); function print(printMe = "") { outputBox.innerHTML += printMe; } function printLine(printMe = "") { outputBox.innerHTML += printMe + "<br/>"; } var someVar = "someVar"; function func(who) { printLine("Outer func (" + who + "): " + this); var self = this; (function() { printLine("Inner func (" + who + "): " + this); printLine("Inner func (" + who + ") self: " + self); })(); } func("global"); printLine(); func.call(someVar, "someVar"); printLine(); function funcTwo(who) { printLine("Outer funcTwo (" + who + "): " + this); var self = this; return function funcThree() { printLine("Inner funcThree (" + who + "): " + this); printLine("Inner funcThree (" + who + ") self: " + self); }; } funcTwo("global")(); printLine(); f = funcTwo("global f"); f(); printLine(); funcTwo.call(someVar, "someVar")(); printLine(); object = { func: function(who) { printLine("Object outer (" + who + "): " + this); var self = this; (function() { printLine("Object inner (" + who + "): " + this); printLine("Object inner (" + who + ") self: " + self); })(); } } object.func("good"); printLine(); bad = object.func; bad("bad"); printLine(); function funcClass(who) { printLine("funcClass (" + who + "): " + this); } funcClass.prototype.func = function() { printLine("funcClass.prototype.func: " + this); self = this; (function() { printLine("funcClass.func inner: " + this); printLine("funcClass.func inner self: " + self); })(); } fc = funcClass("bad"); printLine(); fc = new funcClass("good"); fc.func("good"); printLine(); class classClass { constructor() { printLine("classClass constructor: " + this); } func() { printLine("classClass.func: " + this); self = this; (function() { printLine("classClass.func inner: " + this); printLine("classClass.func inner self: " + self); })(); } funcTwo() { this.func(); } } cc = new classClass(); cc.func(); printLine(); printLine("Calling funcTwo:"); cc.funcTwo(); printLine(); [0].forEach(function(e) { printLine("[0].forEach: " + this); printLine("[0].forEach someVar: " + someVar); }); [0].forEach(function(e) { printLine("[0].forEach with [0]: " + this); }, [0]); printLine(); arr = [ function(who) { printLine("Array (" + who + "): " + this); }, 1, 10, 100 ]; arr[0]("good"); arrFunc = arr[0]; arrFunc("bad"); printLine(); var button = document.getElementById("button"); button.onclick = function() { printLine("button: " + this); } button.click(); button.onclick = func; button.click(); setTimeout(function() { printLine(); printLine("setTimeout: " + this); printLine("setTimeout someVar: " + someVar); }, 0); setTimeout(fc.func, 0); setTimeout(cc.func, 0);
<input id="button" type="button" value="button"/> <br/><br/> <div id="outputBox" />
结论:是的,这很简单.
Conclusion: So yeah that's pretty simple.
这篇关于我怎么知道何时在JS中的函数上使用.bind()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- There is... however... one exception...: if inside a
- 但是...有一个例外...:如果在