จะเข้าถึง "this" ที่ถูกต้องภายในการโทรกลับได้อย่างไร

Nov 29 2013

ฉันมีฟังก์ชันตัวสร้างที่ลงทะเบียนตัวจัดการเหตุการณ์:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', function () {
        alert(this.data);
    });
}

// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

// called as
var obj = new MyConstructor('foo', transport);

อย่างไรก็ตามฉันไม่สามารถเข้าถึงdataคุณสมบัติของวัตถุที่สร้างขึ้นภายในการเรียกกลับ ดูเหมือนว่าthisจะไม่ได้อ้างถึงออบเจ็กต์ที่ถูกสร้างขึ้น แต่เป็นอีกชิ้นหนึ่ง

ฉันยังพยายามใช้วิธีการวัตถุแทนฟังก์ชันที่ไม่ระบุชื่อ:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', this.alert);
}

MyConstructor.prototype.alert = function() {
    alert(this.name);
};

แต่มันแสดงปัญหาเดียวกัน

ฉันจะเข้าถึงวัตถุที่ถูกต้องได้อย่างไร?

คำตอบ

1910 FelixKling Nov 29 2013 at 13:13

สิ่งที่คุณควรรู้ this

this(aka "the context") เป็นคีย์เวิร์ดพิเศษภายในแต่ละฟังก์ชันและค่าของมันขึ้นอยู่กับวิธีการเรียกใช้ฟังก์ชันเท่านั้นไม่ใช่ว่ากำหนดอย่างไร / เมื่อใด / ที่ใด ไม่ได้รับผลกระทบจากขอบเขตคำศัพท์เหมือนตัวแปรอื่น ๆ (ยกเว้นฟังก์ชันลูกศรดูด้านล่าง) นี่คือตัวอย่างบางส่วน:

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

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

ต้องการเรียนรู้เพิ่มเติมเกี่ยวกับการthisมีลักษณะที่เป็นเอกสาร MDN


วิธีการอ้างอิงที่ถูกต้อง this

ใช้ฟังก์ชันลูกศร

ECMAScript 6 แนะนำฟังก์ชันลูกศรซึ่งสามารถคิดได้ว่าเป็นฟังก์ชันแลมบ์ดา พวกเขาไม่มีthisผลผูกพันของตัวเอง แต่thisจะถูกค้นหาในขอบเขตเช่นเดียวกับตัวแปรปกติ .bindนั่นหมายความว่าคุณจะได้ไม่ต้องโทร นั่นไม่ใช่พฤติกรรมพิเศษเพียงอย่างเดียวที่พวกเขามีโปรดดูเอกสาร MDN สำหรับข้อมูลเพิ่มเติม

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

อย่าใช้ this

จริงๆคุณไม่ต้องการที่จะเข้าถึงthisโดยเฉพาะอย่างยิ่ง แต่วัตถุที่มันหมายถึง นั่นเป็นเหตุผลที่วิธีแก้ปัญหาง่ายๆคือสร้างตัวแปรใหม่ที่อ้างถึงวัตถุนั้นด้วย ตัวแปรสามารถมีชื่อใด ๆ แต่คนทั่วไปและselfthat

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

เนื่องจากselfเป็นตัวแปรปกติจึงปฏิบัติตามกฎขอบเขตศัพท์และสามารถเข้าถึงได้ภายในการเรียกกลับ นอกจากนี้ยังมีข้อดีที่คุณสามารถเข้าถึงthisมูลค่าของการโทรกลับได้

การตั้งค่าthisการโทรกลับอย่างชัดเจน- ตอนที่ 1

อาจดูเหมือนว่าคุณไม่สามารถควบคุมค่าได้thisเนื่องจากค่าของมันถูกตั้งค่าโดยอัตโนมัติ แต่จริงๆแล้วไม่เป็นเช่นนั้น

ทุกฟังก์ชันมี method .bind [docs]ซึ่งจะส่งคืนฟังก์ชันใหม่โดยthisผูกไว้กับค่า ฟังก์ชันนี้มีลักษณะการทำงานเหมือนกับที่คุณเรียก.bindใช้เฉพาะที่thisคุณกำหนดไว้เท่านั้น ไม่ว่าฟังก์ชันนั้นจะถูกเรียกใช้อย่างไรหรือเมื่อใดก็ตามthisจะอ้างถึงค่าที่ผ่านเสมอ

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

ในกรณีนี้เราจะมีผลผูกพันการเรียกกลับของthisค่าของ'sMyConstructorthis

หมายเหตุ:เมื่อบริบทที่มีผลผูกพันสำหรับ jQuery ให้ใช้jQuery.proxy [docs]แทน เหตุผลในการทำเช่นนี้คือคุณไม่จำเป็นต้องจัดเก็บข้อมูลอ้างอิงของฟังก์ชันเมื่อยกเลิกการผูกการเรียกกลับเหตุการณ์ jQuery จัดการสิ่งนั้นภายใน

ชุดthisการโทรกลับ - ตอนที่ 2

ฟังก์ชัน / วิธีการบางอย่างที่ยอมรับการโทรกลับยังยอมรับค่าที่การเรียกกลับthisควรอ้างถึง โดยพื้นฐานแล้วจะเหมือนกับการผูกมัดตัวเอง แต่ฟังก์ชัน / วิธีการนี้จะทำเพื่อคุณ Array#map [docs]เป็นวิธีการดังกล่าว ลายเซ็นคือ:

array.map(callback[, thisArg])

อาร์กิวเมนต์แรกคือการเรียกกลับและอาร์กิวเมนต์ที่สองคือค่าที่thisควรอ้างถึง นี่คือตัวอย่างที่สร้างขึ้น:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

หมายเหตุ:คุณสามารถส่งค่าสำหรับได้หรือไม่thisโดยปกติจะกล่าวถึงในเอกสารของฟังก์ชัน / วิธีการนั้น ตัวอย่างเช่นวิธีการของ jQuery [เอกสาร]$.ajaxอธิบายตัวเลือกที่เรียกว่าcontext:

วัตถุนี้จะสร้างบริบทของการเรียกกลับที่เกี่ยวข้องกับ Ajax ทั้งหมด


ปัญหาทั่วไป: การใช้เมธอดอ็อบเจ็กต์เป็น callbacks / event handlers

อาการทั่วไปอีกประการหนึ่งของปัญหานี้คือเมื่อใช้เมธอดอ็อบเจ็กต์เป็นตัวจัดการการเรียกกลับ / เหตุการณ์ ฟังก์ชันเป็นพลเมืองชั้นหนึ่งใน JavaScript และคำว่า "วิธีการ" เป็นเพียงคำเรียกขานสำหรับฟังก์ชันที่เป็นค่าของคุณสมบัติวัตถุ แต่ฟังก์ชันนั้นไม่มีลิงก์เฉพาะไปยังวัตถุ "ที่มี" ของมัน

พิจารณาตัวอย่างต่อไปนี้:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

ฟังก์ชั่นthis.methodที่ได้รับมอบหมายเป็นตัวจัดการเหตุการณ์ค แต่ถ้าdocument.bodyมีการคลิกค่าลงทะเบียนจะเป็นundefinedเพราะภายในตัวจัดการเหตุการณ์ที่thisหมายถึงไม่ได้ตัวอย่างของdocument.body ดังกล่าวแล้วที่จุดเริ่มต้นสิ่งที่หมายถึงขึ้นอยู่กับวิธีการทำงานจะเรียกว่าไม่ว่ามันถูกกำหนดไว้ หากรหัสเป็นดังต่อไปนี้อาจเห็นได้ชัดว่าฟังก์ชันไม่มีการอ้างอิงโดยนัยถึงวัตถุ:Foo
this

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

วิธีแก้ปัญหาเหมือนกับที่กล่าวไว้ข้างต้น: หากมีให้ใช้.bindเพื่อผูกthisกับค่าเฉพาะอย่างชัดเจน

document.body.onclick = this.method.bind(this);

หรือเรียกฟังก์ชันอย่างชัดเจนว่าเป็น "วิธีการ" ของวัตถุโดยใช้ฟังก์ชันที่ไม่ระบุชื่อเป็นตัวจัดการการเรียกกลับ / เหตุการณ์และกำหนดวัตถุ ( this) ให้กับตัวแปรอื่น:

var self = this;
document.body.onclick = function() {
    self.method();
};

หรือใช้ฟังก์ชันลูกศร:

document.body.onclick = () => this.method();
225 MohanDere Aug 13 2016 at 17:26

มีหลายวิธีในการเข้าถึงบริบทหลักในบริบทลูก -

  1. คุณสามารถใช้bind()ฟังก์ชัน
  2. จัดเก็บการอ้างอิงบริบท / สิ่งนี้ภายในตัวแปรอื่น (ดูตัวอย่างด้านล่าง)
  3. ใช้ฟังก์ชันES6 Arrow
  4. แก้ไขโค้ด / การออกแบบฟังก์ชัน / สถาปัตยกรรม - สำหรับสิ่งนี้คุณควรมีคำสั่งเกี่ยวกับ รูปแบบการออกแบบในจาวาสคริปต์

1. ใช้bind()ฟังก์ชัน

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

หากคุณใช้underscore.js- http://underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

2 จัดเก็บการอ้างอิงบริบท / สิ่งนี้ภายในตัวแปรอื่น

function MyConstructor(data, transport) {
  var self = this;
  this.data = data;
  transport.on('data', function() {
    alert(self.data);
  });
}

3 ฟังก์ชั่นลูกศร

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}
59 Guffa May 21 2014 at 07:11

ทั้งหมดนี้อยู่ในไวยากรณ์ "magic" ของการเรียก method:

object.property();

เมื่อคุณได้รับคุณสมบัติจากวัตถุและเรียกใช้ในครั้งเดียววัตถุจะเป็นบริบทสำหรับวิธีการ หากคุณเรียกใช้วิธีเดียวกัน แต่ในขั้นตอนที่แยกจากกันบริบทจะเป็นขอบเขตส่วนกลาง (หน้าต่าง) แทน:

var f = object.property;
f();

เมื่อคุณได้รับการอ้างอิงของวิธีการจะไม่แนบกับวัตถุอีกต่อไปมันเป็นเพียงการอ้างอิงถึงฟังก์ชันธรรมดา สิ่งเดียวกันนี้จะเกิดขึ้นเมื่อคุณได้รับการอ้างอิงเพื่อใช้เป็นการโทรกลับ:

this.saveNextLevelData(this.setAll);

นั่นคือที่ที่คุณจะผูกบริบทเข้ากับฟังก์ชัน:

this.saveNextLevelData(this.setAll.bind(this));

หากคุณใช้ jQuery คุณควรใช้$.proxyวิธีนี้แทนเนื่องจากbindไม่ได้รับการสนับสนุนในทุกเบราว์เซอร์:

this.saveNextLevelData($.proxy(this.setAll, this));
34 RobG Jun 01 2014 at 07:44

ปัญหาเกี่ยวกับ "บริบท"

คำว่า "บริบท" บางครั้งใช้ในการอ้างถึงวัตถุอ้างอิงจากนี้ การใช้งานที่ไม่เหมาะสมเพราะมันไม่พอดีทั้งความหมายในทางเทคนิคหรือมีECMAScript ของนี้

"บริบท"หมายถึงสถานการณ์รอบ ๆ สิ่งที่เพิ่มความหมายหรือข้อมูลก่อนหน้าและต่อไปนี้ที่ให้ความหมายพิเศษ คำว่า "บริบท" ถูกใช้ใน ECMAScript เพื่ออ้างถึงบริบทการดำเนินการซึ่งเป็นพารามิเตอร์ขอบเขตและสิ่งนี้ทั้งหมดภายในขอบเขตของโค้ดการดำเนินการบางส่วน

สิ่งนี้แสดงไว้ในECMA-262 หัวข้อ 10.4.2 :

ตั้งค่า ThisBinding เป็นค่าเดียวกับ ThisBinding ของบริบทการเรียกใช้งาน

ซึ่งบ่งชี้อย่างชัดเจนว่านี่เป็นส่วนหนึ่งของบริบทการดำเนินการ

บริบทการดำเนินการให้ข้อมูลโดยรอบที่เพิ่มความหมายให้กับโค้ดที่กำลังดำเนินการ ซึ่งจะรวมถึงข้อมูลเพิ่มเติมกว่าเพียงthisBinding

ดังนั้นคุณค่าของสิ่งนี้จึงไม่ใช่ "บริบท" แต่เป็นเพียงส่วนหนึ่งของบริบทการดำเนินการ โดยพื้นฐานแล้วเป็นตัวแปรท้องถิ่นที่สามารถตั้งค่าได้โดยการเรียกไปยังวัตถุใด ๆ และในโหมดเข้มงวดเป็นค่าใดก็ได้

32 Ashish Jan 30 2019 at 18:01

คุณควรรู้เกี่ยวกับคำหลัก "นี้"

ตามมุมมองของฉันคุณสามารถใช้ "this" ได้สามวิธี (ฟังก์ชัน Self / Arrow / Bind Method)

คำหลักนี้ของฟังก์ชันทำงานแตกต่างกันเล็กน้อยใน JavaScript เมื่อเทียบกับภาษาอื่น ๆ

นอกจากนี้ยังมีความแตกต่างบางประการระหว่างโหมดเข้มงวดและโหมดไม่เข้มงวด

ในกรณีส่วนใหญ่ค่านี้จะถูกกำหนดโดยวิธีเรียกใช้ฟังก์ชัน

ไม่สามารถกำหนดโดยการมอบหมายระหว่างการดำเนินการและอาจแตกต่างกันในแต่ละครั้งที่เรียกใช้ฟังก์ชัน

ES5 แนะนำวิธีการผูก () เพื่อกำหนดค่าของฟังก์ชันนี้ไม่ว่าจะเรียกอย่างไร

และ ES2015 แนะนำฟังก์ชันลูกศรซึ่งไม่ได้ให้การเชื่อมโยงนี้เป็นของตัวเอง (จะยังคงรักษาค่านี้ของบริบทคำศัพท์ที่แนบมา)

วิธีที่ 1: Self - Self ถูกใช้เพื่อรักษาการอ้างอิงถึงต้นฉบับแม้ว่าบริบทจะเปลี่ยนไป เป็นเทคนิคที่มักใช้ในตัวจัดการเหตุการณ์ (โดยเฉพาะอย่างยิ่งในการปิด)

อ้างอิง : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function () {
        alert(self.data);
    });
}

วิธีที่ 2 : ฟังก์ชันลูกศร - นิพจน์ฟังก์ชันลูกศรเป็นทางเลือกที่กระชับทางไวยากรณ์แทนนิพจน์ฟังก์ชันทั่วไป

แม้ว่าจะไม่มีการเชื่อมโยงของตัวเองกับคำหลักนี้อาร์กิวเมนต์ super หรือ new.target

นิพจน์ฟังก์ชันลูกศรไม่เหมาะกับวิธีการและไม่สามารถใช้เป็นตัวสร้างได้

อ้างอิง : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',()=> {
        alert(this.data);
    });
}

Method3 : Bind- วิธีการผูก () สร้างฟังก์ชันใหม่ที่

เมื่อถูกเรียกจะมีการตั้งค่าคีย์เวิร์ดนี้เป็นค่าที่ระบุ

โดยมีลำดับของอาร์กิวเมนต์ที่กำหนดไว้ข้างหน้าเมื่อมีการเรียกใช้ฟังก์ชันใหม่

อ้างอิง: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',(function() {
        alert(this.data);
    }).bind(this);
26 AL-zami Aug 19 2017 at 00:58

ครั้งแรกที่คุณจะต้องมีความเข้าใจอย่างชัดเจนscopeและพฤติกรรมของคำหลักในบริบทของthisscope

this& scope:


there are two types of scope in javascript. They are :

   1) Global Scope

   2) Function Scope

ในระยะสั้นขอบเขตส่วนกลางหมายถึงวัตถุหน้าต่างตัวแปรที่ประกาศในขอบเขตทั่วโลกสามารถเข้าถึงได้จากทุกที่ในทางกลับกันขอบเขตของฟังก์ชันจะอยู่ภายในฟังก์ชันตัวแปรที่ประกาศภายในฟังก์ชันไม่สามารถเข้าถึงได้จากโลกภายนอกตามปกติ thisคำสำคัญในขอบเขตส่วนกลางหมายถึงวัตถุหน้าต่าง thisภายในฟังก์ชั่นยังหมายถึงวัตถุหน้าต่างดังนั้นthisจะอ้างถึงหน้าต่างเสมอจนกว่าเราจะพบวิธีจัดการthisเพื่อระบุบริบทของการเลือกของเราเอง

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   ( globally "this" refers to window object)                                 -     
-                                                                              -
-         function outer_function(callback){                                   -
-                                                                              -
-               // outer function scope                                        -
-               // inside outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  -

-         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

วิธีต่างๆในการจัดการthisฟังก์ชันการโทรกลับภายใน:

ที่นี่ฉันมีฟังก์ชันตัวสร้างที่เรียกว่าบุคคล มันมีคุณสมบัติที่เรียกว่าnameสี่และวิธีการที่เรียกว่าsayNameVersion1, sayNameVersion2, ,sayNameVersion3 sayNameVersion4ทั้งสี่งานมีภารกิจเฉพาะอย่างหนึ่งยอมรับการโทรกลับและเรียกใช้การโทรกลับมีภารกิจเฉพาะซึ่งจะบันทึกคุณสมบัติชื่อของอินสแตนซ์ของฟังก์ชันตัวสร้างบุคคล

function Person(name){

    this.name = name

    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }

    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }

    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }

}

function niceCallback(){

    // function to be used as callback

    var parentObject = this

    console.log(parentObject)

}

ตอนนี้เรามาสร้างอินสแตนซ์จากตัวสร้างบุคคลและเรียกใช้sayNameVersionXเมธอด (X หมายถึง 1,2,3,4) เวอร์ชันต่างๆniceCallbackเพื่อดูว่าเราสามารถจัดการกับการthisเรียกกลับภายในเพื่ออ้างถึงpersonอินสแตนซ์ได้กี่วิธี

var p1 = new Person('zami') // create an instance of Person constructor

ผูก:

สิ่งที่ผูกไว้คือการสร้างฟังก์ชันใหม่โดยthisตั้งค่าคีย์เวิร์ดเป็นค่าที่ระบุ

sayNameVersion1และsayNameVersion2ใช้การผูกเพื่อจัดการthisกับฟังก์ชันเรียกกลับ

this.sayNameVersion1 = function(callback){
    callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
    callback()
}

อันแรกผูกthisกับการโทรกลับภายในวิธีการนั้นเองและสำหรับการโทรกลับครั้งที่สองจะถูกส่งผ่านไปพร้อมกับวัตถุที่ผูกไว้

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method

p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

โทร :

first argumentของcallวิธีการที่จะใช้เป็นthisภายในฟังก์ชันที่ถูกเรียกด้วยcallแนบมากับมัน

sayNameVersion3ใช้ callเพื่อจัดการthisเพื่ออ้างถึงวัตถุบุคคลที่เราสร้างขึ้นแทนที่จะเป็นวัตถุหน้าต่าง

this.sayNameVersion3 = function(callback){
    callback.call(this)
}

และเรียกว่าดังต่อไปนี้:

p1.sayNameVersion3(niceCallback)

สมัคร:

คล้ายกับcallอาร์กิวเมนต์แรกของการapplyอ้างถึงวัตถุที่จะระบุด้วยthisคำสำคัญ

sayNameVersion4ใช้applyในการจัดการthisเพื่ออ้างถึงวัตถุบุคคล

this.sayNameVersion4 = function(callback){
    callback.apply(this)
}

และเรียกว่าดังต่อไปนี้เพียงแค่โทรกลับเท่านั้น

p1.sayNameVersion4(niceCallback)
20 DattaChanewad Nov 17 2017 at 21:32

เราไม่สามารถผูกสิ่งนี้เข้าsetTimeout()กับมันได้เนื่องจากมันมักจะเรียกใช้กับglobal object (Window)เสมอหากคุณต้องการเข้าถึงthisบริบทในฟังก์ชัน callback โดยใช้bind()กับฟังก์ชัน callback ที่เราสามารถทำได้เป็น:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);
13 Code_Mode Feb 18 2019 at 16:10

คำถามเกี่ยวกับการthisทำงานของคำหลักในจาวาสคริปต์ thisทำงานแตกต่างกันดังต่อไปนี้

  1. ค่าของthisมักจะถูกกำหนดโดยบริบทการเรียกใช้ฟังก์ชัน
  2. ในขอบเขตส่วนกลางthisหมายถึงวัตถุส่วนกลาง ( windowวัตถุ)
  3. หากเปิดใช้งานโหมดเข้มงวดสำหรับฟังก์ชันใด ๆ ค่าของthisจะundefinedเป็นในโหมดเข้มงวดวัตถุส่วนกลางจะอ้างถึงundefinedในตำแหน่งของwindowวัตถุ
  4. ออบเจ็กต์ที่อยู่หน้าจุดคือสิ่งที่คีย์เวิร์ดนี้จะถูกผูกไว้
  5. เราสามารถตั้งค่านี้อย่างชัดเจนด้วยcall(), bind()และapply()
  6. เมื่อใช้newคีย์เวิร์ด (ตัวสร้าง) สิ่งนี้จะถูกผูกไว้กับอ็อบเจ็กต์ใหม่ที่กำลังสร้าง
  7. ฟังก์ชั่นลูกศรไม่ผูกthis - ผูกthisเป็นศัพท์แทน (กล่าวคือขึ้นอยู่กับบริบทเดิม)

ตามที่คำตอบส่วนใหญ่แนะนำเราสามารถใช้ฟังก์ชัน Arrow หรือbind()Method หรือ Self var ฉันจะพูดถึงประเด็นเกี่ยวกับ lambdas (ฟังก์ชัน Arrow) จากGoogle JavaScript Style Guide

ชอบใช้ฟังก์ชันลูกศรมากกว่า f.bind (this) และโดยเฉพาะอย่างยิ่งใน goog.bind (f, this) หลีกเลี่ยงการเขียน const self = this ฟังก์ชันลูกศรมีประโยชน์อย่างยิ่งสำหรับการเรียกกลับซึ่งบางครั้งอาจส่งผ่านข้อโต้แย้งเพิ่มเติมโดยไม่คาดคิด

Google แนะนำอย่างชัดเจนว่าให้ใช้ lambdas แทนการผูกหรือ const self = this

ดังนั้นทางออกที่ดีที่สุดคือใช้ lambdas ดังต่อไปนี้

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

อ้างอิง:

  1. https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
  2. ลูกศรฟังก์ชั่น VS ผูก
8 skyboyer Sep 22 2018 at 20:38

ปัจจุบันมีแนวทางอื่นที่เป็นไปได้หากใช้คลาสในโค้ด

ด้วยการสนับสนุนฟิลด์คลาส จึงเป็นไปได้ที่จะดำเนินการต่อไปนี้:

class someView {
    onSomeInputKeyUp = (event) => {
        console.log(this); // this refers to correct value
    // ....
    someInitMethod() {
        //...
        someInput.addEventListener('input', this.onSomeInputKeyUp)

แน่นอนว่าภายใต้ประทุนมันเป็นฟังก์ชันลูกศรที่ดีที่ผูกบริบท แต่ในรูปแบบนี้มันดูชัดเจนกว่ามากว่าการเชื่อมโยงอย่างชัดเจน

เนื่องจากเป็นข้อเสนอขั้นที่ 3 คุณจะต้องใช้ babel และปลั๊กอิน babelที่เหมาะสมเพื่อดำเนินการในตอนนี้ (08/2018)

5 AndreaPuddu Aug 28 2018 at 16:10

อีกวิธีหนึ่งซึ่งเป็นวิธีมาตรฐานตั้งแต่ DOM2ในการเชื่อมโยงthisภายในตัวฟังเหตุการณ์ที่ช่วยให้คุณลบ Listener ได้ตลอดเวลา (ท่ามกลางประโยชน์อื่น ๆ ) คือhandleEvent(evt)วิธีการจากEventListenerอินเทอร์เฟซ:

var obj = {
  handleEvent(e) {
    // always true
    console.log(this === obj);
  }
};

document.body.addEventListener('click', obj);

สามารถดูข้อมูลโดยละเอียดเกี่ยวกับการใช้งานhandleEventได้ที่นี่: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38

2 WillemvanderVeen May 05 2020 at 15:48

this ใน JS:

ค่าของthisใน JS คือ 100% กำหนดโดยวิธีเรียกใช้ฟังก์ชันไม่ใช่วิธีกำหนด เราสามารถหาได้ง่ายค่อนข้างค่าของthisโดย'ซ้ายของกฎ dot' :

  1. เมื่อฟังก์ชันถูกสร้างขึ้นโดยใช้คีย์เวิร์ดของฟังก์ชันค่าของthisจะเป็นอ็อบเจ็กต์ทางซ้ายของจุดของฟังก์ชันที่เรียกว่า
  2. หากไม่มีวัตถุเหลือจากจุดค่าของthisภายในฟังก์ชันมักจะเป็นวัตถุส่วนกลาง ( globalในโหนดwindowในเบราว์เซอร์) ฉันไม่แนะนำให้ใช้thisคำหลักที่นี่เพราะมีความชัดเจนน้อยกว่าการใช้คำหลักเช่นwindow!
  3. มีโครงสร้างบางอย่างเช่นฟังก์ชันลูกศรและฟังก์ชันที่สร้างขึ้นโดยใช้Function.prototype.bind()ฟังก์ชันที่สามารถแก้ไขค่าของthis. เหล่านี้เป็นข้อยกเว้นของกฎ thisแต่จริงๆเป็นประโยชน์ในการแก้ไขปัญหาค่าของ

ตัวอย่างใน nodeJS

module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);

const obj1 = {
    data: "obj1 data",
    met1: function () {
        console.log(this.data);
    },
    met2: () => {
        console.log(this.data);
    },
};

const obj2 = {
    data: "obj2 data",
    test1: function () {
        console.log(this.data);
    },
    test2: function () {
        console.log(this.data);
    }.bind(obj1),
    test3: obj1.met1,
    test4: obj1.met2,
};

obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);

เอาท์พุต:

ให้ฉันแนะนำคุณเกี่ยวกับเอาต์พุต 1 ต่อ 1 (ละเว้นบันทึกแรกเริ่มจากวินาที):

  1. thisเป็นobj2เพราะด้านซ้ายของกฎจุดเราจึงสามารถดูได้ว่าtest1ถูกเรียกobj2.test1();อย่างไร obj2ทางซ้ายของจุดจึงเป็นthisค่า
  2. แม้ว่าจะobj2เหลืออยู่ในจุดที่test2ถูกผูกไว้กับobj1ผ่านทางbind()วิธีการ ดังนั้นค่าthisobj1
  3. obj2อยู่ทางซ้ายของจุดจากฟังก์ชันที่เรียกว่า: obj2.test3(). จึงobj2จะเป็นค่าของthis.
  4. ในกรณีนี้: obj2.test4() obj2อยู่ทางซ้ายของจุด อย่างไรก็ตามฟังก์ชันลูกศรไม่มีการthisเชื่อมโยงของตัวเอง ดังนั้นมันจะผูกกับthisค่าของขอบเขตภายนอกซึ่งเป็นmodule.exportsอ็อบเจ็กต์ที่ถูกบันทึกในตอนต้น
  5. เรายังสามารถระบุค่าของthisโดยใช้callฟังก์ชัน ที่นี่เราสามารถส่งผ่านthisค่าที่ต้องการเป็นอาร์กิวเมนต์ซึ่งobj2ในกรณีนี้
1 Md.TazbirUrRahmanBhuiyan Oct 12 2020 at 23:07

ฉันกำลังเผชิญปัญหากับNgxแผนภูมิเส้นxAxisTickFormattingฟังก์ชั่นซึ่งถูกเรียกจาก HTML [xAxisTickFormatting]="xFormat"เช่นนี้ ฉันไม่สามารถเข้าถึงตัวแปรของส่วนประกอบของฉันจากฟังก์ชันที่ประกาศไว้ วิธีนี้ช่วยฉันในการแก้ไขปัญหาเพื่อค้นหาสิ่งที่ถูกต้อง หวังว่านี่จะช่วยให้Ngxแผนภูมิเส้นผู้ใช้

แทนที่จะใช้ฟังก์ชันเช่นนี้:

xFormat (value): string {
  return value.toString() + this.oneComponentVariable; //gives wrong result 
}

ใช้สิ่งนี้:

 xFormat = (value) => {
   // console.log(this);
   // now you have access to your component variables
   return value + this.oneComponentVariable
 }