What does 'var that = this;' mean in JavaScript?

前端 未结 6 924
后悔当初
后悔当初 2020-11-22 00:49

In a JavaScript file I saw:

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

What is the purpose of declaring that and

相关标签:
6条回答
  • 2020-11-22 01:00

    I'm going to begin this answer with an illustration:

    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
        });
    });
    

    My answer originally demonstrated this with jQuery, which is only very slightly different:

    $('#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
        });
    });
    

    Because this frequently changes when you change the scope by calling a new function, you can't access the original value by using it. Aliasing it to that allows you still to access the original value of this.

    Personally, I dislike the use of that as the alias. It is rarely obvious what it is referring to, especially if the functions are longer than a couple of lines. I always use a more descriptive alias. In my examples above, I'd probably use clickedEl.

    0 讨论(0)
  • 2020-11-22 01:02

    Sometimes this can refer to another scope and refer to something else, for example suppose you want to call a constructor method inside a DOM event, in this case this will refer to the DOM element not the created object.

    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
    

    Demo

    The solution above will assing this to that then we can and access the name property inside the sayHi method from that, so this can be called without issues inside the DOM call.

    Another solution is to assign an empty that object and add properties and methods to it and then return it. But with this solution you lost the prototype of the constructor.

    var Person = function(name) {
      var that = {};
      that.name = name;
      that.sayHi = function() {
        alert(that.name);
      };
      return that;
    };
    
    0 讨论(0)
  • 2020-11-22 01:03

    Here is an example `

    $(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();
                        }
                    });
                }
    
            });
        });`
    

    So you can see that value of this is two different values depending on the DOM element you target but when you add "that" to the code above you change the value of "this" you are targeting.

    `$(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"); //Here value of "that" is ".our-work-group > p > a" because the value of var that = this; so even though we are at "this"= '.our-work-single-page', still we can use "that" to manipulate previous DOM element.

    0 讨论(0)
  • 2020-11-22 01:11

    The use of that is not really necessary if you make a workaround with the use of call() or 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);
    };
    
    0 讨论(0)
  • 2020-11-22 01:17

    From Crockford

    By convention, we make a private that variable. This is used to make the object available to the private methods. This is a workaround for an error in the ECMAScript Language Specification which causes this to be set incorrectly for inner functions.

    JS Fiddle

    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);
    

    This alerts...

    UsesThat thinks it's called Dave

    UsesThis thinks it's called undefined

    0 讨论(0)
  • 2020-11-22 01:17

    This is a hack to make inner functions (functions defined inside other functions) work more like they should. In javascript when you define one function inside another this automatically gets set to the global scope. This can be confusing because you expect this to have the same value as in the outer function.

    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();
    
    };
    

    This is specifically a problem when you create a function as a method of an object (like car.start in the example) then create a function inside that method (like activateStarter). In the top level method this points to the object it is a method of (in this case, car) but in the inner function this now points to the global scope. This is a pain.

    Creating a variable to use by convention in both scopes is a solution for this very general problem with javascript (though it's useful in jquery functions, too). This is why the very general sounding name that is used. It's an easily recognizable convention for overcoming a shortcoming in the language.

    Like El Ronnoco hints at Douglas Crockford thinks this is a good idea.

    0 讨论(0)
提交回复
热议问题