【自種樹自乘涼】ES6 新特徵總結

這是我參與8月更文挑戰的第4天,活動詳情查看:8月更文挑戰前端

要知道,作前端開發,ES6 是必學的。這篇文章適合初步入門和複習,結合阮一峯老師的教程可以更深刻的學習 ES6。es6

目錄:面試

  1. 塊級做用域、塊級變量 let、塊級常量 const
  2. 箭頭函數
  3. 參數處理(默認參數/...)
  4. 模板字面量(模板字符串)
  5. 對象的擴展
  6. 解構賦值
  7. 模塊(import/export)
  8. 類(class/extends)
  9. Promise
  10. End 感謝閱讀

一. 塊級做用域、變量 let、常量 const

  1. 由一對 { } 界定的語句叫作塊語句,這在其餘編程語言中叫作複合語句

通常理解的塊:express

  • 塊:由 {} 包括住
  • if(){}:是一個塊
  • for(){}:是一個塊

這些也可理解成塊:編程

  • 一個函數:函數做用域
  • script 標籤:全局做用域
  1. JS 中用 var 聲明的變量是沒有塊級做用域的,只有函數做用域和全局做用域
var x = 1;
{
  var x = 2;
}
console.log(x);
複製代碼
  • 會輸出 2,由於塊中的 var 語句與塊前面的 var 語句做用域相同
  • 在 C 或 Java 中,這段代碼會輸出 1
  • 這代碼證實了 var 沒有塊做用域
  1. 相比之下,使用 let 和 const 聲明的變量是有塊級做用域的
let x = 1;
{
  let x = 2;
}
console.log(x); 
複製代碼
  • 輸出 1
  • x 被限制在塊級做用域中
  • 這裏將 let 換成 const 結果也同樣
  1. 經典的例子(背住):
var a = [];
for (var i = 0; i < 10; i++) {
      a[i] = function () {console.log(i);};
}
a[0]();                // 10
a[1]();                // 10
a[6]();                // 10

/********************/

var a = [];
for (let i = 0; i < 10; i++) {
      a[i] = function () {console.log(i);};
}
a[0]();                // 0
a[1]();                // 1
a[6]();                // 6
複製代碼
  • 第一個中的 i 是沒有塊級做用域的,全局只有一個變量 i,每次循環的 {} 中的代碼都指向同一個 i
  • 第二個中的 i 是有塊級做用域的,當前的i只在本輪循環有效,每次循環的 {} 中的代碼都指向不一樣的 i
  • 值得注意的是:for的 () 是一個父做用域,{} 是一個子做用域
  • 由於當前的 i 只在本輪循環有效,因此 let 定義的 i 在每次循環都會從新定義一遍,每次都是一個新變量
  1. 補充:

使用 function 時也有塊級做用域:數組

foo('outside');  // TypeError: foo is not a function
{
  function foo(location) {
   console.log('foo is called ' + location);
  }
  foo('inside'); // 正常工做而且打印 'foo is called inside' 
}
複製代碼
  1. var 變量提高,let 變量暫時性死區
console.log(foo); //輸出 undefined,不會報錯
var foo = 2; 

console.log(bar); //報錯 ReferenceError 
let bar = 2;
複製代碼
  • var 會發生變量提高現象,將變量提高到函數頂部或全局頂部
  • let 沒有這種狀況,必須在 let 聲明後調用該變量 (const 和 let 同樣)
  • let 和 const 的這種現象稱爲暫時性死區
  • 從塊開始到 let 聲明之間是「暫存死區」
  1. let 錯誤

在同一個做用域中用 let 重複定義一個變量將引發 TypeErrorpromise

if (x) {
  let foo;
  let foo; // TypeError thrown
}
複製代碼
  1. const 的概念
  • 必須在聲明的同一語句中指定它的值
  • const 聲明建立一個值的只讀引用,也就是說只能經過 const 定義的變量來讀這個值,不能修改這個值,可是若是這個值自己發生了變化,那麼 const 定義的變量所對應的值也就跟着變化,好比當引動內容是對象的狀況下。
  • 一個常量不能和它所在做用域內的其餘變量或函數擁有相同的名稱。
// 下面錯誤,常量要求有一個初始值
const FOO;

// 下面正確,常量能夠定義成對象
const MY_OBJECT = {"key": "value"};
// 下面錯誤,改變常量會失敗
MY_OBJECT = {"OTHER_KEY": "value"};
// 對象屬性並不在保護的範圍內,下面會成功執行(對象自己發生變化)
MY_OBJECT.key = "otherValue";

// 定義一個常量
const MY_FAV = 20;
// 不能同名,會出錯
var MY_FAV = 20; 
// 也會報錯
let MY_FAV = 20;
複製代碼

二. 箭頭函數

基礎語法:markdown

// 通常語法:
(參數1, 參數2, …, 參數N) => { 函數聲明 }

// 至關於:(參數1, 參數2, …, 參數N) =>{ return 表達式; }
(參數1, 參數2, …, 參數N) => 表達式(單一)

// 當只有一個參數時,圓括號是可選的:
(單一參數) => {函數聲明}
單一參數 => {函數聲明}

// 沒有參數的函數應該寫成一對圓括號
() => {函數聲明}
複製代碼

高級語法:編程語言

注意: 字面量通常指 [1, 2, 3] 或者 {name: "mdn"} 這種簡潔的構造方式ide

// 加括號的函數體返回對象字面表達式:
參數=> ({foo: bar})

// 支持剩餘參數和默認參數
(參數1, 參數2, ...rest) => {函數聲明}
(參數1 = 默認值1,參數2, …, 參數N = 默認值N) => {函數聲明}

// 一樣支持參數列表解構
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f();  // 6
複製代碼

例子:

箭頭函數比較適用於本來須要匿名函數的地方,好比用在數組內置方法map、filter、forEach、reduce的回調函數中

var elements = [
  'Hydrogen',
  'Helium',
  'Lithium',
  'Beryllium'
];

elements.map(function(element) { 
  return element.length; 
}); // 返回數組:[8, 6, 7, 9]

// 上面的普通函數能夠改寫成以下的箭頭函數
elements.map((element) => {
  return element.length;
}); // [8, 6, 7, 9]
複製代碼

重點注意:

this 對象的指向是可變的,可是在箭頭函數中,它是固定的。箭頭函數體內的 this 對象,就是定義時所在的對象,而不是使用時所在的對象。

三. 參數處理

  1. 給函數設置默認參數值

在ES6之前,咱們想要給參數設置默認值得這麼作:

function multiply(a, b) {
  // JavaScript 中函數的參數默認是 undefined
  // 沒有值傳入或者 undefined 被傳入給 b 時給 b 一個默認值
  b = (typeof b !== 'undefined') ?  b : 1;
  return a * b;
}

multiply(5, 2); // 10
multiply(5);    // 5
複製代碼

如今學習了ES6以後就變得很簡單:

function multiply(a, b = 1) {
  return a * b;
}

multiply(5, 2); // 10
multiply(5);    // 5
複製代碼

注意參數的傳遞是從左到右的:

function f(x = 1, y) { 
  return [x, y]; 
}

f(); // [1, undefined]
f(2); // [2, undefined]
複製代碼
  1. 剩餘參數(...)

剩餘參數語法容許咱們將一個不定數量的參數表示爲一個數組。

語法:

function(a, b, ...theArgs) {
   ...
}
複製代碼
  • 必須是函數的最後一個參數以...爲前綴
  • 它是由剩餘實參組成的 Array 數組
  • 這個例子中的 theArgs 收集第三個以及以後的全部實參

實例:

function fun1(...theArgs) {
  alert(theArgs.length); // 可使用全部數組屬性方法
}
fun1();  // 彈出 "0", 由於 theArgs 沒有元素
fun1(5); // 彈出 "1", 由於 theArgs 只有一個元素
複製代碼
  1. 展開運算符(...)

展開語法, 能夠在函數調用/數組構造時, 將數組表達式或者 string 在語法層面展開;還能夠在構造字面量對象時, 將對象表達式按 key-value 的方式展開。

注意: 字面量通常指 [1, 2, 3] 或者 {name: "mdn"} 這種簡潔的構造方式

  • 在函數調用時使用展開語法:
function sum(x, y, z) {
  return x + y + z;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));//6

/****下例表示能夠屢次使用****/

function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
複製代碼
  • 構造字面量數組時使用展開語法:
/****構造字面量數組或鏈接數組****/
var parts = ['shoulders', 'knees']; 
var lyrics = ['head', ...parts, 'and', 'toes']; 
// ["head", "shoulders", "knees", "and", "toes"]
var arr = [...parts, ...lyrics];

/****支持淺拷貝(一維數組)****/
var arr = [1, 2, 3];
var arr2 = [...arr];
arr2.push(4); 
// arr2 此時變成 [1, 2, 3, 4]
// arr 不受影響
複製代碼
  • 構造字面量對象時使用展開語法:
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };

var clonedObj = { ...obj1 };
// 淺拷貝
// 克隆後的對象: { foo: "bar", x: 42 }

var mergedObj = { ...obj1, ...obj2 };
// 合併後的對象: { foo: "baz", x: 42, y: 13 }
複製代碼

四. 模板字面量(模板字符串)

由反引號 `` 來代替單引號 '' 或者雙引號 ""

  • 單行字符串:
`string text`
複製代碼
  • 多行字符串(注意回車也包含在內)

再也不用 "+" 或 "\" 鏈接兩行字符串

`string text line 1 string text line 2`

console.log(`string text line 1 string text line 2`);
複製代碼
  • 插入表達式:

再也不用 "+" 鏈接表達式

`string text ${expression} string text`

var a = 5;
var b = 10;
console.log(`a + b is ${a + b}`);
複製代碼
  • 帶標籤的模板字符串:

標籤使咱們能夠用函數來解析模板字符串。

直接看例子:

var person = 'Mike';
var age = 28;

function myTag(strings, personExp, ageExp) {

  var str0 = strings[0]; // "that "
  var str1 = strings[1]; // " is a "

  var ageStr;
  if (ageExp > 99){
    ageStr = 'centenarian';
  } else {
    ageStr = 'youngster';
  }

  return str0 + personExp + str1 + ageStr;
}

var output = myTag`that ${ person } is a ${ age }`;

console.log(output);
// that Mike is a youngster
複製代碼
  • 原始字符串:

在標籤函數的第一個參數中,存在一個特殊的屬性 raw ,咱們能夠經過它來訪問模板字符串的原始字符串,而不通過特殊字符的替換。

例子:

function tag(strings) {
  console.log(strings.raw[0]);
}
tag`string text line 1 \n string text line 2`;
// logs "string text line 1 \n string text line 2"
複製代碼

五. 對象的擴展

  • 建立對象時能夠簡化方法和重名的鍵值對

通常狀況:

var name="pan";
var age=20;
var people = {
      name: name,
      age: age,
      getName: function() {
           console.log(this.name)
      }
};
複製代碼

ES6簡化後:

var name="pan";
var age=20;
var people = {
      name,
      age,
      getName(){
           console.log(this.name)
      }
};
複製代碼
  • 計算屬性名(屬性名能夠用表達式)
var i = 0;
var a = {
  ["foo" + ++i]: i,
  ["foo" + ++i]: i,
  ["foo" + ++i]: i
};
console.log(a.foo1); // 1
console.log(a.foo2); // 2
console.log(a.foo3); // 3
複製代碼
  • proto

當定義的 屬性:值 爲 proto:值 時,不會建立名爲 proto 的屬性。 但當值爲對象時,將更改原型(由於 proto 本來指向原型)。 因此不建議使用這個屬性名(避免更改 proto 的指向)。

六. 解構賦值

解構賦值語法是一種 JavaScript 表達式,它使得將值從數組,或屬性從對象,提取到不一樣的變量中,成爲可能。

目的就是將數組中的值或對象中的屬性方便的提取到其餘變量中

  • 解構數組語法:
var x, y;
[x, y] = [1, 2, 3];
console.log(x); // 1
console.log(y); // 2

// 或者:
var [x, y] = [1, 2, 3];
console.log(x); // 1
console.log(y); // 2
複製代碼

小技巧(不用臨時變量也能交換變量):

var a = 1;
var b = 3;
// 等價於[a,b]=[3,1]
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
複製代碼
  • 解構對象語法:
var o = {p: 42, q: true};
var {p, q} = o;

console.log(p); // 42
console.log(q); // true
複製代碼

注意:對象解構與數組解構有一個重要的不一樣點,數組的元素是按次序排列的,變量的取值由它的位置決定;而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。

七. 模塊(import/export)

模塊功能主要由兩個命令構成:export 和 import。export 命令用於規定模塊的對外接口,import 命令用於輸入其餘模塊提供的功能。

一個模塊就是一個獨立的文件。該文件內部的全部變量,外部沒法獲取。若是你但願外部可以讀取模塊內部的某個變量,就必須使用 export 關鍵字輸出該變量。下面是一個 JS 文件,裏面使用 export 命令輸出變量。

  • 導出 export
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};
複製代碼
  • 上面代碼是 profile.js 文件,保存了用戶信息,
  • ES6 將其視爲一個模塊,裏面用 export 命令對外部輸出了三個變量。
  • 除了這種普通變量,輸出的變量還能夠是一個函數。
  • 另外,export 語句輸出的接口,與其對應的值是動態綁定關係,
  • 即經過該接口,能夠取到模塊內部實時的值。
  • 最後,export/import 命令不能在塊級做用域內,能夠在全局做用域任何位置。
  • 導入 import

import 語句只能在聲明瞭 type="module" 的 script 的標籤中使用。 動態導入:import(),它不須要依賴type="module" 的 script 標籤。 按照必定的條件或者按需加載模塊的時候,動態 import() 是很是有用的。 而靜態的 import 是初始化加載的最優選擇。

// main.js
import {firstName, lastName, year} from './profile.js';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}
複製代碼
  • 上面代碼的 import 命令,用於加載 profile.js 文件,並從中輸入變量。
  • import 命令接受一對大括號,裏面指定要從其餘模塊導入的變量名。
  • 大括號裏面的變量名,必須與被導入模塊(profile.js)對外接口的名稱相同。

注意:import 語句會執行所加載的模塊:

import './lodash.js';
// 執行lodash模塊,可是不輸入任何值
複製代碼

總體導入:

import * as myModule from './my-module.js'; // 不用加大括號 {}
// 將 my-module 裏面輸出的變量/函數,
// 輸入到 myModule 這個對象中做爲屬性/方法。
// 經過 myModule.屬性名 / myModule.方法() 來調用。
複製代碼
  • 默認導出/導入默認值:

告別使用 import 命令的時候,用戶須要知道所要加載的變量名或函數名的現狀:

// 先用 export default 語法默認導出
// 既然是默認輸出,那麼一個模板只能使用一次
export default function foo() {
  console.log('foo');
}

// 導入默認值
import customName from './default.js'; // 不用加大括號 {}
customName(); // 'foo'
複製代碼

八. 類

ES6 中引入的 JavaScript 類實質上是 JavaScript 現有的基於原型的繼承的語法糖。類語法不會爲 JavaScript 引入新的面向對象的繼承模型。

  • 如何建立類:
class Rectangle {
  constructor(height, width) { //構造方法
    this.height = height;
    this.width = width;
  }
}
// 或者
let Rectangle = class {
  constructor(height, width) { //構造方法
    this.height = height;
    this.width = width;
  }
};
複製代碼
  • 如何使用類:
class Rectangle {
    // constructor
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }
    // Getter
    get area() {
        return this.calcArea()
    }
    // Method
    calcArea() {
        return this.height * this.width;
    }
}
const square = new Rectangle(10, 10);

console.log(square.area); // 100
複製代碼
  • 類的靜態方法:

不能經過一個類實例調用靜態方法(這裏和 Java 語法有區別)

class Point {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    static distance(a, b) { // static 語法
        const dx = a.x - b.x;
        const dy = a.y - b.y;

        return Math.hypot(dx, dy);
    }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
// 直接經過類名調用
console.log(Point.distance(p1, p2));
複製代碼
  • 類的繼承(extends)
class Animal { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

class Dog extends Animal {
   constructor(name) {
    super(name); // 調用超類構造函數
  }

  speak() {
    console.log(this.name + ' barks.');
  }
}

var d = new Dog('Mitzie');
// 'Mitzie barks.'
d.speak();
複製代碼
  • 調用父類方法(super)
class Cat { 
  constructor(name) {
    this.name = name;
  }
  
  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

class Lion extends Cat {
  speak() {
    super.speak();
    console.log(this.name + ' roars.');
  }
}
複製代碼

九. Promise 對象

這部份內容是重難點,說是面試必考的知識點也不過度,由於它不易簡單的進行總結,因此我推薦讀到這裏的朋友去細讀 阮一峯Promise ,進行系統的學習這部份內容。

十. End 感謝閱讀

留下寶貴的一讚再走!

img-16259633876812169a61ab3330f5437ee31d7546c0cd7.jpg

相關文章
相關標籤/搜索