前端面試經典題之ES6新特性


  ES6 主要是為了解決 ES5 的先天不足,在原先ES5的基礎上新增了許多內容,本篇文章將列舉出ES6中新增的10大特性。

  一、 let 和 const

  與var不同,let和const都是用於命名局部變量,都是塊級作用域。具體可參考阮一峰老師的文章:http://es6.ruanyifeng.com/#docs/let

  這三者的用法區別如下:

 1 var val = "全局變量";
 2 
 3 {
 4   let val = "局部變量";
 5   console.log(val);     // 局部變量
 6 }
 7 
 8 console.log(val);       // 全局變量
 9 
10 const val = "常量";
11 val = "123";            // Uncaught TypeError: Assignment to constant variable.

  前面說const聲明的是常量,一旦聲明就不可再進行修改。但是當用const聲明對象時,又會出現一種新情況,舉個栗子:

1 const person = {name: "Peter", age: "22"};
2 person.age = 23;                      // 不會報錯,person的age變量會被改成23
3 person = {name: "Lily", age: "18"};   // 報錯

  如果用const聲明一個對象,對象所包含的值是可以被修改的。換一句話來說,只要對象指向的地址不被修改,就是允許的。

  關於let和const有幾個小tips:

  1. let 關鍵詞聲明的變量不具備變量提升(變量提升:https://blog.csdn.net/qq_42606051/article/details/82016733)特性;
  2. let 和 const 聲明只在最靠近的一個塊中有效;
  3. 當使用常量 const 聲明時,請使用大寫變量,如:CAPITAL_CASING;
  4. const 在聲明時必須被賦值,否則會報錯。
  5. 使用let會出現暫時性死區,原因是let所聲明的變量會鎖在它所在的作用域里,不允許訪問,就是說,它也會先掃描一遍,把let聲明的變量保存起來,但是不允許使用,這時候你訪問a,由於此作用域中有a,就不用訪問外面的a了,但是你不能在它聲明之前訪問它。
var a = 1;
if(ture){
    console.log(a);  //ReferrenceError
    let a = 1;
}

  6. 使用let和const時不能重復聲明。

  7. 使用var聲明的全局變量或者未聲明的變量都會歸屬到window對象下,但是使用let和const聲明全局變量時不會發生這種情況。

  拓展: 如何使用ES5標准來實現let,換言之就是如何實現塊級作用域。(答:使用匿名函數)

  二、 模版字符串

  在過去我們想要將字符串和變量拼接起來,只能通過運算符“+”來實現,若內容過多還要用“\”來表示換行,如:

var person = {name: "Peter", age: 22, career: "student"};
$(".introduction").html("Hello, my name is " + person.name + ", and my \
career is " + person.career + ".");

  而在ES6中,可以將反引號(``)將內容括起來,在反引號中,可以使用${}來寫入需要引用到的變量。如:

var person = {name: "Peter", age: 22, career: "student"};
$(".introduction").html(`Hello, my name is ${person.name}, and my career is ${person.career}.`);

  所以在ES6中,我們可以更方便地將字符串和變量連接起來。

  三、 箭頭函數

  在ES6中引入了一種新的函數表達方式,它是函數的一種簡寫方法,有以下三個特點:

  1. 不需要用關鍵字function來定義函數;
  2. 一般情況下可以省略return;
  3. 在箭頭函數內部,this並不會跟其他函數一樣指向調用它的對象,而是繼承上下文的this指向的對象。

  在上面的三點中,第三點尤為重要,初學者在使用時經常會忽略這一點。

  下面舉幾個箭頭函數的使用方法:

 1 /*
 2 ** 對應上面所說的第3點
 3 ** 在箭頭函數中,this的指向與它的上下文有關
 4 ** 在本例中,箭頭函數fun的上下文是window,所以this指向的也是window
 5 */
 6 window.val = 12;
 7 let fun = () => {
 8     let val = 13;
 9     console.log(val);               // 13
10     console.log(this.val);          // 12
11     console.log(this == window);    // true
12 }
13 fun();
14 
15 /*
16 ** 普通函數使用
17 */
18 
19 let add = function(a, b){
20     return a + b;
21 }
22 
23 /*
24 ** 箭頭函數使用
25 */
26 let add1 = (a, b) => a + b;
27 
28 // 當參數只有一個時,可以將括號省略
29 let sqrt = a => a*a;

  四、 函數可以設置默認參數值

  在這之前,我們想要在函數中設置默認值,只能通過以下方法進行設置:

1 function printText(text){
2     var text = text || "hello world!";
3     console.log(text);
4 }
5 
6 printText("My name is Peter");          // "My name is Peter";
7 printText();                            // "hello world!";    

  但是在ES6中定義了一種新方法,開發者可以直接使用如下方法設置函數的參數默認值:

1 function printText(text = "hello world!") {
2     console.log(text);
3 }
4 
5 printText("My name is Peter");  // "My name is Peter";
6 printText();                    // "hello world!";

  五、 Spread / Rest 操作符

  Rest運算符用於獲取函數調用時傳入的參數。舉個栗子:

1 let fun = function(...args) {
2     console.log(args);
3 }
4 
5 const list = ["Peter", "Lily", "Tom"];
6 fun(list);    // ["Peter", "Lily", "Tom"]

  Spread運算符用於數組的構造,析構,以及在函數調用時使用數組填充參數列表。再舉個栗子:  

 1 /*
 2 ** 使用Spread運算符合並數組
 3 */
 4 const list1 = ["Peter", "Tom"];
 5 const list2 = ["Lily", "Mary"];
 6 const list = [...list1, ...list2];
 7 console.log(list); // ["Peter", "Tom", "Lily", "Mary"]]
 8 
 9 /*
10 ** 使用Spread運算符析構數組
11 */
12 const [person, ...list3] = list;
13 console.log(person);        // Peter
14 console.log(list3);         // ["Tom", "Lily", "Mary"]

  更多關於Rest和Spread運算法的使用方法,可以參考一下阮一峰老師的文章:http://es6.ruanyifeng.com/#docs/array

  六、 二進制和八進制的字面量

  ES6支持二進制和八進制的字面量,通過在數字前面增加0o或者0O可以將數字轉換為八進制。

1 let val1 = 0o10;
2 console.log(val1);      // 8,八進制的0o10對應十進制的8
3 
4 let val2 = 0b10;
5 console.log(val2);      // 2,二進制的0b10對應十進制的2

  七、 對象和數組解構

  ES6可以將對象中的屬性或者數組中的元素進行解構,操作方式與前面所提到的Rest和Spread操作符類似,看一下下面這個栗子:

1 let person = {
2     name: "Peter",
3     age: 22,
4     career: "student"
5 }
6 
7 const {name, age, career } = person;
8 console.log(`Hello, my name is ${name}, and my career is ${career}.`);        
9 //Hello, my name is Peter, and my career is student.

  八、 允許在對象中使用super方法

  super方法應該都不陌生,在java中用來代表調用父類的構造函數。由於js不是面向對象語言,所以也沒有繼承這以說法。但是在ES6中,可以通過調用setPrototypeOf()方法來設置一個對象的prototype對象,與面向對象語言中的繼承有相似之處,所以也可以理解成這是js中用來實現繼承的方法。(這段話純屬個人理解,如果有誤請指出。)所以,在ES6中,通過使用super可以調用某個對象的prototype對象的方法或獲取參數。栗子如下:

 1 var father = {
 2     text: "Hello from the Father.",
 3     foo() {
 4         console.log("Hello from the Father.");
 5     }
 6 }
 7 
 8 var son = {
 9     foo() {
10         super.foo();
11         console.log(super.text);
12         console.log("Hello from the Son.");
13     }
14 }
15 
16 /*
17 ** 將father設置成son的prototpe
18 ** 當在son中調用super時,可以直接調用到它的prototype對象,即father的方法和變量
19 */
20 Object.setPrototypeOf(son, father);
21 son.foo(); 
22 // Hello from the Fater.
23 // Hello from the Fater.
24 // Hello from the Son.

  九、 迭代器iterator、for...of和for...in

  首先你要理解什么是iterator,可參考http://es6.ruanyifeng.com/#docs/iterator#for---of-%E5%BE%AA%E7%8E%AF

  了解完iterator之后,便可以來深入了解一下for...of和for...in這兩種方法了。用一句話來總結就是,無論是for…in還是for…of語句,都是用來迭代數據,它們之間的最主要的區別在於它們的迭代方式不同。

  • for…in 語句以原始插入順序迭代對象的可枚舉屬性,簡單理解就是for...in是用來循環遍歷屬性,遍歷出的是自身和原型上的可枚舉非symbol屬性,但是遍歷不一定按照順序(tips:for...in在ES5中就已經出現了)
  • for…of 語句遍歷可迭代對象定義要迭代的數據,也就是說,for...of只可以循環可迭代對象的可迭代屬性,不可迭代屬性在循環中被忽略了。(tips:for...of是ES6才提出來的)

  關於for...in和for...of的用法,可以看以下栗子:

 1 Object.prototype.objCustom = function() {};
 2 Array.prototype.arrCustom = function() {};
 3 
 4 let iterable = [3, 5, 7];
 5 iterable.foo = 'hello';
 6 //for in 會繼承
 7 for (let i in iterable) {
 8     console.log(i); // 依次打印 0, 1, 2, "foo", "arrCustom", "objCustom"
 9 }
10 
11 for (let i in iterable) {
12     if (iterable.hasOwnProperty(i)) {
13         console.log(i); // 依次打印 0, 1, 2, "foo"
14     }
15 }
16 
17 // for of
18 for (let i of iterable) {
19     console.log(i); // 依次打印 3, 5, 7
20 }

  對於這一塊的應用,我自己也不是很理解。例子是參考別的博主寫的。在實際開發過程中,似乎不太建議使用for...in,因為不同環境下對for...in的遍歷算法的實現不一樣,而且在for...in的過程中對這個對象屬性的添加,修改,刪除操作不能被保證, MDN不建議用這個來遍歷對象。

  十、 class

  ES6 提供了更接近傳統語言的寫法,引入了 class(類)這個概念,作為對象的模板。通過class關鍵字,可以定義類。

  基本上,ES6 的class可以看作只是一個語法糖,它的絕大部分功能,ES5 都可以做到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。在ES5中,我們更多是使用原型鏈來實現繼承。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM