ฉันขุดลึกเพื่อทำความเข้าใจพฤติกรรมเฉพาะนี้และฉันคิดว่าฉันได้พบคำอธิบายที่ดี
ก่อนที่ฉันจะอธิบายถึงสาเหตุที่คุณไม่สามารถใช้นามแฝงdocument.getElementById
ได้ฉันจะพยายามอธิบายว่าฟังก์ชัน / วัตถุ JavaScript ทำงานอย่างไร
เมื่อใดก็ตามที่คุณเรียกใช้ฟังก์ชัน JavaScript ตัวแปล JavaScript จะกำหนดขอบเขตและส่งผ่านไปยังฟังก์ชัน
พิจารณาฟังก์ชันต่อไปนี้:
function sum(a, b)
{
return a + b;
}
sum(10, 20);
ฟังก์ชันนี้ถูกประกาศในขอบเขตของหน้าต่างและเมื่อคุณเรียกใช้ค่าthis
ภายในฟังก์ชัน sum จะเป็นโกลบอลWindow
อ็อบเจ็กต์
สำหรับฟังก์ชัน 'sum' ไม่สำคัญว่าค่าของ 'this' จะเป็นเท่าใดเนื่องจากไม่ได้ใช้งาน
พิจารณาฟังก์ชันต่อไปนี้:
function Person(birthDate)
{
this.birthDate = birthDate;
this.getAge = function() { return new Date().getFullYear() - this.birthDate.getFullYear(); };
}
var dave = new Person(new Date(1909, 1, 1));
dave.getAge();
เมื่อคุณเรียกใช้ฟังก์ชัน dave.getAge, ล่าม JavaScript เห็นว่าคุณกำลังเรียกใช้ฟังก์ชัน getAge บนdave
วัตถุจึงกำหนดthis
ไปdave
และเรียกgetAge
ฟังก์ชั่น ได้อย่างถูกต้องจะกลับมาgetAge()
100
คุณอาจทราบว่าใน JavaScript คุณสามารถระบุขอบเขตโดยใช้apply
วิธีการ ลองดูสิ
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
dave.getAge.apply(bob);
ในบรรทัดด้านบนแทนที่จะปล่อยให้ JavaScript ตัดสินใจขอบเขตคุณกำลังส่งผ่านขอบเขตด้วยตนเองเป็นbob
ออบเจ็กต์ getAge
ตอนนี้จะกลับมา200
แม้ว่าคุณจะ 'คิดว่า' เรียกร้องgetAge
สิ่งdave
นั้นก็ตาม
ประเด็นทั้งหมดข้างต้นคืออะไร? ฟังก์ชั่นถูกแนบ 'อย่างหลวม ๆ ' กับวัตถุ JavaScript ของคุณ เช่นคุณสามารถทำได้
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
bob.getAge = function() { return -1; };
bob.getAge();
dave.getAge();
มาทำขั้นตอนต่อไป
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge();
ageMethod();
ageMethod
การดำเนินการเกิดข้อผิดพลาด! เกิดอะไรขึ้น?
หากคุณอ่านประเด็นข้างต้นของฉันอย่างละเอียดคุณจะทราบว่าdave.getAge
เมธอดถูกเรียกด้วยdave
as this
object ในขณะที่ JavaScript ไม่สามารถกำหนด 'ขอบเขต' สำหรับageMethod
การดำเนินการได้ ดังนั้นมันจึงผ่าน 'Window' ทั่วโลกเป็น 'this' ขณะนี้window
ไม่มีbirthDate
คุณสมบัติageMethod
การดำเนินการจะล้มเหลว
จะแก้ไขได้อย่างไร? เรียบง่าย
ageMethod.apply(dave);
ทั้งหมดข้างต้นสมเหตุสมผลหรือไม่? หากเป็นเช่นนั้นคุณจะสามารถอธิบายได้ว่าเหตุใดคุณจึงไม่สามารถใช้นามแฝงได้document.getElementById
:
var $ = document.getElementById;
$('someElement');
$
ถูกเรียกด้วยwindow
as this
และหากgetElementById
คาดว่าthis
จะใช้document
งานได้ก็จะล้มเหลว
อีกครั้งเพื่อแก้ไขปัญหานี้คุณสามารถทำได้
$.apply(document, ['someElement']);
เหตุใดจึงใช้งานได้ใน Internet Explorer
ผมไม่ทราบว่าการดำเนินการภายในของgetElementById
ใน IE แต่ความคิดเห็นในแหล่ง jQuery ( inArray
วิธีการดำเนินการ) window == document
กล่าวว่าใน หากเป็นเช่นนั้นนามแฝงdocument.getElementById
ควรใช้งานได้ใน IE
เพื่ออธิบายเพิ่มเติมฉันได้สร้างตัวอย่างที่ซับซ้อน ดูPerson
ฟังก์ชั่นด้านล่าง
function Person(birthDate)
{
var self = this;
this.birthDate = birthDate;
this.getAge = function()
{
if(this.constructor == Person)
return new Date().getFullYear() - this.birthDate.getFullYear();
else
return -1;
};
this.getAgeSmarter = function()
{
return self.getAge();
};
this.getAgeSmartest = function()
{
var scope = this.constructor == Person ? this : self;
return scope.getAge();
};
}
สำหรับPerson
ฟังก์ชันข้างต้นนี่คือวิธีการgetAge
ทำงานของเมธอดต่างๆ
มาสร้างวัตถุสองชิ้นโดยใช้Person
ฟังก์ชัน
var yogi = new Person(new Date(1909, 1,1));
var anotherYogi = new Person(new Date(1809, 1, 1));
console.log(yogi.getAge());
ตรงไปตรงมา, วิธีการ getAge ได้รับyogi
วัตถุและเอาท์พุทthis
100
var ageAlias = yogi.getAge;
console.log(ageAlias());
JavaScript ชุด interepreter window
วัตถุเป็นthis
ของเราและวิธีการที่จะกลับมาgetAge
-1
console.log(ageAlias.apply(yogi));
หากเรากำหนดขอบเขตที่ถูกต้องคุณสามารถใช้ageAlias
วิธีการ
console.log(ageAlias.apply(anotherYogi));
ถ้าเราผ่านวัตถุของคนอื่นมันจะยังคำนวณอายุได้อย่างถูกต้อง
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias());
ageSmarter
ฟังก์ชั่นบันทึกเดิมthis
วัตถุดังนั้นตอนนี้คุณไม่ต้องกังวลเกี่ยวกับการจัดหาขอบเขตที่ถูกต้อง
console.log(ageSmarterAlias.apply(anotherYogi));
ปัญหาageSmarter
คือคุณไม่สามารถกำหนดขอบเขตให้กับวัตถุอื่นได้
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias());
console.log(ageSmartestAlias.apply(document));
ageSmartest
ฟังก์ชั่นจะใช้ขอบเขตเดิมถ้าขอบเขตที่ไม่ถูกต้องเป็นที่จัดทำ
console.log(ageSmartestAlias.apply(anotherYogi));
คุณจะยังส่งPerson
วัตถุอื่นไปยังgetAgeSmartest
ได้ :)