คำว่า "หลุม" หมายถึง "กับดัก" เนื่องจากลักษณะของ "ภาษาที่อ่อนแอ" ของ JavaScript จึงมีความยืดหยุ่นและยืดหยุ่นในระหว่างการใช้งาน แต่มันก็ง่ายมากที่จะ "ถูกตี" หลุมเหล่านี้มักจะถูกซ่อนไว้ดังนั้นคุณต้องเปิดตาเพื่อการแล่นเรือใบที่ราบรื่นบนถนนแห่งการเรียนรู้และการใช้ JS
1. ตัวแปรทั่วโลก
JavaScript จัดการขอบเขตผ่านฟังก์ชั่น ตัวแปรที่ประกาศภายในฟังก์ชั่นนั้นอยู่ในฟังก์ชั่นนี้เท่านั้นและไม่สามารถใช้งานได้นอกฟังก์ชั่น ในทางกลับกันตัวแปรทั่วโลกจะถูกประกาศนอกฟังก์ชั่นใด ๆ หรือใช้ง่ายๆและไม่มีการประกาศ
"ใช้มันง่ายๆโดยไม่ต้องประกาศ" หมายความว่าตัวแปรจะถูกประกาศโดยไม่ต้องใช้คำหลัก VAR เราได้ทำให้ชัดเจนแล้วว่าวิธีที่จะหลีกเลี่ยงการสร้างตัวแปรทั่วโลกโดยปริยายคือการประกาศตัวแปรด้วยคำหลัก VAR ให้มากที่สุด
แต่คุณคิดว่ามันโอเคที่จะใช้ VAR หรือไม่? มาดูหลุมนี้กันเถอะ:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น foo () {
var a = b = 0;
// ร่างกาย...
-
บางทีสิ่งที่คุณคาดหวังคือตัวแปรท้องถิ่นสองตัว แต่ B เป็นตัวแปรระดับโลกที่แท้จริง ทำไม เนื่องจากการดำเนินการที่ได้รับมอบหมายนั้นมาจากขวาไปซ้ายดังนั้นจึงเทียบเท่ากับ:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น foo () {
var a = (b = 0);
// ร่างกาย...
-
ดังนั้น B จึงเป็นตัวแปรระดับโลก
เติมในหลุม: การประกาศตัวแปรที่ดีที่สุดคือการมาทีละคนอย่าทำขายส่ง ~ _ ~;
2. การประกาศตัวแปร
มาดูหลุมก่อน:
การคัดลอกรหัสมีดังนี้:
myName = "Global";
ฟังก์ชั่น foo () {
การแจ้งเตือน (myname);
var myname = "local";
การแจ้งเตือน (myname);
-
foo ();
เมื่อมองแวบแรกเราคาดว่าจะคาดหวังว่าผลลัพธ์ของการแจ้งเตือนสองครั้งจะเป็น "ระดับโลก" และ "ท้องถิ่น" ตามลำดับ แต่ผลลัพธ์ที่แท้จริงคือ "ไม่ได้กำหนด" และ "ท้องถิ่น" ทำไม เนื่องจากตัวแปรถูกประกาศในขอบเขตเดียวกัน (ฟังก์ชั่นเดียวกัน) และจะถูกแยกวิเคราะห์ครั้งแรกโดยด้านบนของขอบเขต
ดังนั้นพฤติกรรมการดำเนินการของตัวอย่างโค้ดด้านบนอาจมีลักษณะเช่นนี้:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น foo () {
var myname;
การแจ้งเตือน (myname); // "ไม่ได้กำหนด"
myName = "local";
การแจ้งเตือน (myname); // "ท้องถิ่น"
-
ใช้หลุมอื่นเพื่อทดสอบว่าคุณเข้าใจก่อนการเดินทางหรือไม่:
การคัดลอกรหัสมีดังนี้:
ถ้า (! ("a" ในหน้าต่าง)) {
var a = 1;
-
การแจ้งเตือน (a);
การประกาศของตัวแปรนั้นสูงขึ้นไปด้านบนของรหัสและยังไม่ได้รับมอบหมาย ถัดไปป้อนคำสั่ง IF และตัดสินว่า "A" ในหน้าต่างถูกจัดตั้งขึ้น (A ได้รับการประกาศว่าเป็นตัวแปรระดับโลก) ดังนั้นผลการคำนวณคำสั่งการตัดสินจึงเป็นเท็จและคำสั่ง IF จะกระโดดออกมาดังนั้นมูลค่าของ A จึงไม่ได้กำหนด
การคัดลอกรหัสมีดังนี้:
var a; // "ไม่ได้กำหนด"
console.log ("a" ในหน้าต่าง); // จริง
ถ้า (! ("a" ในหน้าต่าง)) {
var a = 1; // ไม่ได้ดำเนินการ
-
การแจ้งเตือน (a); // "ไม่ได้กำหนด"
เติมในหลุม: เป็นการดีที่สุดที่จะวางประกาศตัวแปรที่ด้านบนของขอบเขต สำหรับตัวแปรที่ไม่สามารถกำหนดได้ในขณะนี้คุณสามารถใช้วิธีการประกาศก่อนแล้วจึงกำหนดค่า
3. การประกาศฟังก์ชั่น
การประกาศของฟังก์ชั่นนั้นยังสูงขึ้นไปสู่ด้านบนของขอบเขตและจะถูกแยกวิเคราะห์และประเมินผลก่อนการแสดงออกและข้อความใด ๆ จะถูกแยกวิเคราะห์และประเมินผล
การคัดลอกรหัสมีดังนี้:
การแจ้งเตือน (typeof foo); // "การทำงาน"
ฟังก์ชั่น foo () {
// ร่างกาย...
-
คุณสามารถเปรียบเทียบได้:
การคัดลอกรหัสมีดังนี้:
การแจ้งเตือน (typeof foo); // "ไม่ได้กำหนด"
var foo = function () {
// ร่างกาย...
-
หากคุณเข้าใจหลักการนี้คุณจะยังคงตกอยู่ในข้อผิดพลาดต่อไปนี้หรือไม่?
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นทดสอบ () {
การแจ้งเตือน ("1");
-
ทดสอบ();
ฟังก์ชั่นทดสอบ () {
การแจ้งเตือน ("2");
-
ทดสอบ();
เมื่อเรียกใช้ตัวอย่างโค้ดด้านบนหน้าต่างป๊อปอัพที่คุณเห็นคือ "2" ทำไมพวกเขาถึงไม่ "1" และ "2" ตามลำดับ? มันง่ายมากการประกาศการทดสอบจะถูกแยกวิเคราะห์ก่อนการทดสอบ () เนื่องจากหลังแทนที่อดีตผลลัพธ์ของการประหารชีวิตทั้งสองคือ "2"
เติมในหลุม: ในกรณีส่วนใหญ่ฉันใช้การแสดงออกของฟังก์ชั่นแทนการประกาศฟังก์ชั่นโดยเฉพาะอย่างยิ่งในบางบล็อกคำสั่ง
4. การแสดงออกของฟังก์ชั่น
มาดูนิพจน์ฟังก์ชั่นที่มีชื่อก่อน แน่นอนว่าต้องมีชื่อตัวอย่างเช่น:
คัดลอกรหัสดังนี้: var bar = function foo () {
// ร่างกาย...
-
ควรสังเกตว่าชื่อฟังก์ชั่นจะปรากฏเฉพาะฟังก์ชั่นภายใน เช่นข้อผิดพลาดต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
var bar = function foo () {
foo (); // วิ่งตามปกติ
-
foo (); // ข้อผิดพลาด: ReferenceRor
กรอกข้อมูลในหลุม: พยายามใช้นิพจน์ฟังก์ชั่นที่มีชื่อให้น้อยที่สุด (ยกเว้นการเรียกซ้ำและการดีบักบางอย่าง) และอย่าใช้ชื่อฟังก์ชั่นภายนอก
5. ฟังก์ชั่น execution
สำหรับการแสดงออกของฟังก์ชั่นคุณสามารถดำเนินการได้โดยการเพิ่ม () หลังจากนั้นและพารามิเตอร์สามารถส่งผ่านในวงเล็บในขณะที่การประกาศฟังก์ชั่นไม่สามารถทำได้ หลุม:
การคัดลอกรหัสมีดังนี้:
// (1) นี่เป็นเพียงตัวดำเนินการจัดกลุ่มไม่ใช่การเรียกใช้ฟังก์ชัน!
// ดังนั้นฟังก์ชั่นที่นี่ยังไม่ถูกดำเนินการมันยังคงเป็นคำสั่ง
ฟังก์ชั่น foo (x) {
การแจ้งเตือน (x);
} (1);
ตัวอย่างโค้ดต่อไปนี้จะถูกดำเนินการแยกกันและหน้าต่างป๊อปอัพแสดง "1" เพราะก่อนหน้า (1) พวกเขาเป็นนิพจน์ฟังก์ชั่นดังนั้น () ที่นี่ไม่ใช่ตัวดำเนินการจัดกลุ่ม แต่เป็นตัวดำเนินการซึ่งระบุการเรียกใช้การโทร
คัดลอกรหัสดังนี้: // นิพจน์ฟังก์ชั่นที่ไม่ระบุชื่อมาตรฐานมาตรฐาน
var bar = function foo (x) {
การแจ้งเตือน (x);
} (1);
// ก่อนหน้า () แปลงการประกาศฟังก์ชันเป็นนิพจน์
(ฟังก์ชั่น foo (x) {
การแจ้งเตือน (x);
}) (1);
// ทั้งหมด () เป็นนิพจน์
(ฟังก์ชั่น foo (x) {
การแจ้งเตือน (x);
} (1));
// นิพจน์ใหม่
ฟังก์ชั่นใหม่ foo (x) {
การแจ้งเตือน (x);
} (1);
// &&, ||,!, +, -, ~ ฯลฯ ผู้ประกอบการ (และเครื่องหมายจุลภาค) เพื่อแสดงการแสดงออกของฟังก์ชั่นและการประกาศฟังก์ชั่น
// ดังนั้นเมื่อตัวแยกวิเคราะห์รู้ว่าหนึ่งในนั้นคือนิพจน์คนอื่น ๆ ก็จะเริ่มต้นการแสดงออก
true && function foo (x) {
การแจ้งเตือน (x);
} (1);
เติมหลุม: กุญแจสู่หลุมนี้คือการหาสาระสำคัญของการแสดงออกของฟังก์ชั่นทุกชนิด
6. ปิดในวง
ต่อไปนี้แสดงให้เห็นถึงข้อผิดพลาดทั่วไป:
การคัดลอกรหัสมีดังนี้:
<! doctype html>
<html lang = "en">
<head>
<meta charset = "utf-8">
<title> เอกสาร </title>
</head>
<body>
<H3> เมื่อคลิกลิงก์ด้านล่างแสดงจำนวนลำดับ </h3>
<ul>
<li> <a href = " #"> ลิงค์ #0 </a> </li>
<li> <a href = " #"> ลิงค์ #1 </a> </li>
<li> <a href = " #"> ลิงค์ #2 </a> </li>
<li> <a href = " #"> ลิงค์ #3 </a> </li>
<li> <a href = " #"> ลิงค์ #4 </a> </li>
</ul>
</body>
</html>
การคัดลอกรหัสมีดังนี้:
var links = document.getElementsByTagname ("ul") [0] .getElementsByTagname ("A");
สำหรับ (var i = 0, l = links.length; i <l; i ++) {
ลิงก์ [i] .onclick = ฟังก์ชั่น (e) {
E.preventDefault ();
การแจ้งเตือน ("คุณคลิกลิงก์ #" + i);
-
-
เราคาดหวังว่าเมื่อคลิกที่ลิงค์ I-TH เราจะได้รับค่าของดัชนี I ในลำดับนี้ อย่างไรก็ตามไม่ว่าจะมีการคลิกลิงก์ใดเราจะได้ผลลัพธ์สุดท้ายของฉันหลังจากลูป: "5"
อธิบายเหตุผล: เมื่อมีการเรียกการแจ้งเตือนการแสดงออกของฟังก์ชันที่ไม่ระบุชื่อใน For Loop ยังคงอ้างอิงถึงตัวแปรภายนอก I (ปิด) ในเวลานี้ลูปสิ้นสุดลงและค่าของฉันได้รับการแก้ไขเป็น "5"
กรอกข้อมูลในหลุม: เพื่อให้ได้ผลลัพธ์ที่ต้องการคุณต้องสร้างสำเนาของตัวแปร I ในแต่ละลูป ต่อไปนี้แสดงให้เห็นถึงวิธีการที่ถูกต้อง:
การคัดลอกรหัสมีดังนี้:
<head>
<meta charset = "utf-8">
<title> เอกสาร </title>
</head>
<body>
<H3> เมื่อคลิกลิงก์ด้านล่างแสดงจำนวนลำดับ </h3>
<ul>
<li> <a href = " #"> ลิงค์ #0 </a> </li>
<li> <a href = " #"> ลิงค์ #1 </a> </li>
<li> <a href = " #"> ลิงค์ #2 </a> </li>
<li> <a href = " #"> ลิงค์ #3 </a> </li>
<li> <a href = " #"> ลิงค์ #4 </a> </li>
</ul>
</body>
</html>
การคัดลอกรหัสมีดังนี้:
var links = document.getElementsByTagname ("ul") [0] .getElementsByTagname ("A");
สำหรับ (var i = 0, l = links.length; i <l; i ++) {
ลิงก์ [i] .onclick = (ฟังก์ชั่น (ดัชนี) {
ฟังก์ชั่น return (e) {
E.preventDefault ();
การแจ้งเตือน ("คุณคลิกลิงก์ #" + ดัชนี);
-
})(ฉัน);
-
อย่างที่คุณเห็นรูปแบบของ (function () {... }) () คือการตรวจสอบด้วยตนเองของฟังก์ชั่นที่กล่าวถึงข้างต้น ฉันถูกส่งผ่านไปยังดัชนีเป็นพารามิเตอร์ เมื่อการแจ้งเตือนดำเนินการอีกครั้งจะมีการอ้างอิงถึงดัชนี ในเวลานี้ค่านี้จะไม่เปลี่ยนแปลงโดยลูป แน่นอนหลังจากทำความเข้าใจหลักการแล้วคุณยังสามารถเขียนเช่นนี้:
การคัดลอกรหัสมีดังนี้:
สำหรับ (var i = 0, l = links.length; i <l; i ++) {
(ฟังก์ชั่น (ดัชนี) {
ลิงก์ [i] .onclick = ฟังก์ชั่น (e) {
E.preventDefault ();
การแจ้งเตือน ("คุณคลิกลิงก์ #" + ดัชนี);
-
})(ฉัน);
-
มันใช้งานได้เช่นกัน