【问题标题】:bind to this keyword in javascript在 javascript 中绑定到 this 关键字
【发布时间】:2016-05-05 15:53:43
【问题描述】:

我正在尝试理解 javascript 中的 this 关键字,我已经阅读了各种文章,但似乎我仍然有些困惑。

例如,让我们考虑以下代码:

/*
 * script.js
 */

var data = 'global data';

var myObj = {

  data: 'object data',

  scope: function() {
      console.log(this.data);
  }

};


myObj.scope();    // print "object data"

所以在这种情况下 scope() 函数的调用上下文是对象,而 this 绑定到对象本身。

现在让我们添加一些 html..

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>

<input type="button" value="clickme" id="button">

<script src="script.js"></script>

</body>
</html>

.. 和按钮上的点击事件监听器来触发 scope() 函数

document.getElementById("button").addEventListener('click', myObj.scope, false);

// click on the button => print "undefined"

在点击事件中 this 指的是没有 data 属性的按钮对象,所以它正确地打印 undefined。 现在我想在声明时使用绑定方法(而不是调用或应用)来解决这个问题。所以我写:

/*
 * script.js
 */

var data = 'global data';

var myObj = {

  data: 'object data',

  scope: function() {
      console.log(this.data);
  }.bind(this)

};

document.getElementById("button").addEventListener('click', myObj.scope, false);


myObj.scope();    // print "global data"

// click on the button => print "global data"

似乎我绑定到全局对象(窗口)而不是 myObj。为什么?第一个示例中 console.log(this.data) 行中使用的 this 关键字与 bind( this) 在最后一个例子中?不应该都引用myObj吗? 我确信我对这一点有些困惑,所以提前感谢您的任何解释:)

【问题讨论】:

  • 您需要将myObj.scope.bind(myObj) 传递给addEventListener。您不能在对象字面量内绑定函数。
  • 这是因为你传入 just 函数 myObj.scope 本身 - 想想如果你将它从 myObj 中取出并粘贴为一个函数本身;它如何知道您尝试访问的范围?您的数据是否需要以这种方式构建?相反,您应该有一个函数,该函数接受要引用的范围的参数
  • 我知道我可以使用这样的调用(或应用)来解决问题: document.getElementById("button").addEventListener('click', function() {myObj.scope.call(myObj )}, 错误的);只是想知道我是否可以在声明时(使用绑定)而不是在调用时修复它

标签: javascript this bind


【解决方案1】:

为什么?行中使用的 this 关键字有什么区别 第一个示例中的 console.log(this.data) 和 最后一个例子中的线绑定(这个)?不应两者都指 我的对象?我确定我对这一点有些困惑,所以谢谢 提前解释一下:)

在你最后的代码 sn-p 中:

var myObj = {

  data: 'object data',

  scope: function() {
      console.log(this.data);
  }bind(this)

};
  1. 首先,您在绑定之前缺少一个点,但我认为这只是错字
  2. bind(this),这里 this 并不指向 myObj 对象。 this 指向全局对象。为什么?因为代码运行的上下文是全局上下文(任何函数之外的代码)
  3. 如果你真的想将myObj.scope的上下文绑定到myObj,你仍然不能像下面这样,在运行时,你会遇到can't read property of undefined错误:

-

var myObj = {

  data: 'object data',

  scope: function() {
      console.log(this.data);
  }.bind(myObj)

};

为什么?因为上面的代码 sn-p 是一个 javascript 语句,当 javascript 引擎试图解释该语句时,myObj 还没有被初始化。它是在初始化期间,所以当函数bind(myObj),myObj 是未定义的。您需要使用 2 个语句来完成:

var myObj = {

  data: 'object data',

  scope: function() {
      console.log(this.data);
  }
};
myObj.scope = myObj.scope.bind(myObj)

【讨论】:

  • 作为旁注;我通常喜欢使用构造方法来构造对象,所以我会这样做: function MyObject() { this.scope = this.scope.bind(this); this.data = '对象数据'; } MyObject.prototype.scope = function() { console.log(this.data); }; var myObj = new MyObject();这样,我知道任何构造的实例都将具有该绑定函数,而无需每次使用 new 关键字构造对象时都绑定它。
【解决方案2】:

似乎不可能将函数直接绑定到对象内部想调用函数:

var myObj = {
  data: 'object data',
};

myObj.scope = function() {
  console.log(this.data);
}.bind(myObj);

你怎么看?

【讨论】:

  • 谢谢,正是我要找的东西
【解决方案3】:

这是解决方案,您需要将 eventHandler 绑定到您想要的上下文。看下面的例子就清楚了:

var data = 'global data';

var myObj = {
  data: 'object data',
  scope: function() {
      console.log(this.data);
  }
};

document.getElementById("button").addEventListener('click', myObj.scope.bind(myObj), false);

如果您不想打扰bind,请参阅 ES6 上使用胖箭头的示例(您今天可以使用它,只需阅读有关 Babeljs 的内容)。看例子:

var data = 'global data';

var myObj = {
  data: 'object data',
  scope: function() {
      console.log(this.data);
  }
};

document.getElementById("button").addEventListener('click', () => myObj.scope(), false);

要了解更多信息,请阅读文章 (https://john-dugan.com/this-in-javascript/),它通过 4 个简单的步骤解释了这一点

【讨论】:

  • 详细说明这个答案:当一个函数被调用时没有点语法(所以fn()而不是object.fn()),this的范围设置为null,这意味着它将默认为全局范围(在浏览器中,它始终为window)。您可以通过 bind()ing 函数来覆盖此行为,如本答案中所述。无论函数如何调用,this 都会引用您传递给bind() 的任何内容作为第一个参数。
  • 感谢您的回答。我会将此标记为已接受,但我仍然不明白为什么在第三个示例中 bind(this) 指的是窗口对象而不是 myObj。有什么线索吗?
  • 是的@KlemenSlavič 解释得很好!检查文章(要了解更多信息,请阅读文章 (john-dugan.com/this-in-javascript),通过 4 个简单的步骤解释这一点)
  • @revy 在第三个示例中,您绑定到this,在您的情况下为window。对象声明不会自动假定其词法范围,这是设计使然。您必须使用 .bind(myObj) 作为显式引用。
  • 是的,我明白了。谢谢!
猜你喜欢
  • 2016-05-16
  • 2019-02-01
  • 2011-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多