ขอบเขตระดับบล็อก
ES5 ไม่มีขอบเขตระดับบล็อกเฉพาะขอบเขตและขอบเขตฟังก์ชันระดับโลกเท่านั้น ด้วยเหตุนี้ขอบเขตของตัวแปรจึงกว้างมากดังนั้นคุณต้องสร้างมันทันทีทันทีที่คุณป้อนฟังก์ชั่น สิ่งนี้ทำให้ตัวแปรที่เรียกว่าเพิ่มขึ้น
คุณลักษณะ "การปรับปรุงตัวแปร" ของ ES5 มักจะทำให้เกิดข้อผิดพลาดหากคุณไม่ระวัง:
1. ตัวแปรภายในครอบคลุมตัวแปรด้านนอก
var tmp = new date (); function f () {console.log (tmp); ถ้า (false) {// ดำเนินการ undefinedvar tmp = "Hello World";}}2. การรั่วไหลของตัวแปรเป็นตัวแปรทั่วโลก
var s = 'hello'; สำหรับ (var i = 0; i <s.length; i ++) {console.log (s [i]);} console.log (i); // 5ในอดีตเรามักจะใช้การปิดเพื่อแก้ปัญหานี้ (เช่นฟังก์ชั่นการดำเนินการด้วยตนเอง) ตอนนี้ตามปัญหานี้ ES6 ได้เพิ่มขอบเขตระดับบล็อกดังนั้นจึงไม่จำเป็นต้องดำเนินการฟังก์ชั่นด้วยตัวเอง
ปล่อยและ const
ES6 นั้นเข้ากันได้ย้อนหลังและการรักษาความเข้ากันได้ย้อนหลังหมายถึงการไม่เปลี่ยนพฤติกรรมของรหัส JS บนแพลตฟอร์มเว็บดังนั้นขอบเขตของตัวแปรที่สร้างโดย VAR จะยังคงเป็นขอบเขตและขอบเขตฟังก์ชันทั่วโลก ด้วยวิธีนี้แม้ว่าคุณจะมีขอบเขตระดับบล็อก แต่ก็ไม่สามารถแก้ปัญหา "การปรับปรุงตัวแปร" ของ ES5 ได้ ดังนั้นที่นี่ ES6 ได้เพิ่มคำหลักใหม่สองคำ: Let and Const
1. ออก
"ขอให้เป็น var ที่สมบูรณ์แบบกว่า" มันมีกฎขอบเขตที่ดีกว่า
2.Const
Const ประกาศค่าคงที่แบบอ่านอย่างเดียว เมื่อประกาศแล้วค่าของค่าคงที่ไม่สามารถเปลี่ยนแปลงได้ แต่วัตถุที่ประกาศโดย const สามารถมีการเปลี่ยนแปลงคุณสมบัติ (วัตถุ freeze object.freeze)
const a = []; a.push ('สวัสดี'); // ปฏิบัติการ a = ['dave']; // รายงานข้อผิดพลาดคุณยังสามารถใช้ Object.Freeze เพื่อตรึงวัตถุ
const foo = object.freeze ({}); // ในโหมดปกติบรรทัดต่อไปนี้ไม่ทำงาน // ในโหมดที่เข้มงวดบรรทัดจะรายงานข้อผิดพลาด foo.prop = 123; //ใช้ Let and Const:
•ตัวแปรนั้นใช้ได้เฉพาะภายในขอบเขตระดับบล็อกที่มีการประกาศอยู่
•การประกาศตัวแปรสามารถใช้ได้เท่านั้น (โซนตายชั่วคราว)
•ตัวแปรไม่สามารถกำหนดได้ซ้ำ ๆ
•ตัวแปรทั่วโลกที่ประกาศคุณลักษณะที่ไม่ได้เป็นของวัตถุทั่วโลก
var a = 1; window.a // 1let b = 1; window.b // undefined
คำหลักนี้
เรารู้ว่าสิ่งนี้ในฟังก์ชั่น ES5 ชี้ไปที่ขอบเขตที่ตั้งอยู่ ตัวอย่างเช่น
function foo () {settimeout (function () {console.log ('id:', this.id);}, 100);} var id = 21; foo.call ({id: 42}); // id: 21ที่นี่ฉันประกาศฟังก์ชั่น foo ซึ่งเป็นฟังก์ชั่นการหน่วงเวลาภายในการพิมพ์ this.id ทุก ๆ 100ms เราเรียกมันว่าผ่าน foo.call ({id: 42}) และตั้งค่าขอบเขตสำหรับฟังก์ชั่นนี้ ใช้เวลา 100 มิลลิวินาทีในการดำเนินการจริง เนื่องจากจุดนี้ไปถึงขอบเขตที่อยู่ที่รันไทม์นี่ชี้ไปที่หน้าต่างวัตถุทั่วโลกไม่ใช่ฟังก์ชั่น FOO ที่นี่:
•ใช้การโทรเพื่อเปลี่ยนบริบทการดำเนินการของ FOO เพื่อให้บริบทการดำเนินการของฟังก์ชั่นไม่ใช่หน้าต่างอีกต่อไปเพื่อแยกแยะตัวชี้นี้ใน SetTimeOut
•วิธีการ settimeout ถูกแขวนไว้ใต้วัตถุหน้าต่างดังนั้นสิ่งนี้ชี้ไปที่ขอบเขตของการดำเนินการ - วัตถุหน้าต่าง
รหัสที่เรียกว่าหมดเวลาจะถูกดำเนินการในขอบเขตส่วนกลางดังนั้นค่าของสิ่งนี้ในฟังก์ชั่นชี้ไปที่วัตถุหน้าต่างในโหมดที่ไม่ใช่ Strict และไม่ได้กำหนดไว้ในโหมดที่เข้มงวด-《 JavaScript Advanced Programming》》
เพื่อแก้ปัญหานี้การปฏิบัติตามปกติของเราคือการกำหนดสิ่งนี้ให้กับตัวแปรอื่น ๆ :
function foo () {var that = this; settimeout (function () {console.log ('id:', that.id);}, 100);} var id = 21; foo.call ({id: 42}); // id: 42ตอนนี้ ES6 ได้เปิดตัวฟังก์ชั่นลูกศรเพื่อแก้ปัญหานี้
ฟังก์ชันลูกศร
ตัวระบุ => นิพจน์
var sum = (num1, num2) => {return num1 + num2; } // เทียบเท่ากับ var sum = function (num1, num2) {return num1 + num2;};•หากฟังก์ชั่นมีพารามิเตอร์เดียวสามารถละเว้นวงเล็บ
•หากฟังก์ชั่นมีคำสั่งส่งคืนเพียงครั้งเดียวการจัดฟันและการส่งคืนสามารถละเว้นได้
•หากฟังก์ชั่นส่งคืนวัตถุโดยตรงต้องเพิ่มวงเล็บนอกวัตถุ (เนื่องจากวัตถุเปล่า {} และบล็อกว่าง {} มีลักษณะเหมือนกันทุกประการดังนั้นคุณต้องห่อเนื้อเยื่อของวัตถุในวงเล็บ)
ในการตอบสนองต่อปัญหาของคำหลักนี้ ES6 ระบุขอบเขตที่การเชื่อมโยงนี้ถูกกำหนดไว้ในฟังก์ชันลูกศรแทนที่จะชี้ไปที่ขอบเขตที่อยู่ที่รันไทม์ ตั้งแต่จุดนี้จุดนี้ได้รับการแก้ไขแล้วซึ่งเอื้อต่อการสรุปฟังก์ชั่นการโทรกลับ
function foo () {var that = this; settimeout (() => {console.log ('id:', that.id);}, 100);} var id = 21; foo.call ({id: 42}); // id: 42หมายเหตุ: การตรึงที่ชี้ไปที่ฟังก์ชั่นลูกศรนี่ไม่ใช่เพราะมีกลไกในการผูกสิ่งนี้ภายในฟังก์ชันลูกศร เหตุผลที่แท้จริงคือฟังก์ชั่นลูกศรไม่มีสิ่งนี้ของตัวเองเลย ฟังก์ชั่นลูกศรไม่มีสิ่งนี้เลยและภายในนี้คือสิ่งนี้ในบล็อกรหัสด้านนอก สิ่งนี้นำไปสู่:
•ไม่สามารถใช้เป็นตัวสร้าง
•คุณไม่สามารถใช้การโทร (), ใช้ (), bind () และวิธีการอื่น ๆ เพื่อเปลี่ยนทิศทางของสิ่งนี้
ชั้นเรียนและมรดก
Ecmascript แบบดั้งเดิมไม่มีแนวคิดของชั้นเรียน มันอธิบายแนวคิดของห่วงโซ่ต้นแบบและใช้โซ่ต้นแบบเป็นวิธีหลักในการใช้การสืบทอด แนวคิดพื้นฐานคือการใช้ต้นแบบเพื่อให้ประเภทอ้างอิงหนึ่งประเภทสามารถสืบทอดคุณสมบัติและวิธีการของประเภทอ้างอิงอื่น วิธีดั้งเดิมในการบรรลุพฤติกรรมนี้คือผ่านตัวสร้าง:
จุดฟังก์ชัน (x, y) {this.x = x; this.y = y;} point.prototype.toString = function () {return '(' + this.x + ',' + this.y + ')';}; var p = จุดใหม่ (1, 2);ที่นี่จุดสร้างจะมีวัตถุต้นแบบ (ต้นแบบ) ซึ่งมีตัวชี้ไปยังจุด (คอนสตรัคเตอร์) และอินสแตนซ์ P มีตัวชี้ภายในไปยังวัตถุต้นแบบ (เสา) ดังนั้นการสืบทอดทั้งหมดจึงถูกนำไปใช้ผ่านห่วงโซ่ต้นแบบ สำหรับรายละเอียดดูบทความนี้ของฉัน: ต้นแบบและตัวสร้างใน JavaScript
ระดับ
ES6 ให้รูปแบบการเขียนที่อยู่ใกล้กับภาษาดั้งเดิมแนะนำแนวคิดของคลาสเป็นเทมเพลตสำหรับวัตถุ ผ่านคำหลักของคลาสคุณสามารถกำหนดคลาส แต่ชั้นเรียนเป็นเพียงน้ำตาลวากยสัมพันธ์สำหรับรูปแบบเชิงวัตถุที่ใช้ต้นแบบ มีความคิดเห็นที่หลากหลายเกี่ยวกับการแนะนำชั้นเรียนและหลายคนคิดว่ามันเป็นข้อบกพร่องที่สำคัญ แต่สำหรับฉันมันเป็นน้ำตาลไวยากรณ์ที่ดีเพราะวิธีปกติในการสืบทอดโซ่ต้นแบบมักจะพันฉันไปซักพัก
// กำหนดจุดคลาสคลาส {constructor (x, y) {this.x = x; this.y = y;} toString () {return '(' + this.x + ',' + this.y + ')';}} var p = จุดใหม่ (1, 2);•มีวิธีตัวสร้างในคลาสซึ่งเป็นวิธีเริ่มต้นของคลาส วิธีนี้จะถูกเรียกโดยอัตโนมัติเมื่อสร้างอินสแตนซ์วัตถุผ่านคำสั่งใหม่ คลาสจะต้องมีวิธีการสร้าง หากไม่ได้กำหนดไว้อย่างชัดเจนวิธีการสร้างที่ว่างเปล่าจะถูกเพิ่มโดยค่าเริ่มต้น
•คำหลักนี้ในวิธีตัวสร้างแสดงถึงวัตถุอินสแตนซ์
•เมื่อกำหนดวิธีการของ "คลาส" (เช่น toString ในตัวอย่างด้านบน) คุณไม่จำเป็นต้องเพิ่มฟังก์ชั่นคำหลักก่อนที่จะใส่คำจำกัดความของฟังก์ชั่นนอกจากนี้ไม่มีการแยกเครื่องหมายจุลภาคระหว่างวิธีการตามข้อผิดพลาดหากเพิ่ม
•เมื่อใช้งานคุณยังใช้คำสั่งใหม่โดยตรงบนคลาสซึ่งเหมือนกับการใช้งานของตัวสร้าง
•วิธีการทั้งหมดของคลาสถูกกำหนดไว้ในคุณสมบัติต้นแบบของคลาส
มรดกของชั้นเรียน - ขยาย
การสืบทอดระหว่างชั้นเรียนสามารถทำได้ผ่านการขยายคำหลักซึ่งชัดเจนกว่าและสะดวกกว่าการสืบทอดของ ES5 โดยการปรับเปลี่ยนห่วงโซ่ต้นแบบ
Class ColorPoint ขยายจุด {constructor (x, y, สี) {super (x, y); // เรียกคอนสตรัคเตอร์ (x, y) ของคลาสแม่ (x, y) this.color = color;} toString () {return this.color + '' + super.toString (); // เรียก toString () ของคลาสแม่}}•คำหลัก Super เมื่อเรียกว่าเป็นฟังก์ชัน (เช่น super (... args)) แสดงถึงตัวสร้างของคลาสแม่ เมื่อเรียกว่าเป็นวัตถุ (เช่น super.prop หรือ super.method ()) แสดงถึงคลาสหลัก ที่นี่มันแสดงถึงตัวสร้างของคลาสแม่และใช้เพื่อสร้างวัตถุนี้ของคลาสแม่
•คลาสย่อยจะต้องเรียกเมธอดซูเปอร์ในเมธอดคอนสตรัคเตอร์มิฉะนั้นจะมีการรายงานข้อผิดพลาดเมื่อสร้างอินสแตนซ์ใหม่ นี่เป็นเพราะคลาสย่อยไม่มีวัตถุนี้ แต่สืบทอดวัตถุนี้ของคลาสแม่แล้วประมวลผล หากไม่ได้เรียกวิธี Super คลาสย่อยจะไม่ได้รับวัตถุนี้
เป็นแบบแยกส่วน
ในอดีต JavaScript ไม่เคยมีระบบโมดูลและเป็นไปไม่ได้ที่จะแบ่งโปรแกรมขนาดใหญ่ออกเป็นไฟล์พึ่งพาซึ่งกันและกันขนาดเล็กแล้วรวบรวมมันอย่างง่าย ๆ ซึ่งได้สร้างอุปสรรคใหญ่ในการพัฒนาโครงการขนาดใหญ่และซับซ้อน เพื่อปรับให้เข้ากับการพัฒนาโมดูลขนาดใหญ่ชุมชนได้กำหนดโซลูชันการโหลดโมดูลบางอย่างเช่น CMD และ AMD
การเขียนแบบแยกส่วนของ ES6:
นำเข้า {stat, มีอยู่, readfile} จาก 'fs';สาระสำคัญของรหัสข้างต้นคือการโหลด 3 วิธีจากโมดูล FS และวิธีอื่น ๆ จะไม่ถูกโหลด การโหลดประเภทนี้เรียกว่า "การโหลดเวลาการรวบรวม" นั่นคือ ES6 สามารถทำการโหลดโมดูลให้เสร็จสมบูรณ์ในเวลาคอมไพล์ซึ่งมีประสิทธิภาพมากกว่าวิธีการโหลดของโมดูล CommonJS แน่นอนว่าสิ่งนี้ยังนำไปสู่การไร้ความสามารถในการอ้างอิงโมดูล ES6 เองเพราะมันไม่ใช่วัตถุ
ฟังก์ชั่นโมดูลส่วนใหญ่ประกอบด้วยสองคำสั่ง:
•ส่งออก
อินเทอร์เฟซภายนอกที่ใช้เพื่อระบุโมดูลและอินเตอร์เฟสภายนอกจะต้องสร้างความสัมพันธ์การติดต่อแบบหนึ่งต่อหนึ่งกับตัวแปรภายในโมดูล
// วิธีการเขียนหนึ่งส่งออก var m = 1; // ข้อผิดพลาดส่งออก 1; // วิธีการเขียนสอง var m = 1; ส่งออก {m}; // ข้อผิดพลาดส่งออก m; // วิธีการเขียนวิธีการสามชื่อ var n = 1; ส่งออก {n เป็น m};•นำเข้า
ใช้เพื่อป้อนฟังก์ชั่นที่จัดทำโดยโมดูลอื่น ๆ มันยอมรับวัตถุ (แสดงในวงเล็บปีกกา) ที่ระบุชื่อตัวแปรที่จะนำเข้าจากโมดูลอื่น ๆ (สามารถโหลดได้โดยใช้ * ทั้งหมด)
การแก้ไขสตริง
ในการพัฒนา JavaScript เรามักจะต้องส่งออกเทมเพลตเช่นนี้:
ฟังก์ชั่น sayshello (ชื่อ) {return "สวัสดีชื่อของฉันคือ"+ชื่อ+"ฉัน"+getage (18);} ฟังก์ชั่น getage (อายุ) {return age;} sayhello ("Brand") // "สวัสดีชื่อของฉันคือแบรนด์ฉันอายุ 18"เราจำเป็นต้องใช้ + เพื่อเชื่อมโยงสตริงและตัวแปร (หรือนิพจน์) ตัวอย่างค่อนข้างง่ายดังนั้นพวกเขาจึงดูไร้เดียงสา แต่เมื่อพวกเขามีความซับซ้อนมากขึ้นพวกเขาจะดูยุ่งยากและไม่สะดวกและการใช้งานนี้ก็ทำให้เราน่าเบื่อหน่าย ในเรื่องนี้ ES6 แนะนำสตริงเทมเพลตซึ่งสามารถแทรกค่า JS ลงในสตริงได้อย่างง่ายดายและสง่างาม
สตริงเทมเพลต
สำหรับสตริงเทมเพลตมัน:
•แพ็คด้วย backticks ``;
•ใช้ $ {} ไปยังค่าเอาต์พุต
•เนื้อหาใน $ {} อาจเป็นนิพจน์ JavaScript ใด ๆ ดังนั้นการเรียกใช้ฟังก์ชันและการดำเนินการทางคณิตศาสตร์จึงถูกกฎหมาย
•หากค่าไม่ใช่สตริงมันจะถูกแปลงเป็นสตริง
•เก็บช่องว่างใหม่ใหม่และเยื้องและส่งออกไปยังสตริงผลลัพธ์ (สามารถเขียนสตริงหลายบรรทัดได้)
•ใช้ backticks และการจัดฟันภายในเพื่อหลบหนีและใช้ backslashes/
สำหรับตัวอย่างด้านบนสตริงเทมเพลตจะถูกเขียนดังนี้:
ฟังก์ชั่น sayshello (ชื่อ) {return `สวัสดีฉันชื่อของฉันคือ $ {ชื่อ} ฉันคือ $ {getage (18)}`;} ฟังก์ชั่น getage (อายุ) {return age;} sayhello ("Brand") // "สวัสดีชื่อของฉันโหมดที่เข้มงวด
หนึ่งในเป้าหมายของโหมดที่เข้มงวดคืออนุญาตให้ทำการดีบักข้อผิดพลาดได้เร็วขึ้น วิธีที่ดีที่สุดในการช่วยให้นักพัฒนาดีบักดีบักคือการโยนข้อผิดพลาดเมื่อรูปแบบบางอย่างเกิดขึ้นแทนที่จะล้มเหลวอย่างเงียบ ๆ หรือแสดงพฤติกรรมแปลก ๆ รหัสในโหมดที่เข้มงวดจะส่งข้อความแสดงข้อผิดพลาดมากขึ้นซึ่งสามารถช่วยให้นักพัฒนาสังเกตเห็นปัญหาบางอย่างที่ต้องแก้ไขได้ทันที ใน ES5 โหมดที่เข้มงวดเป็นทางเลือก แต่ใน ES6 คุณสมบัติมากมายต้องใช้โหมดที่เข้มงวดซึ่งช่วยให้เราเขียน JavaScript ที่ดีขึ้น
ข้างต้นคือปัญหา "ข้อบกพร่อง" ของ ES6 ปรับปรุง JavaScript ที่บรรณาธิการแนะนำให้คุณรู้จัก ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับคุณทันเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!