使用“var that = this”理解Javascript范围

IT技术 javascript
2021-02-05 13:59:11

假设我在一个对象中有以下属性方法:

  onReady: function FlashUpload_onReady()
  {
     Alfresco.util.Ajax.jsonGet({
       url: Alfresco.constants.PROXY_URI + "org/app/classification",
       successCallback: {
         fn: function (o) {
           var classButtonMenu = [],
               menuLabel, that = this;

           var selectButtonClick = function (p_sType, p_aArgs, p_oItem) {
               var sText = p_oItem.cfg.getProperty("text");
               that.classificationSelectButton.set("label", sText);
           };

           for (var i in o.json.items) {
             classButtonMenu.push({
               text: o.json.items[i].classification,
               value: o.json.items[i].filename,
               onClick: {fn: selectButtonClick}
             });
           }

           this.classificationSelectButton = new YAHOO.widget.Button({
             id: this.id + "-appClassification",
             type: "menu",
             label: classButtonMenu[0].text,
             name: "appClassification",
             menu: classButtonMenu,
             container: this.id + "-appClassificationSection-div"
           });
         },
         scope: this
       },
       failureMessage: "Failed to retrieve classifications!"
     });

我花了一些猜测才弄清楚在selectButtonClick我需要引用函数中that而不是this为了获得访问权限this.classificationSelectButton(否则会出现undefined),但我不确定为什么我不能使用this. 我最好的猜测是,new YAHOO.widget.Button一旦调用构造函数,整个对象中以某种方式被引用的任何属性都会失去作用域。

可能有人请解释为什么它是我必须参考classificationSelectButtonvar that = this而不只是调用`this.classificationSelectButton“?

6个回答

要理解的最重要的事情是函数对象没有固定this——值的this变化取决于函数的调用方式。我们说一个函数是用某个特定this调用的——该this值是在调用时确定的,而不是定义时。

  • 如果函数被称为“原始”函数(例如, just do someFunc()),this则将是全局对象(window在浏览器中)(或者undefined如果函数在严格模式下运行)。
  • 如果它作为对象的方法this被调用则将是调用对象。
  • 如果使用callor调用函数applythis则指定为callor的第一个参数apply
  • 如果它被称为事件侦听器(就像这里一样),this则将是作为事件目标的元素。
  • 如果它作为构造函数调用new,this将是一个新创建的对象,其原型设置为prototype构造函数属性。
  • 如果函数是bind操作的结果,则该函数将始终并且永远this设置为bind产生它调用的第一个参数(这是“函数没有固定的this”规则的唯一例外——由bind实际生成的函数确实有一个不可变的this。)

Usingvar that = this;是一种this在函数定义时存储值的方法(而不是函数执行时this什么时候可以是任何值,具体取决于函数的调用方式)。这里的解决方案是将 的外部值存储在包含在新定义函数范围内的this变量(传统上称为thator self)中,因为新定义函数可以访问在其外部范围内定义的变量。

这是对大多数开发人员回避的主题的非常优雅的解释,很棒的工作。
2021-03-20 13:59:11
很有用!我写了一个总结所有这些案例要点
2021-04-03 13:59:11
@apsillers 您是 /r/javascript 中本周最热门的链接。
2021-04-07 13:59:11

因为this它会根据运行的上下文更改其值。

在您的selectButtonClick函数内部,thethis将引用该函数的上下文,而不是外部上下文。所以你需要this在外部上下文中给出一个不同的名称,它可以被selectButtonClick函数内部引用

有词法作用域:在函数中声明的变量和传递给函数的参数仅在函数内部(以及在其内部函数中)可见。

var x = 1; // `1` is now known as `x`
var that = this; // the current meaning of `this` is captured in `that`

词法范围的规则非常直观。您显式分配变量。

然后是动态范围:this. 这是一件神奇的事情,它会根据您调用函数的方式来改变其含义。它也被称为context有几种方法可以为其指定含义。

考虑一个函数:

function print() { console.log(this); }

首先,默认上下文undefined处于严格模式,全局对象处于正常模式:

print(); // Window

其次,您可以将其设置为方法,并使用对对象的引用后跟一个点后跟对函数的引用来调用它:

var obj = {};
obj.printMethod = print;
obj.printMethod(); // Object

请注意,如果您调用不带点的方法,则上下文将回退到默认值:

var printMethod = obj.printMethod;
printMethod(); // Window

最后,有一种分配上下文的方法是使用call/applybind

print.call(obj, 1, 2); // Object
print.apply(obj, [ 1, 2 ]); // Object

var boundPrint = print.bind(obj);
boundPrint(); // Object

为了更好地理解上下文,您可能想尝试使用这些简单的示例。John Resig 有关于 JavaScript 上下文的非常好的交互式幻灯片,您可以在其中学习和测试自己。

将它存储在一个变量中可以让您在其他this可能引用其他内容的范围内访问它

请参阅https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/thishttp://www.quirksmode.org/js/this.htmlJavaScript 中变量的范围是什么?有关this 关键字的更多信息

this当从 DOM 事件调用类的方法时引用不起作用。例如,当对象的方法用作 onclick 的事件处理程序时,this指针指向事件发生的 DOM 节点。所以你必须this在对象中创建一个私有备份