เหตุใดการเรียกใช้ฟังก์ชันบางอย่างจึงเรียกว่า "การเรียกใช้ที่ผิดกฎหมาย" ใน JavaScript


97

ตัวอย่างเช่นถ้าฉันทำสิ่งนี้:

var q = document.querySelectorAll;

q('body');

ฉันได้รับข้อผิดพลาด "การร้องขอที่ผิดกฎหมาย" ใน Chrome ฉันคิดไม่ออกว่าทำไมถึงจำเป็น ประการแรกไม่ใช่กรณีของฟังก์ชันโค้ดเนทีฟทั้งหมด อันที่จริงฉันสามารถทำได้:

var o = Object; // which is a native code function

var x = new o();

และทุกอย่างทำงานได้ดี โดยเฉพาะอย่างยิ่งฉันได้ค้นพบปัญหานี้เมื่อจัดการกับเอกสารและคอนโซล ความคิดใด ๆ ?




คำตอบ:


158

เป็นเพราะคุณสูญเสีย "บริบท" ของฟังก์ชันไป

เมื่อคุณโทร:

document.querySelectorAll()

บริบทของฟังก์ชันคือdocumentและจะสามารถเข้าถึงได้thisโดยการใช้วิธีการนั้น

เมื่อคุณเรียกqว่าไม่มีบริบทอีกต่อไป แต่จะเป็นwindowวัตถุ"global" แทน

การใช้งานquerySelectorAllพยายามใช้thisแต่ไม่ใช่องค์ประกอบ DOM อีกต่อไป แต่เป็นWindowวัตถุ การนำไปใช้งานพยายามเรียกวิธีการบางอย่างขององค์ประกอบ DOM ที่ไม่มีอยู่ในWindowอ็อบเจ็กต์และล่ามเรียกว่าไม่น่าแปลกใจ

ในการแก้ไขปัญหานี้ให้ใช้.bindJavascript เวอร์ชันใหม่กว่า:

var q = document.querySelectorAll.bind(document);

ซึ่งจะช่วยให้มั่นใจได้ว่าการเรียกใช้ในภายหลังทั้งหมดqมีบริบทที่ถูกต้อง หากคุณยังไม่มี.bindให้ใช้สิ่งนี้:

function q() {
    return document.querySelectorAll.apply(document, arguments);
}

3
โอ้ดีโทร. คุณพูดถูกเพราะฉันทำได้: q.apply (document, ['body']); และใช้งานได้
user1152187

โปรดทราบว่าสิ่งนี้ไม่จำเป็นสำหรับฟังก์ชันที่มีอยู่แล้วใน IE ตัวอย่างเช่น console.log ไม่มีวิธีใช้ที่นั่น
hugomg

@Alnitak: ใช่มันใช้งานได้ทุกที่ยกเว้น IE และเป็นเหตุผลที่คุณควรส่งผ่านข้อโต้แย้งที่เป็นปกติเช่นเดียวกับในfunction q(x){ return document.querySelectorAll(x); }. อีกสิ่งหนึ่งที่ฉันชอบเกี่ยวกับออบเจ็กต์เบราว์เซอร์ IE ก็คือบางชิ้นมีข้อยกเว้นหากคุณพยายามอ่านคุณสมบัติจากพวกเขาดังนั้นคุณต้องทดสอบคุณสมบัติด้วยif( 'funcname' in browserobject)แทนที่จะเป็นแบบปกติif(browserobject.funcname)!
hugomg

คำตอบที่ยอดเยี่ยมฉันรู้สึกสับสนกับปรากฏการณ์นี้สถานการณ์เดียวกับ OP
Temporary_user_name

1
ใจเป่า ขอบคุณ.
rb-

1

ในกรณีของฉันการเรียกใช้ที่ผิดกฎหมายเกิดขึ้นเนื่องจากการส่งผ่านตัวแปรที่ไม่ได้ประกาศเพื่อทำหน้าที่เป็นอาร์กิวเมนต์ อย่าลืมประกาศตัวแปรก่อนส่งผ่านไปยังฟังก์ชัน


การประกาศตัวแปรจะไม่สมเหตุสมผลกับกรณีนี้เนื่องจากการเรียกใช้ที่ผิดกฎหมายกำลังเกิดขึ้นเนื่องจากวิธีการขึ้นอยู่กับ Dom ถูกเรียกออกจากบริบทของ DOM เนื่องจากช่วงเวลาที่คุณทำ q = document บางsomethingวิธีจะสูญเสียบริบทของเอกสาร
Anshul Sahni


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