前端理論面試--ES6新特性

ES6新特性

1.變量聲明const和let
2.模板對象與模板字符串
3.箭頭函數
4.類的支持
5.參數默認值,不定參數,拓展參數
6.Spread Operator 展開運算符
7.import 和 export
8.Promise

JavaScript中var、let、const區別?

使用var聲明的變量,其作用域為該語句所在的函數內,且存在變量提升現象;
使用let聲明的變量,其作用域為該語句所在的代碼塊內,不存在變量提升;
使用const聲明的是常量,在后面出現的代碼中不能再修改該常量的值。

1.塊作用域和構造let和const

在ES6代碼中,你可能已經看到那熟悉的身影let。在ES6里let并不是一個花俏的特性,它是更復雜的。Let是一種新的變量申明方式,它允許你把變量作用域控制在塊級里面。我們用大括號定義代碼塊,在ES5中,塊級作用域起不了任何作用:

function calculateTotalAmount (vip) {
  var amount = 0;
  if (vip) {
    var amount = 1;
  }
  { // more crazy blocks!
    var amount = 100;
    {
      var amount = 1000;
    }
  }  
  return amount;
}
console.log(calculateTotalAmount(true));

結果將返回1000,這真是一個bug。在ES6中,我們用let限制塊級作用域。而var是限制函數作用域。

function calculateTotalAmount (vip) {
  var amount = 0; // probably should also be let, but you can mix var and let
  if (vip) {
    let amount = 1; // first amount is still 0
  } 
  { // more crazy blocks!
    let amount = 100; // first amount is still 0
    {
      let amount = 1000; // first amount is still 0
    }
  }  
  return amount;
}
 
console.log(calculateTotalAmount(true));

這個結果將會是0,因為塊作用域中有了let。如果(amount=1).那么這個表達式將返回1。談到const,就更加容易了;它就是一個不變量,也是塊級作用域就像let一樣。下面是一個演示,這里有一堆常量,它們互不影響,因為它們屬于不同的塊級作用域:

function calculateTotalAmount (vip) {
  const amount = 0;  
  if (vip) {
    const amount = 1;
  } 
  { // more crazy blocks!
    const amount = 100 ;
    {
      const amount = 1000;
    }
  }  
  return amount;
}
console.log(calculateTotalAmount(true));

從我個人看來,let 和const使這個語言變復雜了。沒有它們的話,我們只需考慮一種方式,現在有許多種場景需要考慮。

2.模板對象與模板字符串

模板對象
在其它語言中,使用模板和插入值是在字符串里面輸出變量的一種方式。因此,在ES5,我們可以這樣組合一個字符串:

let name = 'Your name is ' + first + ' ' + last + '.';
let url = 'http://localhost:3000/api/messages/' + id;

幸運的是,在ES6中,我們可以使用新的語法$ {NAME},并把它放在反引號里:

let name = `Your name is ${first} ${last}. `;
let url = `http://localhost:3000/api/messages/${id}`;

模板字符串
ES6的多行字符串是一個非常實用的功能。在ES5中,我們不得不使用以下方法來表示多行字符串:

var roadPoem = 'Then took the other, as just as fair,nt'
    + 'And having perhaps the better claimnt'
    + 'Because it was grassy and wanted wear,nt'
    + 'Though as for that the passing therent'
    + 'Had worn them really about the same,nt';
var fourAgreements = 'You have the right to be you.n
    You can only be you when you do your best.';

然而在ES6中,僅僅用反引號就可以解決了:

var roadPoem = `Then took the other, as just as fair,
    And having perhaps the better claim
    Because it was grassy and wanted wear,
    Though as for that the passing there
    Had worn them really about the same,`;
var fourAgreements = `You have the right to be you.
    You can only be you when you do your best.`;

3.箭頭函數

這是我迫不及待想講的一個特征,CoffeeScript 就是因為它豐富的箭頭函數讓很多開發者喜愛。在ES6中,也有了豐富的箭頭函數。這些豐富的箭頭是令人驚訝的因為它們將使許多操作變成現實,比如,
以前我們使用閉包,this總是預期之外地產生改變,而箭頭函數的迷人之處在于,現在你的this可以按照你的預期使用了,身處箭頭函數里面,this還是原來的this。
有了箭頭函數在ES6中, 我們就不必用that = this或 self = this 或 _this = this 或.bind(this)。例如,下面的代碼用ES5就不是很優雅:

var _this = this;
$('.btn').click(function(event){
  _this.sendData();
})

在ES6中就不需要用 _this = this:

$('.btn').click((event) =>{
  this.sendData();
})

不幸的是,ES6委員會決定,以前的function的傳遞方式也是一個很好的方案,所以它們仍然保留了以前的功能。
下面這是一個另外的例子,我們通過call傳遞文本給logUpperCase() 函數在ES5中:

var logUpperCase = function() {
  var _this = this;
 
  this.string = this.string.toUpperCase();
  return function () {
    return console.log(_this.string);
  }
}
 
logUpperCase.call({ string: 'ES6 rocks' })();

而在ES6,我們并不需要用_this浪費時間:

var logUpperCase = function() {
  this.string = this.string.toUpperCase();
  return () => console.log(this.string);
}
logUpperCase.call({ string: 'ES6 rocks' })();

請注意,只要你愿意,在ES6中=>可以混合和匹配老的函數一起使用。當在一行代碼中用了箭頭函數,它就變成了一個表達式。它將暗地里返回單個語句的結果。如果你超過了一行,將需要明確使用return。

這是用ES5代碼創建一個消息數組:

var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9'];
var messages = ids.map(function (value) {
  return "ID is " + value; // explicit return
});

用ES6是這樣:

var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9'];
var messages = ids.map(value => `ID is ${value}`); // implicit return

請注意,這里用了字符串模板。

在箭頭函數中,對于單個參數,括號()是可選的,但當你超過一個參數的時候你就需要他們。

在ES5代碼有明確的返回功能:

var ids = ['5632953c4e345e145fdf2df8', '563295464e345e145fdf2df9'];
var messages = ids.map(function (value, index, list) {
  return 'ID of ' + index + ' element is ' + value + ' '; // explicit return
});

在ES6中有更加嚴謹的版本,參數需要被包含在括號里并且它是隱式的返回:

var ids = ['5632953c4e345e145fdf2df8','563295464e345e145fdf2df9'];
var messages = ids.map((value, index, list) => `ID of ${index} element is ${value} `); // implicit return

4.類的支持

如果你喜歡面向對象編程(OOP),那么你將喜愛這個特性。以后寫一個類和繼承將變得跟在facebook上寫一個評論那么容易。

類的創建和使用真是一件令人頭疼的事情在過去的ES5中,因為沒有一個關鍵字class (它被保留,但是什么也不能做)。在此之上,大量的繼承模型像pseudo classical, classical, functional 更加增加了混亂,JavaScript 之間的宗教戰爭只會更加火上澆油。

用ES5寫一個類,有很多種方法,這里就先不說了。現在就來看看如何用ES6寫一個類吧。ES6沒有用函數, 而是使用原型實現類。我們創建一個類baseModel ,并且在這個類里定義了一個constructor 和一個 getName()方法:

class baseModel {
  constructor(options, data) { // class constructor,node.js 5.6暫時不支持options = {}, data = []這樣傳參
    this.name = 'Base';
    this.url = 'http://azat.co/api';
    this.data = data;
    this.options = options;
   }
 
    getName() { // class method
        console.log(`Class name: ${this.name}`);
    }
}

注意我們對options 和data使用了默認參數值。此外方法名也不需要加function關鍵字,而且冒號(:)也不需要了。另外一個大的區別就是你不需要分配屬性this。現在設置一個屬性的值,只需簡單的在構造函數中分配。
AccountModel 從類baseModel 中繼承而來:

class AccountModel extends baseModel {
    constructor(options, data) {
  }
}

為了調用父級構造函數,可以毫不費力的喚起super()用參數傳遞:

super({private: true}, ['32113123123', '524214691']); //call the parent method with super
       this.name = 'Account Model';
       this.url +='/accounts/';
    }

如果你想做些更好玩的,你可以把 accountData 設置成一個屬性:

get accountsData() { //calculated attribute getter
    // ... make XHR
        return this.data;
    }
}

那么,你如何調用他們呢?它是非常容易的:

let accounts = new AccountModel(5);
accounts.getName();
console.log('Data is %s', accounts.accountsData);

結果令人驚訝,輸出是:

Class name: Account Model

Data is 32113123123,524214691

5.參數默認值,不定參數,拓展參數

還記得我們以前不得不通過下面方式來定義默認參數:

var link = function (height, color, url) {
    var height = height || 50;
    var color = color || 'red';
    var url = url || 'http://azat.co';
    ...
}

一切工作都是正常的,直到參數值是0后,就有問題了,因為在JavaScript中,0表示fasly,它是默認被hard-coded的值,而不能變成參數本身的值。當然,如果你非要用0作為值,我們可以忽略這一缺陷并且使用邏輯OR就行了!但在ES6,我們可以直接把默認值放在函數申明里:

var link = function(height = 50, color = 'red', url = 'http://azat.co') {
  ...
}

順便說一句,這個語法類似于Ruby!

6.Spread Operator 展開運算符

ES6中另外一個好玩的特性就是Spread Operator 也是三個點兒...接下來就展示一下它的用途。

組裝對象或者數組

//數組
    const color = ['red', 'yellow']
    const colorful = [...color, 'green', 'pink']
    console.log(colorful) //[red, yellow, green, pink]
    
    //對象
    const alp = { fist: 'a', second: 'b'}
    const alphabets = { ...alp, third: 'c' }
    console.log(alphabets) //{ "fist": "a", "second": "b", "third": "c"}

有時候我們想獲取數組或者對象除了前幾項或者除了某幾項的其他項

//數組
    const number = [1,2,3,4,5]
    const [first, ...rest] = number
    console.log(rest) //2,3,4,5
    //對象
    const user = {
        username: 'lux',
        gender: 'female',
        age: 19,
        address: 'peking'
    }
    const { username, ...rest } = user
    console.log(rest) //{"address": "peking", "age": 19, "gender": "female"}

對于 Object 而言,還可以用于組合成新的 Object 。(ES2017 stage-2 proposal) 當然如果有重復的屬性名,右邊覆蓋左邊

const first = {
        a: 1,
        b: 2,
        c: 6,
    }
    const second = {
        c: 3,
        d: 4
    }
    const total = { ...first, ...second }
    console.log(total) // { a: 1, b: 2, c: 3, d: 4 }

7.import 和 export

眾所周知,在ES6以前JavaScript并不支持本地的模塊。人們想出了AMD,RequireJS,CommonJS以及其它解決方法。現在ES6中可以用模塊import 和export 操作了。

在ES5中,你可以在 <script>中直接寫可以運行的代碼(簡稱IIFE),或者一些庫像AMD。然而在ES6中,你可以用export導入你的類。下面舉個例子,在ES5中,module.js有port變量和getAccounts 方法:

module.exports = {
  port: 3000,
  getAccounts: function() {
    ...
  }
}

在ES5中,main.js需要依賴require(‘module’) 導入module.js:

var service = require('module.js');
console.log(service.port); // 3000

但在ES6中,我們將用export and import。例如,這是我們用ES6 寫的module.js文件庫:

export var port = 3000;
export function getAccounts(url) {
  ...
}

如果用ES6來導入到文件main.js中,我們需用import {name} from ‘my-module’語法,例如:

import {port, getAccounts} from 'module';
console.log(port); // 3000

或者我們可以在main.js中把整個模塊導入, 并命名為 service:

import * as service from 'module';
console.log(service.port); // 3000

從我個人角度來說,我覺得ES6模塊是讓人困惑的。但可以肯定的事,它們使語言更加靈活了。
并不是所有的瀏覽器都支持ES6模塊,所以你需要使用一些像jspm去支持ES6模塊。

更多的信息和例子關于ES6模塊,請看 (http://exploringjs.com/es6/ch_modules.html)。不管怎樣,請寫模塊化的JavaScript。

8.Promise

Promises 是一個有爭議的話題。因此有許多略微不同的promise 實現語法。Q,bluebird,deferred.js,vow, avow, jquery 一些可以列出名字的。也有人說我們不需要promises,僅僅使用異步,生成器,回調等就夠了。但令人高興的是,在ES6中有標準的Promise實現。
下面是一個簡單的用setTimeout()實現的異步延遲加載函數:

setTimeout(function(){
  console.log('Yay!');
}, 1000);

在ES6中,我們可以用promise重寫:

var wait1000 =  new Promise(function(resolve, reject) {
  setTimeout(resolve, 1000);
}).then(function() {
  console.log('Yay!');
});

或者用ES6的箭頭函數:

var wait1000 =  new Promise((resolve, reject)=> {
  setTimeout(resolve, 1000);
}).then(()=> {
  console.log('Yay!');
});

到目前為止,代碼的行數從三行增加到五行,并沒有任何明顯的好處。確實,如果我們有更多的嵌套邏輯在setTimeout()回調函數中,我們將發現更多好處:

setTimeout(function(){
  console.log('Yay!');
  setTimeout(function(){
    console.log('Wheeyee!');
  }, 1000)
}, 1000);

在ES6中我們可以用promises重寫:

var wait1000 =  ()=> new Promise((resolve, reject)=> {setTimeout(resolve, 1000)});
wait1000()
    .then(function() {
        console.log('Yay!')
        return wait1000()
    })
    .then(function() {
        console.log('Wheeyee!')
    });

還是不確信Promises 比普通回調更好?其實我也不確信,我認為一旦你有回調的想法,那么就沒有必要額外增加promises的復雜性。

雖然,ES6 有讓人崇拜的Promises 。Promises 是一個有利有弊的回調但是確實是一個好的特性,更多詳細的信息關于promise:Introduction to ES6 Promises.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容

  • ES6中比較實用的八個特性: 1.塊級作用域的let和const2.箭頭函數3.默認參數4.模版表達式5.多行字符...
    getElementsByMK閱讀 1,139評論 0 13
  • 在近期的Vue開發中,使用了大量的ES6語法,因此覺得有必要找個時間來整理下近期的學習筆記。ES6相對ES5增加了...
    zhanzhan_wu閱讀 7,974評論 1 10
  • ECMAScript 6.0(以下簡稱ES6)是、JavaScript語音的下一代標準,已經在2015年6月正式發...
    Leisure_blogs閱讀 499評論 1 2
  • 首先感謝Carnia幫我指出ES6箭頭函數中this指向的錯誤,此次主要更新箭頭函數中this指向問題。 ECMA...
    范小飯_閱讀 8,805評論 7 21
  • let和const命令 var:聲明變量,更多的是全局作用域,存在變量提升 let:聲明變量,存在于塊級作用域,不...
    zhangivon閱讀 2,482評論 1 13