Câu hỏi Từ khóa "này" hoạt động như thế nào?


Tôi đã nhận thấy rằng dường như không có một lời giải thích rõ ràng về những gì this từ khóa là gì và nó được sử dụng như thế nào (và không chính xác) được sử dụng trong JavaScript trên trang web Stack Overflow.

Tôi đã chứng kiến ​​một số hành vi rất lạ với nó và đã không hiểu tại sao nó lại xảy ra.

Làm thế nào this làm việc và khi nào nó nên được sử dụng?


1073
2018-06-27 13:12


gốc


Tôi tìm thấy điều này khi tôi googled "này" quirksmode.org/js/this.html - Wai Wong
Một số câu hỏi liên quan hữu ích * Sự nhầm lẫn con trỏ "này" của jQuery / JavaScript * Trong Javascript, tại sao toán tử "này" không phù hợp? và viết đẹp ở đây * phạm vi / ngữ cảnh trong javascript - Paul Dixon
Peter Michaux ủng hộ việc sử dụng this  peter.michaux.ca/articles/javascript-widgets-without-this - Marcel Korpel
Tổng quan về MDN không phải là một nửa xấu ... developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/… - dat
Một lời giải thích thú vị về this từ khóa: rainsoft.io/gentle-explanation-of-this-in-javascript - Dmitri Pavlutin


Các câu trả lời:


Tôi khuyên bạn nên đọc Mike WestBài viết của Phạm vi trong JavaScript (gương) Đầu tiên. Nó là một giới thiệu tuyệt vời, thân thiện với các khái niệm về this và phạm vi chuỗi trong JavaScript.

Khi bạn bắt đầu quen với this, các quy tắc thực sự khá đơn giản. Các Tiêu chuẩn ECMAScript 5.1 định nghĩa this:

§11.1.1 Các this từ khóa

Các this từ khóa đánh giá đến giá trị của ThisBinding của ngữ cảnh thực thi hiện tại

ThisBinding là một cái gì đó mà trình thông dịch JavaScript duy trì khi nó đánh giá mã JavaScript, giống như một thanh ghi CPU đặc biệt chứa một tham chiếu đến một đối tượng. Trình thông dịch cập nhật ThisBinding bất cứ khi nào thiết lập một bối cảnh thực thi trong một trong ba trường hợp khác nhau:

1. bối cảnh thực thi toàn cầu ban đầu

Đây là trường hợp mã JavaScript được đánh giá ở cấp cao nhất, ví dụ: khi trực tiếp bên trong <script>:

<script>
  alert("I'm evaluated in the initial global execution context!");

  setTimeout(function () {
      alert("I'm NOT evaluated in the initial global execution context.");
  }, 1);
</script>

Khi đánh giá mã trong bối cảnh thực thi ban đầu toàn cục, ThisBinding được đặt thành đối tượng chung, window (§10.4.1.1).

Nhập mã eval

  • ... bằng cách gọi trực tiếp tới eval() ThisBinding được giữ nguyên; nó có cùng giá trị với ThisBinding của bối cảnh thực hiện cuộc gọi (§10.4.2 (2) (a)).

  • … Nếu không bằng một cuộc gọi trực tiếp đến eval()
    ThisBinding được đặt thành đối tượng chung như thể thực thi trong bối cảnh thực thi ban đầu toàn cục (§10.4.2 (1)).

§15.1.2.1.1 định nghĩa cuộc gọi trực tiếp tới eval() Là. Về cơ bản, eval(...) là một cuộc gọi trực tiếp trong khi một cái gì đó như (0, eval)(...) hoặc là var indirectEval = eval; indirectEval(...); là một cuộc gọi gián tiếp đến eval(). Xem câu trả lời của chuckj đến (1, eval) ('this') so với eval ('this') trong JavaScript? và Thông tin chi tiết về ECMA-262-5 của Dmitry Soshnikov. Chương 2. Chế độ nghiêm ngặt. khi bạn có thể sử dụng gián tiếp eval() gọi điện.

Nhập mã chức năng

Điều này xảy ra khi gọi một hàm. Nếu một hàm được gọi trên một đối tượng, chẳng hạn như trong obj.myMethod() hoặc tương đương obj["myMethod"](), sau đó ThisBinding được đặt thành đối tượng (obj trong ví dụ; §13.2.1). Trong hầu hết các trường hợp khác, ThisBinding được đặt thành đối tượng chung (§10.4.3).

Lý do để viết "trong hầu hết các trường hợp khác" là vì có 8 hàm dựng sẵn ECMAScript 5 cho phép ThisBinding được chỉ định trong danh sách đối số. Những chức năng đặc biệt này được gọi là thisArg mà sẽ trở thành ThisBinding khi gọi hàm (§10.4.3).

Các chức năng tích hợp đặc biệt này là:

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Array.prototype.every( callbackfn [ , thisArg ] )
  • Array.prototype.some( callbackfn [ , thisArg ] )
  • Array.prototype.forEach( callbackfn [ , thisArg ] )
  • Array.prototype.map( callbackfn [ , thisArg ] )
  • Array.prototype.filter( callbackfn [ , thisArg ] )

Trong trường hợp của Function.prototype các hàm, chúng được gọi trên một đối tượng hàm, nhưng thay vì thiết lập ThisBinding thành đối tượng hàm, ThisBinding được đặt thành thisArg.

Trong trường hợp của Array.prototype chức năng, callbackfn được gọi trong ngữ cảnh thực thi nơi mà ThisBinding được đặt thành thisArg nếu được cung cấp; nếu không, với đối tượng toàn cầu.

Đó là những quy tắc cho JavaScript đơn giản. Khi bạn bắt đầu sử dụng các thư viện JavaScript (ví dụ: jQuery), bạn có thể thấy rằng một số hàm thư viện nhất định thao tác giá trị của this. Các nhà phát triển của các thư viện JavaScript làm điều này vì nó có xu hướng hỗ trợ các trường hợp sử dụng phổ biến nhất và người dùng thư viện thường thấy hành vi này thuận tiện hơn. Khi chuyển các hàm gọi lại tham chiếu this với các chức năng thư viện, bạn nên tham khảo tài liệu về bất kỳ đảm bảo nào về giá trị của this là khi hàm được gọi.

Nếu bạn đang tự hỏi làm thế nào một thư viện JavaScript thao túng giá trị của this, thư viện chỉ đơn giản là sử dụng một trong các hàm JavaScript tích hợp chấp nhận thisArg. Bạn cũng có thể viết chức năng của riêng bạn bằng chức năng gọi lại và thisArg:

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

Có một trường hợp đặc biệt mà tôi chưa đề cập đến. Khi xây dựng một đối tượng mới thông qua new toán tử JavaScript, trình thông dịch JavaScript tạo một đối tượng rỗng, mới, đặt một số thuộc tính bên trong, và sau đó gọi hàm khởi tạo trên đối tượng mới. Do đó, khi một hàm được gọi trong ngữ cảnh của hàm tạo, giá trị của this là đối tượng mới mà trình thông dịch đã tạo:

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

Chỉ để cho vui, kiểm tra sự hiểu biết của bạn với một số ví dụ

Để hiển thị câu trả lời, di chuột qua các ô màu vàng nhạt.

  1. Giá trị của this tại dòng được đánh dấu? Tại sao?

      window - Dòng được đánh dấu được đánh giá trong ngữ cảnh thực thi ban đầu.

    if (true) {
        // What is `this` here?
    }
    
  2. Giá trị của this tại dòng được đánh dấu khi obj.staticFunction() được thực hiện? Tại sao?

      obj - Khi gọi một hàm trên một đối tượng, ThisBinding được đặt thành đối tượng.

    var obj = {
        someData: "a string"
    };
    
    function myFun() {
        return this // What is `this` here?
    }
    
    obj.staticFunction = myFun;
    
    console.log("this is window:", obj.staticFunction() == window);
    console.log("this is obj:", obj.staticFunction() == obj);
      

  3. Giá trị của this tại dòng được đánh dấu? Tại sao?

      window

    Trong ví dụ này, trình thông dịch JavaScript nhập mã chức năng, nhưng vì myFun/obj.myMethod không được gọi trên một đối tượng, ThisBinding được đặt thành window.  

    Điều này khác với Python, trong đó truy cập một phương thức (obj.myMethod) tạo ra đối tượng phương thức liên kết.

    var obj = {
        myMethod: function () {
            return this; // What is `this` here?
        }
    };
    var myFun = obj.myMethod;
    console.log("this is window:", myFun() == window);
    console.log("this is obj:", myFun() == obj);
      

  4. Giá trị của this tại dòng được đánh dấu? Tại sao?

      window

    Điều này là khó khăn. Khi đánh giá mã eval, this Là obj. Tuy nhiên, trong mã eval, myFun không được gọi trên một đối tượng, do đó, ThisBinding được đặt thành window cho cuộc gọi.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
    
  5. Giá trị của this tại dòng được đánh dấu? Tại sao?

      obj

    Dòng myFun.call(obj); đang gọi hàm dựng sẵn đặc biệt Function.prototype.call(), chấp nhận thisArg làm đối số đầu tiên.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        someData: "a string"
    };
    console.log("this is window:", myFun.call(obj) == window);
    console.log("this is obj:", myFun.call(obj) == obj);
      


1151
2017-07-07 17:32



những dấu hiệu này có ý nghĩa gì? §10.4.1.1 - Ali
@Ali: Chúng là các tham chiếu đến các phần trong phiên bản 5.1 của Tiêu chuẩn ECMAScript, ECMA-262. Tôi cung cấp cho họ để bạn có thể đọc các tiêu chuẩn cho các chi tiết kỹ thuật nếu bạn muốn. - Daniel Trebbien
Tôi nghĩ @supertonsky là đúng về # 2 - nếu myFun () được gọi từ phạm vi toàn cầu, và không phải là một phương pháp trên đối tượng, "điều này" sẽ là đối tượng toàn cầu, do đó, các phrasing của câu hỏi quan trọng. btw - tôi có thật không như ý tưởng sử dụng di chuột để nhận câu trả lời cho một cái gì đó như thế này. - user655489
Nhưng, jsfiddle.net/H4LYm/2 cho thấy rằng setTimeout ví dụ có một this của window(global). - Kevin Meredith
Xin chào @KevinMeredith. Thật. Vì vậy, để tìm ra những gì this nằm trong hàm thời gian chờ, nó không phải là quy tắc "ngữ cảnh thực thi ban đầu toàn cầu" được áp dụng, mà là quy tắc "nhập mã chức năng". Vì hàm thời gian chờ không được gọi trên một đối tượng (ví dụ: someObject.someMethod()), this Là window trong hàm timeout, như JSFiddle hiển thị. - Daniel Trebbien


Các this từ khóa hoạt động khác với JavaScript so với ngôn ngữ khác. Trong các ngôn ngữ hướng đối tượng, this từ khóa đề cập đến trường hợp hiện tại của lớp. Trong JavaScript giá trị của this được xác định chủ yếu bởi ngữ cảnh yêu cầu của hàm (context.function()) và nơi nó được gọi.

1. Khi được sử dụng trong ngữ cảnh chung

Khi bạn sử dụng this trong bối cảnh toàn cục, nó bị ràng buộc với đối tượng toàn cục (windowtrong trình duyệt)

document.write(this);  //[object Window]

Khi bạn sử dụng this bên trong một hàm được định nghĩa trong ngữ cảnh chung, this vẫn còn bị ràng buộc với đối tượng toàn cầu vì hàm này thực sự được tạo thành một phương thức ngữ cảnh chung.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

Ở trên f1 được tạo thành một phương thức của đối tượng toàn cầu. Vì vậy, chúng tôi cũng có thể gọi nó trên window đối tượng như sau:

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. Khi sử dụng phương thức đối tượng bên trong

Khi bạn sử dụng this từ khóa bên trong một phương thức đối tượng, this được gắn với đối tượng kèm theo "ngay lập tức".

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

Ở trên tôi đã đặt từ ngay lập tức trong dấu ngoặc kép. Nó là để làm cho điểm rằng nếu bạn làm tổ đối tượng bên trong một đối tượng, sau đó this bị ràng buộc với cha mẹ ngay lập tức.

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

Ngay cả khi bạn thêm hàm một cách rõ ràng vào đối tượng dưới dạng một phương thức, nó vẫn tuân theo các quy tắc trên, đó là this vẫn trỏ đến đối tượng cha mẹ ngay lập tức.

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3. Khi gọi hàm context-less

Khi bạn sử dụng this Hàm bên trong được gọi mà không có bất kỳ ngữ cảnh nào (tức là không phải trên bất kỳ đối tượng nào), nó được ràng buộc với đối tượng chung (window trong trình duyệt) (ngay cả khi hàm được xác định bên trong đối tượng).

var context = "global";

var obj = {  
    context: "object",
    method: function () {                  
        function f() {
            var context = "function";
            return this + ":" +this.context; 
        };
        return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

Đang thử tất cả với chức năng

Chúng ta cũng có thể thử các điểm trên với các hàm. Tuy nhiên có một số khác biệt.

  • Ở trên, chúng tôi đã thêm các thành viên vào các đối tượng sử dụng ký hiệu chữ của đối tượng. Chúng ta có thể thêm các thành viên vào các hàm bằng cách sử dụng this. để chỉ định chúng.
  • Ký hiệu chữ của đối tượng tạo ra một thể hiện của đối tượng mà chúng ta có thể sử dụng ngay lập tức. Với hàm chúng ta có thể cần phải tạo ra thể hiện của nó bằng cách sử dụng new nhà điều hành.
  • Cũng trong một cách tiếp cận đối tượng theo nghĩa đen, chúng ta có thể thêm một cách rõ ràng các thành viên vào đối tượng đã được định nghĩa bằng cách sử dụng toán tử dấu chấm. Điều này chỉ được thêm vào trường hợp cụ thể. Tuy nhiên tôi đã thêm biến vào nguyên mẫu hàm sao cho nó được phản ánh trong mọi trường hợp của hàm.

Dưới đây tôi đã thử tất cả những thứ chúng tôi đã làm với Object và this ở trên, nhưng bằng cách tạo hàm đầu tiên thay vì viết trực tiếp một đối tượng.

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. `this` keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then `this` inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object's prototype chain, `this` refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4. Khi được sử dụng bên trong hàm xây dựng.

Khi hàm được sử dụng như một hàm tạo (đó là khi hàm được gọi với new từ khóa), this bên trong các điểm cơ quan chức năng cho đối tượng mới đang được xây dựng.

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5. Khi được sử dụng bên trong hàm được xác định trên chuỗi nguyên mẫu

Nếu phương thức nằm trên chuỗi nguyên mẫu của đối tượng, this bên trong phương thức đó đề cập đến đối tượng mà phương thức được gọi, như thể phương thức được định nghĩa trên đối tượng.

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6. Hàm gọi bên trong (), apply () và bind ()

  • Tất cả các phương pháp này được xác định trên Function.prototype.
  • Các phương thức này cho phép viết một hàm một lần và gọi nó trong ngữ cảnh khác nhau. Nói cách khác, chúng cho phép xác định giá trị của this sẽ được sử dụng trong khi chức năng đang được thực hiện. Chúng cũng lấy bất kỳ tham số nào được truyền cho hàm ban đầu khi nó được gọi.
  • fun.apply(obj1 [, argsArray]) Bộ obj1 như giá trị của this phía trong fun() và cuộc gọi fun() đi qua các yếu tố của argsArray làm đối số của nó.
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Bộ obj1 như giá trị của this phía trong fun() và cuộc gọi fun() đi qua arg1, arg2, arg3, ... làm đối số của nó.
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]]) - Trả về tham chiếu đến hàm fun với thisvui vẻ bên trong obj1 và các thông số của fun ràng buộc với các tham số được chỉ định arg1, arg2, arg3,....
  • Bởi bây giờ sự khác biệt giữa apply, call và bind phải trở nên rõ ràng. apply cho phép chỉ định các đối số để hoạt động như đối tượng giống như mảng, tức là một đối tượng có một số length thuộc tính và các thuộc tính số nguyên không âm. Trong khi call cho phép chỉ định các đối số cho hàm trực tiếp. Cả hai apply và call ngay lập tức gọi hàm trong ngữ cảnh được chỉ định và với các đối số được chỉ định. Mặt khác, bind đơn giản trả về hàm bị ràng buộc với this giá trị và các đối số. Chúng ta có thể nắm bắt tham chiếu đến hàm trả về này bằng cách gán nó cho một biến và sau đó chúng ta có thể gọi nó bất cứ lúc nào.
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7. this bên trong xử lý sự kiện

  • Khi bạn gán hàm trực tiếp cho trình xử lý sự kiện của một phần tử, sử dụng this trực tiếp bên trong hàm xử lý sự kiện đề cập đến phần tử tương ứng. Việc gán chức năng trực tiếp như vậy có thể được thực hiện bằng cách sử dụng addeventListener hoặc thông qua các phương thức đăng ký sự kiện truyền thống như onclick.
  • Tương tự, khi bạn sử dụng this trực tiếp bên trong thuộc tính sự kiện (như <button onclick="...this..." >) của phần tử, nó đề cập đến phần tử.
  • Tuy nhiên, sử dụng this gián tiếp thông qua hàm khác được gọi bên trong hàm xử lý sự kiện hoặc thuộc tính sự kiện phân giải thành đối tượng chung window.
  • Cùng một hành vi trên đạt được khi chúng ta đính kèm hàm vào trình xử lý sự kiện bằng cách sử dụng phương thức mô hình đăng ký sự kiện của Microsoft attachEvent. Thay vì gán hàm cho trình xử lý sự kiện (và do đó tạo ra phương thức hàm của phần tử), nó gọi hàm đó trên sự kiện (gọi hiệu quả nó trong ngữ cảnh chung).

Tôi khuyên bạn nên thử điều này tốt hơn JSFiddle.

<script> 
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    } 
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);   
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>

122
2017-10-26 15:07



"Khi bạn sử dụng hàm này bên trong một hàm được định nghĩa trong ngữ cảnh chung, thì điều này vẫn bị ràng buộc với đối tượng toàn cục vì hàm này thực sự đã tạo ra một phương thức ngữ cảnh chung." không đúng. điều này được đặt theo cách hàm được gọi hoặc theo trói buộc, không phải bởi nơi nó được xác định. Việc gọi bất kỳ hàm nào không có tham chiếu cơ sở ("ngữ cảnh") sẽ mặc định điều này đối tượng toàn cầu hoặc vẫn không được xác định trong chế độ nghiêm ngặt. - RobG
@RobG hmm có thể, nhưng tôi tìm thấy điều này trên MDN: Trong trường hợp này, giá trị của this không được đặt bởi cuộc gọi. Vì mã không ở chế độ nghiêm ngặt, giá trị của this phải luôn là một đối tượng để nó mặc định đối tượng chung. Và trong thực tế, đó là lý do tại sao tôi nghĩ rằng chúng tôi có thể trực tiếp thực hiện cuộc gọi window.f1(), vậy điều đó có nghĩa là f1() đã được đính kèm với window đối tượng, ý tôi là trước khi gọi. Tôi có hiểu sai không? - Mahesha999
Tôi đã bình luận (có lẽ không rõ ràng) về việc liên kết các thiết lập của điều này với "hàm thực sự được tạo thành một phương thức của ngữ cảnh chung", như thể nó được gọi là window.fn, nó không phải. điều này mặc định là đối tượng chung vì không có tham chiếu cơ sở nào được sử dụng trong cuộc gọi, không phải vì hàm được định nghĩa (do đó điều này vẫn được đặt theo cách hàm được gọi). Nếu bạn gọi nó một cách rõ ràng window.fn, sau đó bạn đang thiết lập điều này đến cửa sổ. Cùng một kết quả, cách khác nhau để đi về nó. :-) - RobG
"ở trên tôi đã đặt từ ngay lập tức ..." không có bạn đã không. Bạn có thể sửa đổi điều này để lỗi được sửa không? Có vẻ như ngữ nghĩa đối với câu trả lời và do đó tôi không thể tiếp tục đọc cho đến khi lỗi được sửa chữa vì sợ học cái gì đó không chính xác. - TylerH
@TylerH làm Ctrl + F trên trang này trong trình duyệt của bạn để tìm chuỗi "ngay lập tức" (bao gồm cả dấu ngoặc kép) Tôi nghĩ rằng nó ở đó nếu tôi hiểu sai - Mahesha999


Javascript this

Lời gọi hàm đơn giản

Xem xét chức năng sau:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function

Lưu ý rằng chúng tôi đang chạy điều này ở chế độ bình thường, tức là chế độ nghiêm ngặt không được sử dụng.

Khi chạy trong trình duyệt, giá trị của this sẽ được ghi lại là window. Điều này là bởi vì window là biến toàn cục trong phạm vi của trình duyệt web.

Nếu bạn chạy cùng một đoạn mã này trong môi trường như node.js, this sẽ đề cập đến biến toàn cầu trong ứng dụng của bạn.

Bây giờ nếu chúng ta chạy nó ở chế độ nghiêm ngặt bằng cách thêm câu lệnh "use strict"; vào đầu khai báo hàm, this sẽ không còn tham chiếu đến biến toàn cầu trong một trong các envirnoments. Điều này được thực hiện để tránh nhầm lẫn trong chế độ nghiêm ngặt. this trong trường hợp này, chỉ cần đăng nhập undefined, bởi vì đó là những gì nó được, nó không được xác định.

Trong các trường hợp sau, chúng ta sẽ xem cách thao tác giá trị của this.

Gọi một hàm trên một đối tượng

Có nhiều cách khác nhau để làm điều này. Nếu bạn đã gọi các phương thức gốc trong Javascript như forEach và slice, bạn nên biết rằng this biến trong trường hợp đó đề cập đến Object mà bạn gọi hàm đó (Lưu ý rằng trong javascript, mọi thứ đều là Object, kể cả Arraycát FunctionS). Lấy ví dụ sau.

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged

Nếu một Object chứa thuộc tính chứa Function, thuộc tính được gọi là phương thức. Phương pháp này, khi được gọi, sẽ luôn có nó this biến được đặt thành Object nó được liên kết với. Điều này đúng cho cả hai chế độ nghiêm ngặt và không nghiêm ngặt.

Lưu ý rằng nếu một phương thức được lưu trữ (hoặc đúng hơn, được sao chép) trong một biến khác, tham chiếu đến this không còn được giữ nguyên trong biến mới nữa. Ví dụ:

// continuing with the previous code snippet

var myVar = myObj.thisMethod;
myVar();
// logs either of window/global/undefined based on mode of operation

Xem xét một kịch bản phổ biến hơn:

var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself

Các new từ khóa

Xem xét hàm xây dựng trong Javascript:

function Person (name) {
    this.name = name;
    this.sayHello = function () {
        console.log ("Hello", this);
    }
}

var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`

Cái này hoạt động ra sao? Vâng, hãy xem điều gì sẽ xảy ra khi chúng ta sử dụng new từ khóa.

  1. Gọi hàm bằng new từ khóa sẽ ngay lập tức khởi tạo Object loại Person.
  2. Nhà xây dựng này Object có hàm tạo của nó được đặt thành Person. Ngoài ra, lưu ý rằng typeof awal sẽ trở lại Object chỉ có.
  3. Điều này mới Object sẽ được chỉ định Person.prototype. Điều này có nghĩa là bất kỳ phương pháp hoặc thuộc tính nào trong Person nguyên mẫu sẽ có sẵn cho tất cả các phiên bản Person, kể cả awal.
  4. Chức năng Person chính nó bây giờ được gọi; this là một tham chiếu đến đối tượng mới được xây dựng awal.

Khá thẳng thắn, eh?

Lưu ý rằng thông số ECMAScript chính thức không có trạng thái mà các loại chức năng như vậy thực tế constructor chức năng. Chúng chỉ là những chức năng bình thường, và new có thể được sử dụng trên bất kỳ chức năng nào. Chỉ là chúng tôi sử dụng chúng như vậy, và vì vậy chúng tôi gọi chúng như vậy.

Chức năng gọi trên Chức năng: call và apply

Vâng, vì functioncũng là Objects (và các biến lớp học đầu tiên trong thực tế trong Javascript), thậm chí các hàm cũng có các phương thức được ... tốt, các hàm được định nghĩa.

Tất cả các hàm được kế thừa từ toàn cầu Functionvà hai trong số nhiều phương pháp của nó là call và applyvà cả hai có thể được sử dụng để điều khiển giá trị của this trong hàm mà chúng được gọi.

function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);

Đây là một ví dụ điển hình của việc sử dụng call. Về cơ bản nó lấy tham số và bộ đầu tiên this trong hàm foo như một tham chiếu đến thisArg. Tất cả các thông số khác được chuyển đến call được chuyển đến hàm foo làm đối số.
Vì vậy, các mã trên sẽ đăng nhập {myObj: "is cool"}, [1, 2, 3] trong bảng điều khiển. Cách khá hay để thay đổi giá trị của this trong bất kỳ chức năng nào.

apply gần giống như call chấp nhận rằng nó chỉ mất hai tham số: thisArg và một mảng chứa các đối số được truyền cho hàm. Vì vậy, ở trên call cuộc gọi có thể được dịch sang apply như thế này:

foo.apply(thisArg, [1,2,3])

Lưu ý rằng call và apply có thể ghi đè giá trị của this được đặt theo lời gọi phương thức chấm mà chúng tôi đã thảo luận trong dấu đầu dòng thứ hai. Đủ đơn giản :)

Đang trình bày .... bind!

bind là anh trai của call và apply. Nó cũng là một phương thức được thừa hưởng bởi tất cả các hàm từ toàn cầu Function hàm tạo trong Javascript. Sự khác biệt giữa bind và call/apply là cả hai call và apply sẽ thực sự gọi hàm. bind, mặt khác, trả về một hàm mới với thisArg và arguments được đặt trước. Hãy lấy một ví dụ để hiểu rõ hơn về điều này:

function foo (a, b) {
    console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */

bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`

Xem sự khác biệt giữa ba? Nó là tinh tế, nhưng chúng được sử dụng khác nhau. Như call và apply, bind cũng sẽ vượt quá giá trị của this được đặt theo lời gọi phương thức chấm.

Cũng lưu ý rằng cả ba hàm này đều không thực hiện bất kỳ thay đổi nào đối với hàm ban đầu. call và apply sẽ trả về giá trị từ các hàm mới được xây dựng trong khi bind sẽ trả về hàm mới được xây dựng, sẵn sàng để được gọi.

Công cụ bổ sung, sao chép nội dung này

Đôi khi, bạn không thích thực tế là this thay đổi với phạm vi, phạm vi lồng nhau đặc biệt. Hãy xem ví dụ sau.

var myObj = {
    hello: function () {
        return "world"
        },
    myMethod: function () {
        // copy this, variable names are case-sensitive
        var that = this;
        // callbacks ftw \o/
        foo.bar("args", function () {
            // I want to call `hello` here
            this.hello(); // error
            // but `this` references to `foo` damn!
            // oh wait we have a backup \o/
            that.hello(); // "world"
        });
    }
  };

Trong đoạn mã trên, chúng ta thấy rằng giá trị của this thay đổi với phạm vi lồng nhau, nhưng chúng tôi muốn giá trị của this từ phạm vi ban đầu. Vì vậy, chúng tôi 'sao chép' this đến that và sử dụng bản sao thay vì this. Clever, eh?

Mục lục:

  1. Những gì được tổ chức tại this theo mặc định?
  2. Điều gì sẽ xảy ra nếu chúng ta gọi hàm như một phương thức với ký hiệu đối tượng-dấu chấm?
  3. Nếu chúng ta sử dụng new từ khóa?
  4. Làm thế nào để chúng ta thao tác this với call và apply?
  5. Sử dụng bind.
  6. Đang sao chép this để giải quyết các vấn đề về phạm vi lồng nhau.

46
2018-06-27 14:10



Tại sao có một phần về new từ khóa? Câu hỏi này cũng đã bị đánh đến chết, nhưng tất cả chúng ta đều có "lần đó chúng tôi cố gắng cưỡi những chiếc áo choàng của một câu hỏi được trả lời cách đây 4 năm" - Lady Bird


"điều này" là tất cả về phạm vi. Mỗi hàm đều có phạm vi riêng của nó và vì mọi thứ trong JS là một đối tượng, thậm chí một hàm có thể lưu trữ một số giá trị vào chính nó bằng cách sử dụng "this". OOP 101 dạy rằng "điều này" chỉ áp dụng cho các phiên bản của một đối tượng. Do đó, mỗi khi một hàm thực hiện, một "cá thể" mới của hàm đó có một ý nghĩa mới của "cái này".

Hầu hết mọi người bối rối khi họ cố gắng sử dụng "điều này" bên trong các chức năng đóng mở ẩn danh như:

(hàm (giá trị) {
    this.value = value;
    $ ('. some-elements') mỗi (hàm (elt) {
        elt.innerHTML = this.value; // uh oh !! có thể không xác định
    });
}) (2);

Vì vậy, ở đây, bên trong mỗi (), "điều này" không giữ "giá trị" mà bạn mong đợi nó (từ

this.value = value;
 trên nó). Vì vậy, để vượt qua vấn đề này (không có ý định chơi chữ), nhà phát triển có thể:

(hàm (giá trị) {
    var self = this; // thay đổi nhỏ
    self.value = value;
    $ ('. some-elements') mỗi (hàm (elt) {
        elt.innerHTML = self.value; // phew !! == 2
    });
}) (2);

Hãy dùng thử; bạn sẽ bắt đầu thích mô hình lập trình này


43
2017-10-06 19:46



"mọi thứ trong JS là một đối tượng" là không đúng, JavaScript cũng có các giá trị nguyên thủy, xem bclary.com/2004/11/07/#a-4.3.2 - Marcel Korpel
Các giá trị nguyên thủy dường như có một số phương thức trên chính nó, như String # substring (), Number # toString (), v.v. Vì vậy, có thể không có cùng danh pháp như bài viết đó, chúng thực sự cư xử như thể chúng là các đối tượng (chúng là tất cả prototyped, tức là String # substring () thực sự là: String.prototype.substring = function () {...}). Nêu tôi sai vui long chân chỉnh tôi. - arunjitsingh
Các this từ khóa không có gì để làm với phạm vi. Ngoài ra, nó cũng có nghĩa trong các hàm không thuộc tính của các đối tượng. - Bergi
@ arunjitsingh — có hai trường tư tưởng về điều đó. Tôi thích người nói "tất cả mọi thứ là một đối tượng, nhưng một số có thể được đại diện bởi nguyên thủy để thuận tiện". ;-) - RobG
this không phải là TẤT CẢ về phạm vi. Đó là TẤT CẢ về ngữ cảnh thực thi, không giống như phạm vi. JavaScript là phạm vi từ vựng (nghĩa là phạm vi được xác định bởi vị trí của mã), nhưng this được xác định bằng cách hàm chứa nó được gọi ra - không phải là hàm đó ở đâu. - Scott Marcus


this trong Javascript luôn đề cập đến 'chủ sở hữu' của hàm đang bị xử tử.

Nếu không có chủ sở hữu rõ ràng nào được xác định, thì chủ sở hữu nhiều nhất, đối tượng cửa sổ, được tham chiếu.

Vì vậy, nếu tôi đã làm

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

this sẽ đề cập đến đối tượng phần tử. Nhưng hãy cẩn thận, rất nhiều người mắc lỗi này

<element onclick="someKindOfFunction()">

Trong trường hợp thứ hai, bạn chỉ tham chiếu hàm, không chuyển nó cho phần tử. Vì vậy, this sẽ tham chiếu đến đối tượng cửa sổ.


12
2017-10-30 03:58





Kể từ khi chủ đề này đã tăng lên, tôi đã biên soạn vài điểm cho độc giả mới this đề tài. 

Giá trị của thisxác định?

Chúng tôi sử dụng điều này tương tự như cách chúng tôi sử dụng đại từ trong các ngôn ngữ tự nhiên như tiếng Anh: “John đang chạy nhanh vì anh ấy đang cố bắt tàu. ”Thay vào đó, chúng tôi có thể viết“… John đang cố bắt tàu ”.

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

this  không được gán giá trị cho đến khi một đối tượng gọi hàm mà nó được định nghĩa. Trong phạm vi toàn cục, tất cả các biến và hàm toàn cục được xác định trên window vật. Vì thế, this trong một chức năng toàn cầu đề cập đến (và có giá trị của) toàn cầu window vật.

Khi nào use strict, this trong toàn cầu và trong các hàm ẩn danh không bị ràng buộc với bất kỳ đối tượng nào có giá trị undefined.

Các this từ khóa là hiểu lầm nhất khi: 1) chúng tôi mượn một phương thức sử dụng this, 2) chúng tôi chỉ định một phương pháp sử dụng this đến một biến, 3) một hàm sử dụng this được chuyển thành hàm gọi lại và 4) this được sử dụng bên trong một bao đóng - một hàm bên trong. (2)

table

Điều gì giữ tương lai

Được xác định trong Tập lệnh ECMA 6, arrow-chức năng áp dụng this ràng buộc từ kèm theo (chức năng hoặc toàn cầu) phạm vi.

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!

Trong khi các chức năng mũi tên cung cấp một cách thay thế cho việc sử dụng bind(), điều quan trọng cần lưu ý là về cơ bản họ đang vô hiệu hóa truyền thống this cơ chế ủng hộ phạm vi từ vựng được hiểu rộng rãi hơn. (1)


Tham khảo:

  1. này & Object Prototypes, bởi Kyle Simpson. Giải pháp Getify 2014.
  2. javascriptissexy.com - http://goo.gl/pvl0GX 
  3. Angus Croll - http://goo.gl/Z2RacU 

12
2018-06-27 13:15





Mỗi chức năng  ngữ cảnh thực thi trong javascript có một phạm vi  bối cảnh  điều này tham số được đặt bởi:

  1. Cách hàm được gọi (bao gồm cả một phương thức đối tượng, sử dụng gọi điện và ứng dụng, sử dụng Mới)
  2. Sử dụng trói buộc
  3. Về mặt kỹ thuật cho các chức năng mũi tên (chúng áp dụng điều này ngữ cảnh thực thi bên ngoài của chúng)

Bất kể bối cảnh phạm vi đó là gì, được tham chiếu bởi "this".

Bạn có thể thay đổi điều đó đặt giá trị của điều này  phạm vi  bối cảnh sử dụng func.call, func.apply hoặc là func.bind.

Theo mặc định và điều gây nhầm lẫn cho hầu hết người mới bắt đầu, khi gọi lại người nghe được gọi sau khi một sự kiện được nâng lên trên một phần tử DOM, phạm vi ngữ cảnh  điều này giá trị của hàm là phần tử DOM.

jQuery làm cho điều này tầm thường để thay đổi với jQuery.proxy.


9
2017-11-29 06:01



Đúng hơn một chút để nói rằng mọi chức năng gọi điện có một phạm vi. Nói cách khác, điều gì gây nhầm lẫn về this trong Javascript là nó không phải một thuộc tính nội tại của chính hàm đó, mà là một tạo phẩm của cách hàm được gọi. - Pointy
@pointy cảm ơn. điều gây ra sự nhầm lẫn nhiều nhất về điều này trong js là thực tế rằng trong tất cả các ngôn ngữ được sử dụng trước đó (c #, c ++), - không thể thao tác n luôn trỏ đến đối tượng trong khi ở js nó phụ thuộc và có thể thay đổi khi gọi chức năng sử dụng func.call, func.bind vv - Sushil - Sushil
this làm không phải tham chiếu phạm vi của hàm. this sẽ tham chiếu một đối tượng cụ thể (hoặc có thể undefined), như bạn đã nói có thể được thay đổi bằng cách sử dụng .call() hoặc là .apply(). Chức năng của một phạm vi là (về cơ bản, khi được đơn giản hóa) mà các biến nó có quyền truy cập vào, và điều này phụ thuộc hoàn toàn vào vị trí hàm được khai báo và không thể thay đổi. - nnnnnn
@Pointy: "Đúng hơn một chút khi nói rằng mọi cuộc gọi hàm đều có phạm vi." Thậm chí chính xác hơn để nói rằng các hàm (và bây giờ khối) có phạm vi, chức năng cuộc gọi có bối cảnh. Phạm vi xác định những gì các định danh có thể được sử dụng bởi mã trong phạm vi đó. Ngữ cảnh xác định những gì các định danh được ràng buộc. - T.J. Crowder
"Bất kể phạm vi đó là gì, được tham chiếu bởi" cái này "." Không, this và phạm vi không có gì liên quan đến nhau trong ES5 và trước đó (ví dụ, khi câu trả lời này được viết). Trong ES2015 (aka ES6), this và phạm vi có liên quan một cách khá tối thiểu các chức năng mũi tên wrt ( this trong một chức năng mũi tên được thừa hưởng từ phạm vi kèm theo của nó), nhưng this không bao giờ đề cập đến một phạm vi. - T.J. Crowder


Đây là một nguồn tốt của this trong JavaScript.

Dưới đây là tóm tắt:

  • toàn cầu này

    Trong trình duyệt, ở phạm vi toàn cầu, this là windowvật

    <script type="text/javascript">
      console.log(this === window); // true
      var foo = "bar";
      console.log(this.foo); // "bar"
      console.log(window.foo); // "bar"
    

    Trong node sử dụng repl, this là không gian tên trên cùng. Bạn có thể gọi nó là global.

    >this
      { ArrayBuffer: [Function: ArrayBuffer],
        Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
        Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
        ...
    >global === this
     true
    

    Trong node thực thi từ một tập lệnh, this tại phạm vi toàn cục bắt đầu như một đối tượng trống. Nó không giống như global

    \\test.js
    console.log(this);  \\ {}
    console.log(this === global); \\ fasle
    
  • chức năng này

Ngoại trừ trong trường hợp xử lý sự kiện DOM hoặc khi thisArg được cung cấp (xem thêm chi tiết), cả trong nút và trong trình duyệt sử dụng thistrong một hàm không được gọi với new tham chiếu phạm vi toàn cầu…

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

Nếu bạn dùng use strict;, trong trường hợp this sẽ là undefined

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

Nếu bạn gọi một hàm với new các this sẽ là một bối cảnh mới, nó sẽ không ám chỉ toàn cầu this.

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>
  • nguyên mẫu này

Các hàm bạn tạo thành các đối tượng hàm. Họ tự động nhận được một đặc biệt prototype thuộc tính, là thứ bạn có thể gán giá trị cho. Khi bạn tạo một cá thể bằng cách gọi hàm của bạn với new bạn có quyền truy cập vào các giá trị bạn đã gán cho prototype bất động sản. Bạn truy cập các giá trị đó bằng cách sử dụng this.

function Thing() {
  console.log(this.foo);
}

Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

Nó thường là một sai lầm để gán mảng hoặc là các đối tượng trên prototype. Nếu bạn muốn các cá thể có mỗi mảng riêng của chúng, hãy tạo chúng trong hàm, chứ không phải mẫu thử.

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
  • đối tượng này

Bạn có thể dùng this trong bất kỳ hàm nào trên một đối tượng để tham chiếu đến các thuộc tính khác trên đối tượng đó. Điều này không giống như một cá thể được tạo bằng new.

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"
  • Sự kiện DOM này

Trong trình xử lý sự kiện HTML DOM, this luôn là tham chiếu đến phần tử DOM sự kiện được đính kèm

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();

Trừ khi bạn bind bối cảnh

function Listener() {
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs Listener {handleClick: function}
}

var listener = new Listener();
document.getElementById("foo").click();
  • HTML này

Các thuộc tính HTML bên trong mà bạn có thể đặt JavaScript, this là một tham chiếu đến phần tử.

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
  • đánh giá cái này

Bạn có thể dùng eval truy cập vào this.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();
  • Với cái này

Bạn có thể dùng with thêm this đến phạm vi hiện tại để đọc và ghi vào các giá trị trên this mà không đề cập đến this một cách rõ ràng.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
  • jQuery cái này

jQuery sẽ ở nhiều nơi có this tham chiếu đến phần tử DOM.

<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>

7
2018-04-23 12:57





Daniel, lời giải thích tuyệt vời! Một vài từ trong danh sách này this con trỏ ngữ cảnh thực hiện trong trường hợp xử lý sự kiện.

Trong hai từ, this trong JavaScript trỏ đối tượng mà từ đó (hoặc từ ngữ cảnh thực thi của nó) chức năng hiện tại được chạy và nó luôn luôn là chỉ đọc, bạn không thể đặt nó (như một nỗ lực sẽ kết thúc với 'Bên trái không hợp lệ trong nhiệm vụ' thông điệp.

Đối với trình xử lý sự kiện: xử lý sự kiện nội tuyến, chẳng hạn như <element onclick="foo">, ghi đè lên bất kỳ trình xử lý nào khác được đính kèm trước đó và trước đó, vì vậy hãy cẩn thận và tốt hơn hết là nên dừng lại ở phái đoàn sự kiện nội tuyến. Và nhờ Zara Alaverdyan đã truyền cảm hứng cho tôi đến danh sách các ví dụ này thông qua một cuộc tranh luận bất đồng :)

  • el.onclick = foo; // in the foo - obj
  • el.onclick = function () {this.style.color = '#fff';} // obj
  • el.onclick = function() {doSomething();} // In the doSomething - Window
  • el.addEventListener('click',foo,false) // in the foo - obj
  • el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
  • <button onclick="this.style.color = '#fff';"> // obj
  • <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">

6
2018-01-31 08:29