สิ่งที่รองรับ JavaScript นี้สำนวน: var self = this?


357

ฉันเห็นสิ่งต่อไปนี้ในแหล่งที่มาสำหรับการสาธิตหมายเหตุการจัดเก็บ WebKit HTML 5 SQL :

function Note() {
  var self = this;

  var note = document.createElement('div');
  note.className = 'note';
  note.addEventListener('mousedown', function(e) { return self.onMouseDown(e) }, false);
  note.addEventListener('click', function() { return self.onNoteClick() }, false);
  this.note = note;
  // ...
}

ผู้เขียนใช้ตัวเองในบางสถานที่ (ร่างกายฟังก์ชั่น) และสิ่งนี้ในสถานที่อื่น ๆ (ร่างกายของฟังก์ชั่นที่กำหนดไว้ในรายการอาร์กิวเมนต์ของวิธีการ) เกิดอะไรขึ้น? ตอนนี้ฉันสังเกตเห็นครั้งหนึ่งฉันจะเริ่มเห็นมันทุกที่หรือไม่?


4
นี่เป็นคุณลักษณะภาษา JS ที่เรียกว่า“ การปิดคำศัพท์”
subZero

2
เป็นไปได้ที่ซ้ำกันของ: var self = this? .
DavidRR

มีการอธิบายแนวคิดของสิ่งนี้อย่างชัดเจนที่นี่ scotch.io/@alZami/understanding-this-in-javascript
AL-zami

ตัวอย่างที่เกี่ยวข้องในคำตอบนี้stackoverflow.com/a/20279485/5610569 (สำหรับคำถาม "วิธีการเข้าถึงที่ถูกต้องthisภายในการโทรกลับ?")
FluxLemur

คำตอบ:


431

ดูนี้บทความเกี่ยวกับ alistapart.com (Ed: บทความได้รับการปรับปรุงตั้งแต่การเชื่อมโยงเดิม)

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

แก้ไข:โปรดทราบว่าการใช้งานselfไม่ได้รับการสนับสนุนเท่าที่window.selfมีอยู่และมีโอกาสที่จะทำให้เกิดข้อผิดพลาดหากคุณไม่ระวัง

สิ่งที่คุณเรียกว่าตัวแปรนั้นไม่สำคัญเลย var that = this;ไม่เป็นไร แต่ไม่มีอะไรมหัศจรรย์เกี่ยวกับชื่อ

ฟังก์ชั่นที่ประกาศในบริบท (เช่นการเรียกกลับ, การปิด) จะสามารถเข้าถึงตัวแปร / ฟังก์ชั่นที่ประกาศในขอบเขตเดียวกันหรือสูงกว่า

ตัวอย่างเช่นการเรียกกลับเหตุการณ์อย่างง่าย:

function MyConstructor(options) {
  let that = this;

  this.someprop = options.someprop || 'defaultprop';

  document.addEventListener('click', (event) => {
    alert(that.someprop);
  });
}

new MyConstructor({
  someprop: "Hello World"
});


ปรากฏว่าบทความเปลี่ยนไปใช้var that = this;
Bob Stein

@ BobStein ขอบคุณ ฉันจะอัปเดตคำตอบตามนั้น
Jonathan Fingland

96

ฉันคิดว่าชื่อตัวแปร 'ตัวเอง' ไม่ควรใช้ด้วยวิธีนี้อีกต่อไปเนื่องจากเบราว์เซอร์ที่ทันสมัยให้ตัวแปรทั่วโลกที่selfชี้ไปที่วัตถุทั่วโลกของทั้งหน้าต่างปกติหรือ WebWorker

เพื่อหลีกเลี่ยงความสับสนและความขัดแย้งที่อาจเกิดขึ้นคุณสามารถเขียนvar thiz = thisหรือvar that = thisแทน


43
ฉันมักจะใช้_this
djheru

6
@djheru +1 ดีกว่า " that" (ซึ่งสมองของฉันจะไม่ชิน)
o_o_o--

9
ฉันเริ่มใช้ "ฉัน" :)
Mopparthy Ravindranath

3
จนกระทั่งเบราว์เซอร์รุ่นใหม่เริ่มให้ตัวแปรระดับโลก _ สิ่งนี้หรือฉัน
Beejor

10
ไม่มีปัญหาอย่างแน่นอนกับการใช้ชื่อselfตราบใดที่คุณประกาศว่าเป็นvariable มันจะทำให้เป็นสากล แน่นอนถ้าคุณลืมvarมันจะไม่ทำงานกับชื่ออื่นเช่นกัน
Bergi

34

ใช่คุณจะเห็นมันทุกที่ that = this;ก็มักจะ

ดูวิธีการselfใช้งานภายในฟังก์ชั่นที่เรียกโดยเหตุการณ์ ผู้ที่จะมีบริบทของตัวเองเพื่อselfจะใช้ในการถือที่เข้ามาthisNote()

เหตุผลselfยังคงมีอยู่สำหรับฟังก์ชั่นแม้ว่าพวกเขาจะสามารถดำเนินการหลังจากNote()ฟังก์ชั่นเสร็จสิ้นการดำเนินการคือฟังก์ชั่นด้านในได้รับบริบทของฟังก์ชั่นด้านนอกเนื่องจากปิด


12
สำหรับฉันประเด็นตรงจุดคือselfไม่มีความหมายพิเศษ ฉันชอบใช้ var ชื่ออย่างอื่นมากกว่าselfเพราะมันทำให้ฉันสับสนบ่อยเพราะฉันคาดว่า 'ตัวเอง' จะเป็นคำสงวน ดังนั้นฉันชอบคำตอบของคุณ และในตัวอย่างของ OP ฉันต้องการvar thisNote = thisหรือคล้ายกัน
สตีฟ

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

28

ควรสังเกตว่ามีรูปแบบพร็อกซีสำรองสำหรับการอ้างอิงกับต้นฉบับthisในการโทรกลับหากคุณไม่ชอบvar self = thisสำนวน

ในฐานะที่เป็นฟังก์ชั่นสามารถเรียกใช้กับบริบทที่กำหนดโดยใช้function.applyหรือfunction.callคุณสามารถเขียนเสื้อคลุมที่ส่งกลับฟังก์ชั่นที่เรียกใช้ฟังก์ชั่นของคุณด้วยapplyหรือcallใช้บริบทที่กำหนด ดูproxyฟังก์ชันของ jQuery สำหรับการนำรูปแบบนี้ไปใช้ นี่คือตัวอย่างของการใช้งาน:

var wrappedFunc = $.proxy(this.myFunc, this);

wrappedFuncสามารถถูกเรียกใช้และจะให้เวอร์ชันของคุณthisเป็นบริบท


10

ตามที่คนอื่นได้อธิบายไว้var self = this;อนุญาตให้ใช้โค้ดในการปิดเพื่ออ้างอิงกลับไปยังขอบเขตพาเรนต์

อย่างไรก็ตามตอนนี้ปี 2018 และ ES6 ได้รับการสนับสนุนอย่างกว้างขวางจากเว็บเบราว์เซอร์ที่สำคัญทั้งหมด var self = this;สำนวนไม่ได้ค่อนข้างเป็นสิ่งจำเป็นที่มันเคยเป็น

ตอนนี้มันเป็นไปได้ที่จะหลีกเลี่ยงการvar self = this;ผ่านการใช้ฟังก์ชั่นลูกศร

ในกรณีที่เราจะใช้var self = this:

function test() {
    var self = this;
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", function() {
        console.log(self.hello); // logs "world"
    });
};

ตอนนี้เราสามารถใช้ฟังก์ชั่นลูกศรโดยไม่ต้องvar self = this:

function test() {
    this.hello = "world";
    document.getElementById("test_btn").addEventListener("click", () => {
        console.log(this.hello); // logs "world"
    });
};

ฟังก์ชั่นลูกศรไม่มีของตัวเองthisและเพียงแค่สมมติขอบเขตการล้อมรอบ


หรือ - ตกใจกลัว! - ทำไมไม่ผ่านสิ่งที่เกี่ยวข้องจริงเป็นอาร์กิวเมนต์ให้กับฟังก์ชั่นของคุณ (ปิด)? ทำไมคุณถึงอ้างถึงว่าอยู่นอกขอบเขตเหตุใดจึงเป็นคนเขียนโปรแกรมแบบนี้ นอกจากนี้ไม่เคยเหตุผลที่แท้จริงใด ๆ ที่จะทำเช่นนี้ แต่.addEventListender("click", (x) => { console.log(x); });คุณได้อธิบายถึงวิธีการและเหตุผลที่ชัดเจนมากและฉันเห็นด้วยกับการใช้ฟังก์ชั่นลูกศรที่สมเหตุสมผลมากขึ้น แต่ถึงกระนั้น ... นี่เป็นเพียงการเขียนโปรแกรมที่แย่มากขี้เกียจยุ่ง
Benjamin R

2
ใน JavaScript การอ้างอิงกลับไปยังขอบเขตหลักนั้นเป็นเรื่องธรรมดาและจำเป็นมาก มันเป็นส่วนพื้นฐานของภาษา ข้อเสนอแนะของคุณให้ผ่านในขอบเขตหลักเป็นอาร์กิวเมนต์ในตัวจัดการเหตุการณ์เป็นไปไม่ได้จริง นอกจากนี้ใน ES6 ฟังก์ชั่นลูกศรใช้การกำหนดขอบเขตศัพท์ - 'นี่' หมายถึงขอบเขตรอบปัจจุบันและไม่เพิ่มเติม - ไม่ใช่ "อ้างอิงจากสถานะขอบเขต" หรืออะไรทำนองนั้น
Elliot B.

9

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


9

มันเป็นมุมแหลม JavaScript เมื่อฟังก์ชั่นเป็นคุณสมบัติของวัตถุเรียกว่า aptly มากขึ้นวิธีการนี้หมายถึงวัตถุ ในตัวอย่างของตัวจัดการเหตุการณ์วัตถุที่บรรจุเป็นองค์ประกอบที่ก่อให้เกิดเหตุการณ์ เมื่อมีการเรียกใช้ฟังก์ชั่นมาตรฐานสิ่งนี้จะอ้างถึงวัตถุทั่วโลก เมื่อคุณมีฟังก์ชั่นซ้อนอยู่ในตัวอย่างของคุณสิ่งนี้จะไม่เกี่ยวข้องกับบริบทของฟังก์ชั่นด้านนอกเลย ฟังก์ชั่นด้านในจะแชร์ขอบเขตกับฟังก์ชั่นที่มีดังนั้นนักพัฒนาจะใช้รูปแบบของvar that = thisเพื่อรักษาสิ่งที่พวกเขาต้องการในฟังก์ชั่นภายใน


5

ตัวตนที่แท้จริงคือการอ้างอิงไปยังหน้าต่าง ( window.self) ดังนั้นเมื่อคุณพูดว่าvar self = 'something'คุณแทนที่การอ้างอิงหน้าต่างกับตัวเอง - เพราะตนเองมีอยู่ในวัตถุหน้าต่าง

นี่คือเหตุผลที่นักพัฒนาซอฟต์แวร์ส่วนใหญ่ต้องการvar that = thisมากกว่าvar self = this;

อย่างไรก็ตาม; var that = this;ไม่สอดคล้องกับแนวปฏิบัติที่ดี ... สันนิษฐานว่ารหัสของคุณจะได้รับการแก้ไข / แก้ไขในภายหลังโดยผู้พัฒนารายอื่นคุณควรใช้มาตรฐานการเขียนโปรแกรมทั่วไปที่เกี่ยวข้องกับชุมชนนักพัฒนา

ดังนั้นคุณควรใช้สิ่งต่าง ๆ เช่น var oldThis/ var oThis/ etc - เพื่อให้ชัดเจนในขอบเขตของคุณ // .. ไม่มาก แต่จะประหยัดไม่กี่วินาทีและรอบสมองไม่กี่


2
@prior ฉันคิดว่ามันสมเหตุสมผลจนถึงย่อหน้าสุดท้าย
miphe

0

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


@JohnPaul ... นี่ไม่ให้คำตอบ อาจไม่ใช่คำตอบที่ถูกต้อง แต่คุณจะบอกได้อย่างไรว่า "กำลังคุ้นเคยกับ ... " ไม่ใช่คำตอบของ "ทำไมเขาถึงทำเช่นนี้"?
GreenAsJade

-1
function Person(firstname, lastname) {
  this.firstname = firstname;

  this.lastname = lastname;
  this.getfullname = function () {
    return `${this.firstname}   ${this.lastname}`;
  };

  let that = this;
  this.sayHi = function() {
    console.log(`i am this , ${this.firstname}`);
    console.log(`i am that , ${that.firstname}`);
  };
}

let thisss = new Person('thatbetty', 'thatzhao');

let thatt = {firstname: 'thisbetty', lastname: 'thiszhao'};

thisss.sayHi.call (thatt);


1
คุณควรเพิ่มคำอธิบายด้วยรหัสว่าสิ่งที่คุณทำเป็นพิเศษ
Farhana
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.