为什么需要 JavaScript bind()?

Why is JavaScript bind() necessary?

提问人:Tom 提问时间:12/30/2016 更新时间:10/31/2023 访问量:10693

问:

示例 1 中的问题是“this”指的是全局名称而不是 myName 对象。

我理解使用 bind() 将 this 的值设置为特定对象,因此它解决了示例 1 中的问题,但为什么首先会出现这个问题?它只是 Javascript 的创建方式吗?

我也想知道为什么示例 3 解决了这个问题以及示例 2 和 3 之间的区别。

this.name = "John"

var myName = {
  name: "Tom",
  getName: function() {
    return this.name
  }
}

var storeMyName = myName.getName; // example 1
var storeMyName2 = myName.getName.bind(myName); // example 2
var storeMyName3 = myName.getName(); // example 3

console.log("example 1: " + storeMyName()); // doesn't work
console.log("example 2: " + storeMyName2()); // works
console.log("example 3: " + storeMyName3); // works

javascript 绑定

评论

3赞 Felix Kling 12/30/2016
“这就是 Javascript 的创建方式吗?”我想是的。的值是动态确定的,除非它是绑定函数或箭头函数。不确定您还想知道什么,期待了解工作原理this
0赞 Azad 12/30/2016
Javascript call() 和 apply() 与 bind() 的可能重复?
4赞 Felix Kling 12/30/2016
“我也想知道为什么示例 3 解决了这个问题”,并且包含函数,而包含调用 .大不同。我在调用函数的方式和 twitter.com/fkling42/status/736228742008176640 之间进行了比较。也许它以某种方式有所帮助。storeMyNamestoreMyName2storeMyName3myName.getName().bind
0赞 Dave Lunny 1/6/2017
medium.com/@dave_lunny/bind-for-dummies-5d1a750725b8#.liz1lnoo1
0赞 Greg 1/9/2017
这是一本很棒的读物。它为我清除了 JS 中的所有内容:rainsoft.io/gentle-explanation-of-this-in-javascriptthis

答:

6赞 mrid 12/30/2016 #1

Function.prototype.bind() 上的 mdn wed 文档

实例的方法创建一个新函数,该函数在调用时调用此函数,其关键字设置为提供的值,并在调用新函数时提供任何参数之前的给定参数序列。bind()Functionthis

因此,当您第一次执行时,它采用全局 ( )。var storeMyName = myName.getName;namethis.name = "John"

当您使用 function 时,它开始引用当前闭包(在本例中为 )中定义的名称,因此打印 .bind()myNameTom

第三次,由于该函数是立即调用的,因此其作用域位于其自己的本地对象内,因此在闭包中打印值。Tom

69赞 Felix Kling 12/30/2016 #2

为什么需要 JavaScript bind()?

的值由函数的调用方式决定。如果是调用该函数,则通常无需使用 ,因为您可以控制如何调用该函数,从而控制其值。this.bindthis

但是,调用函数的通常不是您。函数作为回调和事件处理程序传递给其他函数。它们由其他代码调用,您无法控制函数的调用方式,因此无法控制将引用的内容。this

如果您的函数需要设置为特定值,而您不是调用该函数的人,则需要将该函数设置为特定值。this.bindthis

换句话说:允许您在不立即调用函数的情况下设置 的值。.bindthis

以下是引用/调用函数的比较:

                    +-------------------+-------------------+
                    |                   |                   |
                    |      time of      |       time of     |
                    |function execution |    this binding   |
                    |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|  function object  |      future       |      future       |
|         f         |                   |                   |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|   function call   |       now         |        now        |
|        f()        |                   |                   |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|     f.call()      |       now         |        now        |
|     f.apply()     |                   |                   |
|                   |                   |                   |
+-------------------+-------------------+-------------------+
|                   |                   |                   |
|     f.bind()      |      future       |        now        |
|                   |                   |                   |
+-------------------+-------------------+-------------------+

我也想知道为什么示例 3 解决了这个问题以及示例 2 和 3 之间的区别。

示例 1/2 和 3 截然不同。 并包含函数,这些函数在将来调用,而包含当时调用的结果。storeMyNamestoreMyName2storeMyName3myName.getName()


延伸阅读材料:

评论

0赞 Tom 12/30/2016
非常感谢您的帮助和资源。我是javascript的新手,你让我的答案非常明显。所以 call()/apply() 与示例 3 相同,只是在 getName() 方法与对象分开时使用?
0赞 Felix Kling 12/30/2016
基本上是的。如果函数是对象的属性,则调用该函数 as 将隐式设置为 。它等价于 .myName.getName()thismyNamemyName.getName.call(myName)
1赞 Dhruv 12/30/2016 #3

Bind 是一种机制,通过该机制,您可以更改执行的上下文(此处的默认上下文是全局上下文)。

根据您的示例 -

var storeMyName = myName.getName;

从上面的一行是你正在全局上下文中执行函数,所以对于这个执行将是顶行(即全局一/“约翰”)。storeMyNamethis.name

var storeMyName2 = myName.getName.bind(myName);

对于上面的一行,您正在显式更改函数的执行上下文(通过说我不想将此函数作为全局函数执行,我想在对象的上下文中执行此函数,因此在这种情况下将是“Tom”)storeMyName2myNamethis.name

var storeMyName3 = myName.getName(); // example 3

对于上面的这一行,你只是在对象上下文上执行函数,更重要的是你没有执行,这就是为什么它的上下文不是全局的。myNamestoreMyName3

4赞 Vincent J 1/6/2017 #4

我喜欢一个类比,我从未在任何地方见过: 假设你有一个带有函数的 foo 对象。 当您将 bar 函数绑定到另一个变量(或将其作为函数参数传递,这在回调中更常见)时,您不是将函数与他的封闭对象绑定/传递,而只是“裸体”函数。 因此,使用“裸体”函数,表示全局对象。barthis

一个小演示

var foo = "global foo"; //foo set on the global object
var a = {foo : "object foo", bar : function(){return this.foo;}};
var bound = a.bar;
console.log(bound());//returns "global foo", not "object foo"

bound只需指向function(){return this.foo;}

评论

0赞 Yuta73 3/12/2022
终于有人解释了原因!点赞。