อันที่จริงนี่เป็นปัญหาที่น่าเบื่อ มีบทความมากมายเกี่ยวกับเรื่องนี้ ที่จริงแล้วฉันคิดว่าฉันคิดออก แต่เมื่อวานนี้ฉันยังมีข้อสงสัยเล็กน้อยในระหว่างโครงการ ฉันคิดถึงบทความโดยละเอียดที่ฉันได้รวบรวมและอ่านใน JavaScript Weekly (มีลิงค์ในภายหลังและการแปลภาษาจีนเกี่ยวกับ Earths Rare Earths ติดอยู่) และบทความอื่นที่แนะนำโดยผู้อาวุโสดังนั้นฉันจึงดูพวกเขาและความเข้าใจของฉันได้ดีขึ้นเล็กน้อย
'สิ่งนี้' ใน JavaScript นั้นมีไดนามิกและถูกกำหนดเมื่อฟังก์ชั่นทำงานไม่ใช่เมื่อมีการประกาศฟังก์ชั่น ฟังก์ชั่นทั้งหมดสามารถเรียกได้ว่า 'สิ่งนี้' ซึ่งไม่สำคัญว่าฟังก์ชันจะเป็นของวัตถุ เกี่ยวกับเรื่องนี้ส่วนใหญ่มีสี่สถานการณ์
1. วิธีที่ใช้เป็นวัตถุเรียกว่า
หากฟังก์ชั่นเป็นวิธีที่ถือเป็นวัตถุแล้วฟังก์ชั่นนี้จะชี้ไปที่วัตถุ
var john = {firstName: "john"} ฟังก์ชั่น func () {alert (this.firstname + ": hi!")} john.sayhi = func john.sayhi () // this = Johnมีบางสิ่งที่น่าสังเกตที่นี่ เมื่อวิธีการของวัตถุถูกนำออกและกำหนดให้กับตัวแปรวิธีการจะกลายเป็นทริกเกอร์ฟังก์ชั่นและชี้ไปที่หน้าต่างหรือ underfind (โหมดที่เข้มงวด)
2. โทรภายในฟังก์ชั่น
เมื่อฟังก์ชั่นนี้มีสิ่งนี้มันหมายความว่ามันถูกเรียกว่าเป็นวิธีการ การโทรระหว่างทั้งสองนั้นเทียบเท่ากับการถือว่าเป็นวัตถุหน้าต่าง ชี้ไปที่หน้าต่าง เป็นที่น่าสังเกตว่า ES5 กำหนดว่าสิ่งนี้ = ไม่ได้กำหนดและเบราว์เซอร์เท่านั้นที่ยังคงดำเนินการตามวิธีเก่า (ฉันทดสอบในรุ่นล่าสุดของ Chrome, Safari และ Firefox ทั้งหมดชี้ไปที่ Window (201607)) และใช้โหมดที่เข้มงวด
ฟังก์ชั่น func () func () {แจ้งเตือน (นี่) // [หน้าต่างวัตถุ] หรือ [วัตถุทั่วโลก] หรือชนิดของ .. }ในการผ่านสิ่งนี้ () ควรเป็นประเภทอ้างอิงมาก่อนคล้ายกับ obj.a หรือ obj ['a'] และไม่สามารถเป็นอย่างอื่นได้
นอกจากนี้ยังมีหลุมเล็ก ๆ ที่นี่ เมื่อมีฟังก์ชั่นในวิธีการของวัตถุฟังก์ชั่นจะถูกทริกเกอร์เป็นโหมดฟังก์ชันดังนั้นค่าเริ่มต้นนี้ไปยังหน้าต่าง (ไม่ได้กำหนดในโหมดที่เข้มงวด) วิธีแก้ปัญหาคือการผูกสิ่งนี้กับฟังก์ชั่น
var numbers = {numbera: 5, numberb: 10, sum: function () {console.log (นี่ === ตัวเลข); // => ฟังก์ชั่นจริงคำนวณ () {// นี่คือหน้าต่างหรือไม่ได้กำหนดในโหมดคอนโซลที่เข้มงวด log (นี่ === ตัวเลข); // => เท็จส่งคืนสิ่งนี้ numbera + this.numberb; } return calculate (); }}; numbers.sum (); // => nan หรือพ่น typeerror ในโหมดที่เข้มงวด var numbers = {numbera: 5, numberb: 10, ผลรวม: function () {console.log (นี่ === ตัวเลข); // => ฟังก์ชั่นจริงคำนวณ () {console.log (นี่ === ตัวเลข); // => true return this.numbera + this.numberb; } // ใช้. call () เมธอดเพื่อแก้ไขบริบท return calculate.call (this); }}; numbers.sum (); // => 153. โทรใหม่
ตัวแปรที่อ้างอิงวัตถุจริงบันทึกการอ้างอิงไปยังวัตถุนั่นคือตัวแปรจริงจะบันทึกตัวชี้ไปยังข้อมูลจริง
เมื่อใช้คำหลักใหม่การเปลี่ยนแปลงนี้จะใช้ขั้นตอนต่อไปนี้:
สร้างสิ่งนี้ = {}
สิ่งนี้อาจเปลี่ยนแปลงได้ในระหว่างการดำเนินการใหม่จากนั้นคุณลักษณะและวิธีการจะถูกเพิ่มเข้ามา;
ส่งคืนสิ่งนี้เปลี่ยนไป
ฟังก์ชั่นสัตว์ (ชื่อ) {this.name = ชื่อ this.canwalk = true} var iment = สัตว์ใหม่ ("Beastie") การแจ้งเตือน (Animal.name)ควรสังเกตว่าหากคอนสตรัคเตอร์ส่งคืนวัตถุแล้วจะชี้ไปที่วัตถุที่ส่งคืน
ฟังก์ชัน Animal () {this.name = 'mousie'; this.age = '18'; return {ชื่อ: 'godzilla'} // <- จะถูกส่งคืน} var iment = สัตว์ใหม่ () console.log (iment.name) // godzilla console.log (iment.age) // undefinedเป็นสิ่งสำคัญที่จะต้องทราบที่นี่ที่อย่าลืมใช้ใหม่มิฉะนั้นจะไม่สร้างฟังก์ชั่นใหม่ แต่เพียงแค่เรียกใช้ฟังก์ชันซึ่งเทียบเท่ากับการเรียกใช้ฟังก์ชันและสิ่งนี้ชี้ไปที่หน้าต่างจริง
ฟังก์ชั่นยานพาหนะ (ประเภท, wheelscount) {this.type = type; this.wheelscount = wheelscount; ส่งคืนสิ่งนี้;} // function invocationVar Car = ยานพาหนะ ('Car', 4); car.type; // => 'car' car.wheelscount // => 4 car === window // => true4. โทรอย่างชัดเจนใช้การโทรและสมัคร
นี่เป็นสถานที่ที่ได้รับแรงบันดาลใจจาก JavaScript มากที่สุด
รหัสต่อไปนี้:
func.call(obj, arg1, arg2,...)
พารามิเตอร์แรกจะถูกใช้เป็นวัตถุอ้างอิงของสิ่งนี้และพารามิเตอร์ที่ตามมาจะถูกใช้เป็นพารามิเตอร์ของฟังก์ชัน วิธีแก้ปัญหาคือใช้การผูก
ฟังก์ชั่นสัตว์ (ประเภท, ขา) {this.type = type; this.legs = ขา; this.loginfo = function () {console.log (this === mycat); // => True Console.log ('The' + this.type + 'มี' + this.legs + 'ขา'); };} var mycat = สัตว์ใหม่ ('แมว', 4); // บันทึก "แมวมี 4 ขา" settimeout (mycat.loginfo.bind (MyCat), 1,000); // settimeout ?? var john = {firstName: "John", เหตุการณ์: "Smith"} ฟังก์ชั่น func (a, b) {alert (นี่ [a] + '' + this [b])} func.call (John, 'FirstName', 'นามสกุล') // "John Smith"สำหรับการใช้งานมันผ่านพารามิเตอร์ในจัตุรัสของอาร์เรย์และส่วนอื่น ๆ ก็เหมือนกันดังนี้:
Func.call (John, 'FirstName', 'Surname') Func.apply (John, ['FirstName', 'นามสกุล'])))))
พวกเขายังสามารถใช้ในการสืบทอดคลาสใน ES5 เพื่อเรียกตัวสร้างหลัก
ฟังก์ชั่น runner (ชื่อ) {console.log (อินสแตนซ์ของกระต่ายนี้); // => จริง this.name = name; } ฟังก์ชั่นกระต่าย (ชื่อ, countlegs) {console.log (อินสแตนซ์ของกระต่ายอินสแตนซ์นี้); // => true // ที่เรียกว่าทางอ้อมตัวสร้าง parent constructor runner.call (ชื่อนี้); this.countlegs = countlegs; } var myrabbit = กระต่ายใหม่ ('กระต่ายสีขาว', 4); Myrabbit; // {ชื่อ: 'White Rabbit', Countlegs: 4}5.. -bind ()
เปรียบเทียบวิธีการ. APPPLY () และ. call () ซึ่งทั้งสองอย่างจะดำเนินการฟังก์ชั่นทันทีในขณะที่ฟังก์ชัน. -bind () ส่งคืนวิธีการใหม่ที่ผูกมัดการระบุไว้ล่วงหน้านี้และสามารถชะลอการโทรได้
ฟังก์ชั่นของวิธี. bind () คือการสร้างฟังก์ชั่นใหม่ บริบทในระหว่างการดำเนินการเป็นพารามิเตอร์แรกที่ส่งผ่านโดย. -bind () ซึ่งอนุญาตให้สร้างฟังก์ชั่นที่มีการตั้งค่าไว้ล่วงหน้านี้
var numbers = {array: [3, 5, 10], getNumbers: function () {return this.array; }}; // สร้าง functionvar boundgetNumbers = number.getNumbers.bind (ตัวเลข); BoundgetNumbers (); // => [3, 5, 10] // วิธีการแยกจาก ObjectVar SimpleGetNumbers = number.getNumbers; SimplegetNumbers (); // => ไม่ได้กำหนดหรือส่งข้อผิดพลาดในโหมดเข้มงวดเมื่อใช้. bind () คุณควรทราบว่า. -bind () สร้างห่วงโซ่บริบทนิรันดร์และไม่สามารถแก้ไขได้ แม้ว่าฟังก์ชั่นการผูกมัดจะใช้. call () หรือ. apply () เพื่อส่งผ่านไปยังบริบทที่แตกต่างกันอื่น ๆ มันจะไม่เปลี่ยนบริบทของการเชื่อมต่อก่อนหน้านี้และการรีคืนจะไม่มีบทบาทใด ๆ
เฉพาะเมื่อมีการเรียกตัวสร้างเท่านั้นฟังก์ชั่นการเชื่อมโยงสามารถเปลี่ยนบริบทได้ แต่นี่ไม่ใช่วิธีการที่แนะนำเป็นพิเศษ
6. ฟังก์ชั่นลูกศร
ฟังก์ชั่นลูกศรไม่ได้สร้างบริบทของการดำเนินการของตัวเองซึ่งขึ้นอยู่กับฟังก์ชั่นภายนอกที่กำหนดไว้ในเวลาที่นิยาม
ฟังก์ชั่นลูกศรไม่สามารถเปลี่ยนแปลงได้หลังจากผูกบริบทหนึ่งครั้งแม้ว่าจะใช้วิธีการเปลี่ยนแปลงบริบท:
หมายเลข var = [1, 2]; (function () {var get = () => {console.log (นี่ === ตัวเลข); // => การส่งคืนจริงนี้;}; console.log (นี่ === numbers); // => true get (); // => [1, 2] // // => [1, 2] // bind get.bind ([0]) ();นี่เป็นเพราะฟังก์ชั่นลูกศรมีบริบทคงที่และจะไม่เปลี่ยนแปลงเนื่องจากการโทรที่แตกต่างกัน ดังนั้นอย่าใช้ฟังก์ชั่นลูกศรเพื่อกำหนดวิธีการ
ระยะเวลาฟังก์ชั่น (ชั่วโมง, นาที) {this.hours = ชั่วโมง; this.minutes = นาที; } period.prototype.format = () => {console.log (this === หน้าต่าง); // => true return this.hours + 'ชั่วโมงและ' + this.minutes + 'นาที'; - var walkperiod = ช่วงเวลาใหม่ (2, 30); walkperiod.format (); // => 'ชั่วโมงที่ไม่ได้กำหนดและนาทีที่ไม่ได้กำหนด'อ้างถึง
กลิ่นสี่อันของ "สิ่งนี้"
คำอธิบายที่อ่อนโยนของคำหลัก 'นี้' ใน JavaScript
JavaScript ความลึกลับนี้ (แปล)
ขอแนะนำอย่างยิ่งให้นักเรียนที่ไม่เข้าใจ ตรวจสอบบทความสามบทความข้างต้นบทความที่สามคือการแปลของบทความที่สอง หากคุณมีคำถามใด ๆ เกี่ยวกับเรื่องนี้คุณสามารถพูดคุยร่วมกันสื่อสารและส่งเสริมการคิดและดำเนินการด้วยกัน