ฉันขุดลึกเพื่อทำความเข้าใจพฤติกรรมเฉพาะนี้และฉันคิดว่าฉันได้พบคำอธิบายที่ดี
ก่อนที่ฉันจะอธิบายถึงสาเหตุที่คุณไม่สามารถใช้นามแฝง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เมธอดถูกเรียกด้วยdaveas thisobject ในขณะที่ JavaScript ไม่สามารถกำหนด 'ขอบเขต' สำหรับageMethodการดำเนินการได้ ดังนั้นมันจึงผ่าน 'Window' ทั่วโลกเป็น 'this' ขณะนี้windowไม่มีbirthDateคุณสมบัติageMethodการดำเนินการจะล้มเหลว
จะแก้ไขได้อย่างไร? เรียบง่าย
ageMethod.apply(dave);
ทั้งหมดข้างต้นสมเหตุสมผลหรือไม่? หากเป็นเช่นนั้นคุณจะสามารถอธิบายได้ว่าเหตุใดคุณจึงไม่สามารถใช้นามแฝงได้document.getElementById:
var $ = document.getElementById;
$('someElement');
$ถูกเรียกด้วยwindowas 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วัตถุและเอาท์พุทthis100
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ได้ :)