'Var that = this;' nghĩa là gì trong JavaScript?


351

Trong một tệp JavaScript tôi thấy:

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

Mục đích của việc khai báo thatvà gán thisnó cho nó là gì?


3
có thể trùng lặp var self = this?
Bergi

6
Không cần hack "cái này" và "cái đó" cho các chức năng mũi tên. Với chức năng mũi tên "này" hoạt động như mong đợi. Xem tại đây để biết thêm chi tiết ES6 In Depth: Hàm mũi tên
satguru srivastava

1
Ở đây khái niệm về điều này được giải thích scotch.io/@alZami/under Hiểu
-this-in-javascript

Một lời giải thích tuyệt vời về hành vi bí ẩn này dựa trên bối cảnh ở đây
RBT

Giải thích mới nhất và cập nhật có thể được tìm thấy ở đây
Sukrit Gupta

Câu trả lời:


486

Tôi sẽ bắt đầu câu trả lời này bằng một minh họa:

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

Câu trả lời của tôi ban đầu đã chứng minh điều này với jQuery, chỉ khác một chút:

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

thisthường xuyên thay đổi khi bạn thay đổi phạm vi bằng cách gọi một hàm mới, bạn không thể truy cập giá trị ban đầu bằng cách sử dụng nó. Bí danh thatcho phép bạn vẫn truy cập giá trị ban đầu của this.

Cá nhân, tôi không thích sử dụng thatnhư bí danh. Nó hiếm khi rõ ràng những gì nó được đề cập đến, đặc biệt là nếu các chức năng dài hơn một vài dòng. Tôi luôn luôn sử dụng một bí danh mô tả nhiều hơn. Trong các ví dụ của tôi ở trên, tôi có thể sử dụng clickedEl.


149
Tôi thường đi với var self = this;. Từ này thatdường như ngụ ý biến là bất cứ điều gì NHƯNG this.
David Murdoch

13
@David Có, tôi đã nghĩ rằng điều đó là sai lệch. Nhưng nếu, như Crockford nói, đó là một quy ước, liệu có khôn ngoan khi đi theo con đường đó. Tôi hoàn toàn đồng ý với bạn mặc dù, có ý nghĩa hơn nhiều.
El Ronnoco

4
@El Ronnoco, nhưng "Anh ta có mái tóc hoa râm và bộ râu lởm chởm và cách cư xử của anh ta khiến một ông già gắt gỏng la mắng bọn trẻ phải rời khỏi bãi cỏ." - blogging.compendiumblog.com/blog/software-for-humans/0/0/ trên ;-p
David Murdoch

7
@ElRonnoco: Tuy nhiên, đó là một sự hấp dẫn đối với chính quyền. Nếu chúng ta chỉ làm những gì "những người nổi tiếng" nói rằng chúng ta nên làm, thì chúng ta đang hướng đến thảm họa.
Các cuộc đua Lightness trong quỹ đạo

3
Các forEachchức năng phải mất một giây là đối số tùy chọn được các ràng buộc của hàm. colours.forEach(function(){/* 'this' is bound correctly --> */}, this);Vì vậy, một lưu ý nên được thêm vào mà var that = thiskhông thực sự cần thiết với forEach.
Matt Clarkson

107

Từ Crockford

Theo quy ước, chúng ta thực hiện một tin rằng biến. Điều này được sử dụng để làm cho đối tượng có sẵn cho các phương thức riêng tư. Đây là một cách giải quyết cho một lỗi trong Đặc tả ngôn ngữ ECMAScript khiến điều này được đặt không chính xác cho các chức năng bên trong.

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

Thông báo này ...

Sử dụng Điều đó nghĩ rằng nó được gọi là Dave

Sử dụng Điều này nghĩ rằng nó được gọi là không xác định


2
Cảm ơn, tổng hợp nó đủ tốt cho tôi.
Chris

3
Tôi đọc nó, không hiểu vì nó không có chi tiết, tìm kiếm trên Google, tìm thấy trang này. Nơi tôi lại chỉ vào cùng một câu. Do đó downvote.
MP Aditya

3
Đó là một điểm công bằng, tôi sẽ nói rằng ai đó không quen thuộc với JavaScript sẽ gặp khó khăn trong việc nắm bắt khái niệm từ câu trả lời của tôi. Tôi đã trả lời rất ngắn gọn (và tôi đã liên kết đến trang mà bạn đã tìm kiếm ..) Tôi nói câu trả lời của cô đơn là rõ ràng nhất, mặc dù tôi vẫn thích sử dụng nó trong JS đơn giản hơn là ví dụ về jQuery.
El Ronnoco

16
Tôi không có hành vi phạm tội. Thật tuyệt khi thấy ai đó bình luận khi hạ cấp!
El Ronnoco

4
Vấn đề với câu trả lời của Crockford là thatbiến không được sử dụng trong ví dụ của anh ấy. Nó làm cho nó trông giống như chỉ cần tạo một biến giữ giữ thismột cái gì đó cho phần còn lại của mã.
r3m0t

86

Đây là một hack để làm cho các chức năng bên trong (các chức năng được xác định bên trong các chức năng khác) hoạt động giống như chúng cần. Trong javascript khi bạn xác định một chức năng bên trong một chức năng khác thissẽ tự động được đặt thành phạm vi toàn cầu. Điều này có thể gây nhầm lẫn bởi vì bạn mong đợi thiscó cùng giá trị như trong hàm ngoài.

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

};

Đây là một vấn đề cụ thể khi bạn tạo một hàm như một phương thức của một đối tượng (như car.starttrong ví dụ) sau đó tạo một hàm bên trong phương thức đó (như activateStarter). Trong phương thức cấp cao nhất thistrỏ đến đối tượng, nó là một phương thức (trong trường hợp này car) , nhưng trong hàm bên trong thisbây giờ chỉ đến phạm vi toàn cục. Đây là một nỗi đau.

Tạo một biến để sử dụng theo quy ước trong cả hai phạm vi là một giải pháp cho vấn đề rất chung này với javascript (mặc dù nó cũng hữu ích trong các hàm jquery). Đây là lý do tại sao tên âm thanh rất chung thatđược sử dụng. Đó là một quy ước dễ nhận biết để khắc phục một thiếu sót trong ngôn ngữ.

Giống như gợi ý của El Ronnoco tại Douglas Crockford nghĩ rằng đây là một ý tưởng tốt.


8
Tôi cho rằng đây là câu trả lời hữu ích hơn câu trả lời được chấp nhận. Bởi vì nó làm rõ lý do tại sao Crockford đã phát minh ra "điều đó" trong khi câu trả lời về jQuery thì không.
Konstantin Smolyanin

4
Đây thực sự là một ví dụ tốt hơn sau đó câu trả lời được chấp nhận. Nó giải thích nó giống như một "lỗi trong Đặc tả ngôn ngữ ECMAScript khiến cho điều này được đặt không chính xác cho các chức năng bên trong", Douglas nói.
kakacii

1
Bạn có thể muốn làm cho nó đúng ngữ pháp mặc dù. Tôi biết nó giống như một lỗi đánh máy, nhưng nó có thể gây nhầm lẫn cho người mới bắt đầu sử dụng javascript vì câu hỏi này là người mới bắt đầu thích hơn. Ý tôi là nó phải là: var car = {}; car.starter = {}; car.start = function () {...}
kakacii

1
@kakacii Cảm ơn. Đã sửa bây giờ.
Waylon Flinn

9

Việc sử dụng thatkhông thực sự cần thiết nếu bạn thực hiện một cách giải quyết với việc sử dụng call()hoặc 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

Đôi khi thiscó thể tham chiếu đến một phạm vi khác và tham chiếu đến một cái gì đó khác, ví dụ giả sử bạn muốn gọi một phương thức xây dựng bên trong một sự kiện DOM, trong trường hợp thisnày sẽ đề cập đến phần tử DOM không phải là đối tượng được tạo.

HTML

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

Mã não

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

Bản giới thiệu

Giải pháp ở trên sẽ khẳng thisđịnh thatsau đó chúng ta có thể và truy cập thuộc tính name bên trong sayHiphương thức từ đó that, vì vậy điều này có thể được gọi mà không gặp vấn đề gì trong lệnh gọi DOM.

Một giải pháp khác là gán một thatđối tượng trống và thêm các thuộc tính và phương thức cho nó và sau đó trả về nó. Nhưng với giải pháp này, bạn đã mất các prototypenhà xây dựng.

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

2

Đây là một ví dụ `

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

        });
    });`

Vì vậy, bạn có thể thấy giá trị này là hai giá trị khác nhau tùy thuộc vào phần tử DOM mà bạn nhắm mục tiêu nhưng khi bạn thêm "cái đó" vào mã ở trên, bạn sẽ thay đổi giá trị của "cái này" mà bạn đang nhắm mục tiêu.

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

        });
    });`

..... $ (đó) .css ("màu nền", "# ffe700"); // Ở đây giá trị của "that" là ".our-work-group> p> a" vì giá trị của var that = this; vì vậy mặc dù chúng tôi đang ở "this" = '.our-work-single-page', chúng tôi vẫn có thể sử dụng "that" để thao tác với phần tử DOM trước đó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.