'var that = this;'是什么?在JavaScript中意味着什么?


351

在一个JavaScript文件中,我看到了:

function Somefunction(){
   var that = this; 
   ... 
}

声明that并分配this给它的目的是什么?



6
箭头功能不需要“ this”和“ that” hack。使用箭头功能,“ this”将按预期工作。在这里看到更多的细节ES6在深度:箭头功能
satguru塔瓦


基于上下文的神秘这类行为的一个很好的解释这里
RBT

最新的和更新的解释可以在这里
Sukrit Gupta

Answers:


485

我将以一个插图开始这个答案:

var colours = ['red', 'green', 'blue'];
document.getElementById('element').addEventListener('click', function() {
    // this is a reference to the element clicked on

    var that = this;

    colours.forEach(function() {
        // this is undefined
        // that is a reference to the element clicked on
    });
});

我的回答最初是用jQuery演示的,只是略有不同:

$('#element').click(function(){
    // this is a reference to the element clicked on

    var that = this;

    $('.elements').each(function(){
        // this is a reference to the current element in the loop
        // that is still a reference to the element clicked on
    });
});

由于this在通过调用新函数更改范围时会经常更改,因此无法使用原始值访问原始值。将其别名为that可以使您仍然访问的原始值this

就个人而言,我不喜欢使用thatas作为别名。它所指的内容很少是明显的,特别是如果函数长于几行。我总是使用更具描述性的别名。在上面的示例中,我可能会使用clickedEl


149
我通常会和var self = this;。这个词that似乎暗示变量是任何东西this
大卫·默多克

13
@David是的,我认为有点误导。但是,如果像克罗克福德所说的那样,这是一个惯例,那走那条路是否明智?不过,我完全同意你的看法。
El Ronnoco

4
@艾尔·隆诺科(El Ronnoco),但“他有一头白发,胡乱的胡须,他的举止让我想到一个脾气暴躁的老人,他大吼大叫要孩子们离开草坪。” - blogging.compendiumblog.com/blog/software-for-humans/0/0/... ;-p
大卫默多克

7
@ElRonnoco:不过,这是对权威的呼吁。如果我们只按照“名人”的话做,那我们就要走向灾难。
Lightness Races in Orbit 2013年

3
forEach函数带有第二个可选参数,它是函数的绑定。colours.forEach(function(){/* 'this' is bound correctly --> */}, this);因此,一个音符应该说,var that = this是不是真正需要用forEach
马特·克拉克森

107

克罗福德

按照惯例,我们做一个私有的是 可变的。这用于使对象可用于私有方法。这是为在ECMAScript的语言规范的错误导致一种变通方法这个不正确地对内部函数来设定。

JS小提琴

function usesThis(name) {
    this.myName = name;

    function returnMe() {
        return this;        //scope is lost because of the inner function
    }

    return {
        returnMe : returnMe
    }
}

function usesThat(name) {
    var that = this;
    this.myName = name;

    function returnMe() {
        return that;            //scope is baked in with 'that' to the "class"
    }

    return {
        returnMe : returnMe
    }
}

var usesthat = new usesThat('Dave');
var usesthis = new usesThis('John');
alert("UsesThat thinks it's called " + usesthat.returnMe().myName + '\r\n' +
      "UsesThis thinks it's called " + usesthis.returnMe().myName);

这会提醒...

认为那叫戴夫(Dave)

用途这被认为是未定义的


2
谢谢,总结起来对我来说足够了。
克里斯,

3
我读过,不懂,因为它没有细节,在Google上搜索后找到了此页面。我再次指出同一句话。因此,投降票。
Aditya MP

3
这是一个公平的观点,我想说,一个不熟悉JavaScript的人将很难仅从我的回答中掌握这个概念。我的回答很简短(我确实链接到您用Google搜索过的页面。
El Ronnoco

16
我没有违法。很高兴看到有人在投票时发表评论!
El Ronnoco

4
克罗克福德答案的问题是that在他的例子中根本没有使用变量。它看起来好像只是创建一个变量保存this对其余的代码有作用​​。
r3m0t

86

这是使内部功能(在其他功能内定义的功能)更按需工作的一种技巧。在javascript中,当您在另一个函数中定义一个函数时,会this自动设置为全局范围。这可能会造成混淆,因为您期望this与外部函数具有相同的值。

var car = {};
car.starter = {};

car.start = function(){
    var that = this;

    // you can access car.starter inside this method with 'this'
    this.starter.active = false;

    var activateStarter = function(){
        // 'this' now points to the global scope
        // 'this.starter' is undefined, so we use 'that' instead.
        that.starter.active = true;

        // you could also use car.starter, but using 'that' gives
        // us more consistency and flexibility
    };

    activateStarter();

};

当您将函数创建为对象的方法(如car.start示例中),然后在该方法内部创建函数(如activateStarter)时,这特别是一个问题。在顶层方法this指向对象时,它是的方法(在这种情况下为car),但在内部函数中则this指向全局范围。真痛苦

创建一个变量以按惯例在两个范围内使用都是解决javascript这个非常普遍的问题的方法(尽管它在jquery函数中也很有用)。这就是为什么使用非常通用的名称的that原因。这是克服语言缺陷的一种容易识别的约定。

就像El Ronnoco在道格拉斯 ·克罗克福德(Douglas Crockford)暗示的那样,这是一个好主意。


8
我想这是比接受的答案更有用的答案。因为它阐明了Crockford发明了“ that”而有关jQuery的答案却没有的原因。
Konstantin Smolyanin

4
这实际上是一个比接受的答案更好的例子。它解释了道格拉斯所说的“ ECMAScript语言规范中的错误,导致对内部函数的错误设置”。
kakacii

1
您可能希望使其语法正确。我知道它更像是一个错字,但是它可能会使javascript初学者感到困惑,因为这个问题更像是初学者。我的意思是:var car = {}; car.starter = {}; car.start = function(){...}
kakacii13年

1
@kakacii谢谢。立即修复。
Waylon Flinn

9

使用的that是不是真的有必要,如果你与使用的解决办法call()apply()

var car = {};
car.starter = {};

car.start = function(){
    this.starter.active = false;

    var activateStarter = function(){
        // 'this' now points to our main object
        this.starter.active = true;
    };

    activateStarter.apply(this);
};

3

有时this可以引用另一个作用域并引用其他内容,例如,假设您要在DOM事件内调用构造函数方法,在这种情况下this将引用DOM元素而不是创建的对象。

的HTML

<button id="button">Alert Name</button>

JS

var Person = function(name) {
  this.name = name;
  var that = this;
  this.sayHi = function() {
    alert(that.name);
  };
};

var ahmad = new Person('Ahmad');
var element = document.getElementById('button');
element.addEventListener('click', ahmad.sayHi); // => Ahmad

演示版

上面会assing的解决方案thisthat,然后我们就可以和访问里面的name属性sayHi的方法that,所以这可以被称为无DOM调用中的问题。

另一个解决方案是分配一个空that对象并向其添加属性和方法,然后将其返回。但是使用此解决方案,您就失去prototype了构造函数的。

var Person = function(name) {
  var that = {};
  that.name = name;
  that.sayHi = function() {
    alert(that.name);
  };
  return that;
};

2

这是一个例子

$(document).ready(function() {
        var lastItem = null;
        $(".our-work-group > p > a").click(function(e) {
            e.preventDefault();

            var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
            if (item == lastItem) {
                lastItem = null;
                $('.our-work-single-page').show();
            } else {
                lastItem = item;
                $('.our-work-single-page').each(function() {
                    var imgAlt = $(this).find('img').attr('alt'); //Here value of "this" is '.our-work-single-page'. 
                    if (imgAlt != item) {
                        $(this).hide();
                    } else {
                        $(this).show();
                    }
                });
            }

        });
    });`

因此,您可以看到此值是两个不同的值,具体取决于您定位的DOM元素,但是当您在上面的代码中添加“ that”时,您更改的是“ this”的值。

`$(document).ready(function() {
        var lastItem = null;
        $(".our-work-group > p > a").click(function(e) {
            e.preventDefault();
            var item = $(this).html(); //Here value of "this" is ".our-work-group > p > a"
            if (item == lastItem) {
                lastItem = null;
                var that = this;
                $('.our-work-single-page').show();
            } else {
                lastItem = item;
                $('.our-work-single-page').each(function() {
                   ***$(that).css("background-color", "#ffe700");*** //Here value of "that" is ".our-work-group > p > a"....
                    var imgAlt = $(this).find('img').attr('alt'); 
                    if (imgAlt != item) {
                        $(this).hide();
                    } else {
                        $(this).show();
                    }
                });
            }

        });
    });`

..... $(that).css(“ background-color”,“#ffe700”); //这里“ that”的值是“ .our-work-group> p> a”,因为var that = this; 因此,即使我们位于“ this” ='.our-work-single-page',我们仍然可以使用“ that”来操作先前的DOM元素。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.