JavaScript & 6小時瞭解ES6基本語法

一步一步似爪牙。html

前言

學習es6以前咱們可能並不知道es6相比es5差距在哪, 可是這並不妨礙咱們站在巨人的肩膀上; 程序員就是要樂於嚐鮮;
學習es6最終目的是結合es5 一塊兒進行工程項目開發, 而不是徹底拋棄es5 ;
學習的方法是文檔爲主, 前人的blog爲輔助, 實際console爲最終標準 ;
注意!
留意TODO關鍵詞node

ECMAScript 新功能 & 新特性

http://mp.weixin.qq.com/s?__b...程序員

塊的做用域-let

if (true) {
    console.log(a) // 報錯 : Uncaught ReferenceError: a is not defined(…)
    let a = 'js'
} 
// 這裏也訪問不到 a
  • 一個做用域不能重複聲明同一個值
if(true){
    var a = 1;
    if (true) {
        let a = 'js' // a == 'js'
    } 
    a = 3; // a == 3;
    let a = 2 ; // 報錯Uncaught SyntaxError: Identifier 'a' has already been declared ; 

    // 題外話, 在console中, 產生報錯後a的內存指引被清除, 能夠從新賦值
    let a = 0; // a == 0
    // 但實際開發中, 產生報錯, 後面的代碼再也不執行, 因此不會有這種狀況產生
}

恆量-const

const a = 1;
a = 2; // 報錯 : Uncaught TypeError: Assignment to constant variable.(…)
  • const聲明的數組, 對象, 還能夠進行增改查, 可是不能從新定義
const a = [];
    a.push(2)   // a == [2]

const b = {};
    b.a = a ;   // 包含了a數組的對象
  • 只在聲明的做用域有效(與let同樣)
if(true){
    const c = 1;
} 
// 此處訪問會報錯:   Uncaught ReferenceError: c is not defined(…)

總結: 能夠把const理解爲let的常量版(不可改的let)es6


解構數組-Array Destructuring

參考:
let [a, b, c] = [1, 2, 3];
// 即: let a = 1;let b = 2;let c = 3;

let [bar, foo] = [1];
// 解構失敗: undefined
// 即: let bar = 1; let foo = undefined

let [a] = 1;
// 等號的右邊不是數組 (或者嚴格地說,不是可遍歷的解構)
// 報錯:VM2799:2 Uncaught TypeError: undefined is not a function(…)

// 若是賦值的字面量全等undefined, 則默認值生效
let [x = 1] = [undefined];// x  === 1
let [x = 1] = [];//x  ===  1

// null 不全等 undefined, 因此默認值不生效
let [x = 1] = [null];// x  === null
  • 進階語法
// 解構賦值容許指定默認值。
let [foo = true] = []; // 即: foo === true
  • 坑!當心
function f() {
  console.log('aaa');
}
let [x = f()] = [1];// x === 1
// 此處f函數並無執行; 若是是es5, 在賦值過程當中, 確定會先執行f()方法: log('aaa')
// es6 沒有執行f方法, 通過粗略查閱文檔, 百穀後, 並無獲得答案; 生命有限, 留待往後, TODO
// 在與`MeatHill`老師交流事後,得知 , 在此處後面有具體的值,就不須要計算默認值, 賦值是從右往左運行
  • 奇奇怪怪的, 我猜可能會出面試題
let [x = 1, y = x] = [];   // x == 1; y == 1; 
 
let [x = 1, y = x] = [2];  // x == 2; y == 2; 別急, 一步一步來
// 第一步: x = 2(賦值從右到左, x = 1 不會計算);
// 第二步: y = x = 2;

let [x = 1, y = x] = [1, 2]; // 答案呢? 留着想

let [x = y, y = 1] = [];  
// 第一步  x = y ; y未聲明報錯

解構對象-Object Destructuring

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

  • 語法
let { foo, bar } = { foo: "aaa", bar: "bbb" }; 
// 變量必須與屬性重名
// 以上實際上是 let { foo : foo, bar : bar } = { foo: "aaa", bar: "bbb" };的簡寫;  
// 對象的解構賦值的內部機制,是先找到同名屬性,而後再賦給對應的變量。真正被賦值的是後者,而不是前者
// foo === "aaa"; bar === "bbb"


let {foo} = {bar: 'baz'}; 
// foo === undefined


let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
// 數值也屬於對象的一種表現形式
  • 默認值
let {x = 3} = {x: undefined};
// x === 3
// 默認值生效的條件是,對象的屬性值嚴格等於undefined。
  • 注意
let { foo: baz } = { foo: "aaa", bar: "bbb" };
// 上面代碼中,foo是匹配的模式,baz纔是變量。真正被賦值的是變量baz,而不是模式foo。
  • 高階(解析嵌套結構)
let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};
let { p: [x, { y }] } = obj
// 注意,這時p是模式,不是變量,所以不會被賦值。
  • 疑難雜症
let {foo: {bar}} = {baz: 'baz'};
// 報錯 : VM3721:2 Uncaught TypeError: Cannot match against 'undefined' or 'null'.(…)
// 報錯 : 等號左邊對象的foo屬性,對應一個子對象。該子對象的bar屬性,解構時會報錯。緣由很簡單,由於foo這時等於undefined,再取子屬性就會報錯

let x;
{x} = {x: 1};
// 報錯: 由於JavaScript引擎會將{x}理解成一個代碼塊,從而發生語法錯誤。
// 應該不將大括號寫在行首,避免JavaScript將其解釋爲代碼塊, 正確的寫法:
let x;
({x} = {x: 1})面試


其餘數據的解構-Object Destructuring

函數參數的解構(解構參數 - Destructured Parameters)

// 第三個參數默認值爲 {}
function demo(a, b, {c , d} = {}){
    console.log(a, b, c, d)
    // 1  2 'c' 'd'
}
demo(1, 2, {c : "c", d:"d"})

字符串的解構賦值

let [a, b, c, d, e] = 'hello'
// a === 'h', b === 'e', ......

let {length} = 'hello';
// length === 5
// 相似數組的對象都有一個length屬性,所以還能夠對這個屬性解構賦值
  • 小總結segmentfault

    • 數組的解構賦值對應的是位置
    // 因此能夠交換變量的值
    let x = 1;
    let y = 2;
    [x, y] = [y, x];
    • 對象對應的是鍵名
  • 解構的意義數組

    • 數組結構能夠方便快速的交換變量的值
    • 接受函數return的值, 若是函數返回array或者object, 利用解構方便快捷
    • 解析JSON數據
    • 代替 ||

模版字符串-Template Strings

參考
let name = "Bob", 
    time = "today";
console.log(`Hello ${name}, how are you ${time}?`)
// 模板字符串都是用反引號表示,若是在模板字符串中須要使用反引號,則前面須要用反斜槓轉義
  • 多行字符串
console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"

帶標籤的模版字符串-Tagged Templates

參考
function a(b, ...c){
    console.log(b)
    // ["個人年齡是", ",個人性別是", "", raw: Array[3]]

    console.log(c)
    // Array : ["1", "nan"]
}
let d = "1";
a`個人年齡是${d},個人性別是${f}`

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


判斷字符串裏是否包含其餘字符串

傳統上,JavaScript只有indexOf方法,能夠用來肯定一個字符串是否包含在另外一個字符串中。ES6又爲String對象擴展了三種新方法。

參考
'Blue Whale'.includes('blue'); // return false
'Blue Whale'.includes('Whale' , 2); // return true
  • startsWith():返回布爾值,表示參數字符串是否在源字符串的頭部。
'Blue Whale'.startsWith('blue'); // return false
'Blue Whale'.startsWith('Whale' , 2); // return false
'Blue Whale'.startsWith('Whale' , 5); // return true
  • endsWith():返回布爾值,表示參數字符串是否在源字符串的尾部。
'Blue Whale'.endsWith('blue'); // return false
'Blue Whale'.endsWith('Whale' , 10); // return true
'0Blue'.endsWith('Blue' , 5); // return true

默認參數 - Default Parameter Values

之前es5 : 
function makeRequest(url, timeout, callback) {
    timeout = timeout || 2000;
    callback = callback || function() {};
    // ...
}

如今es6 :
function makeRequest(url, timeout = 2000, callback = function(){}) {
    // ...
}

若是不傳入參數, 或者傳入undefined, 則使用默認值;


展開操做符-Spread

參考:

語法

console.log(...[1, 2, 3])
// 1 2 3

console.log(1, ...[2, 3, 4], 5);
// 1 2 3 4 5

用於函數調用

function func(x, y, z, a, b) {
    console.log(x, y, z, a, b);
}
var args = [1, 2];
func(0, ...args, 3, ...[4]); // 0 1 2 3 4

更好的 apply 方法

// es5使用數組做爲參數:
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);

// es6使用數組做爲參數:
function demo(x, y, z) { 
    console.log(x, y, z)
}
var args = [0, 1, 2];
demo(...args);

淺複製一個數組

let arr = [1, 2, 3];
let arr2 = [...arr]; // 就像是 arr.slice()

arr2.push(4); 

console.log(arr2) // [1, 2, 3, 4]
// arr 不受影響

合併數組

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1  , ...arr2]
// arr3 : [0, 1, 2, 3, 4, 5]

將類數組對象轉換成數組

var nodeList = document.querySelectorAll('div');
var array = [...nodeList];
// 實際: 360瀏覽器報錯 : VM2386:3 Uncaught TypeError: nodeList[Symbol.iterator] is not a function(…)
// 版本: 8.7.0.306

// 火狐爲一個空數組
// 版本:26.0.0.137

// google爲undefined
// 版本:57.0.2987.133

剩餘操做符Rest - 剩餘參數(rest參數)

參考

定義:

剩餘參數只包含那些沒有對應形參的實參

語法:

function(a, b, ...restArgs) {
  // ...restArgs 即爲剩餘參數, 是一個Array對象
}

剩餘參數和 arguments 對象的區別

  • 剩餘參數只包含那些沒有對應形參的實參,而 arguments 對象包含了傳給函數的全部實參。
  • arguments 對象不是一個真實的數組,而剩餘參數是真實的 Array實例,也就是說你可以在它上面直接使用全部的數組方法,好比 sort,map,forEach,pop。
  • arguments 對象對象還有一些附加的屬性 (好比callee屬性)。

實例:

function fun1(...theArgs) {
  alert(theArgs.length);
}
 
fun1();  // 彈出 "0", 由於theArgs沒有元素
fun1(5); // 彈出 "1", 由於theArgs只有一個元素
fun1(5, 6, 7); // 彈出 "3", 由於theArgs有三個元素

Object.keys() - 返回對象可枚舉的鍵

// TODO

函數的名字-name屬性

函數的name屬性,返回該函數的函數名。
這個屬性早就被瀏覽器普遍支持,可是直到 ES6 ,纔將其寫入了標準。

實例:

function foo() {}  
foo.name // "foo"

值得一提:

  • 並不徹底支持的ES6(360瀏覽器環境)
var a = function(){}
a.name
// 空字符串: "" 

let b = function(){}
b.name
// 一樣是 ""

解讀:
ES6 對這個屬性的行爲作出了一些修改。若是將一個匿名函數賦值給一個變量, ES5 的name屬性,會返回空字符串,而 ES6 的name屬性會返回實際的函數名。

但實際上國內目前主流瀏覽器支持的仍是es5爲主, 在node下搭建的es6環境, 纔會返回實際的函數名(Google測試已經支持)

  • 函數名的優先級
let a = function d(demo){}
a.name // "d"

箭頭函數-Arrow Fuctions

重點:
!箭頭函數會捕獲其所在上下文的 this 值,做爲本身的 this 值
!也就是能夠理解爲: 箭頭函數沒有本身的this, 若是上下文沒有this, 則this指向Window對象

參考

語法

  • 基礎語法
let demoFun = oArgument => oDessert
// demoFun 爲函數名
// oArgument 爲函數形參
// oDessert 爲返回的值


let func = (x, y) => { return x + y; }; 
//常規編寫 明確的返回值
  • 高級語法
let demoFun = (oArgument, drink) => oArgument + drink
// 返回的是 oArgument + drink

let demoFun = params => ({foo: bar})
//返回一個對象時,函數體外要加圓括號

let demoFun = (param1, param2, ...rest) => { statements }
// 支持 剩餘參數和默認參數:

描述

  • 不綁定 this

箭頭函數會捕獲其所在上下文的 this 值,做爲本身的 this 值,所以下面的代碼將如期運行。

function Person() {  
    this.age = 0;  
    setInterval(() => {
        // 回調裏面的 `this` 變量就指向了指望的那個對象了
        this.age++;
    }, 3000);
}
var p = new Person();
  • 箭頭函數沒有本身的 arguments
var arr = () => arguments;
arr();  // Uncaught ReferenceError: arguments is not defined(…)
  • 箭頭函數不能用做構造器,和 new 一塊兒用就會拋出錯誤。
var Foo = () => {};
var foo = new Foo();  // TypeError: Foo is not a constructor
  • 箭頭函數沒有原型屬性。
var Foo = () => {};
console.log(Foo.prototype); // undefined
  • 箭頭不是操做符

在箭頭函數中的箭頭不是操做符(或者運算符,就像'+ -'那些), 可是箭頭函數有特殊的解析規則就是:相比普通的函數,受操做符的優先級影響。參考: https://developer.mozilla.org...

let callback;
callback = callback || function() {}; // ok
callback = callback || () => {};      // SyntaxError:非法箭頭函數屬性
callback = callback || (() => {});    // ok

疑難雜症

  • 像方法同樣使用箭頭函數
'use strict';
let obj = {
  i: 10,
  b: () => console.log(this.i, this),
  c: function() {
    console.log( this.i, this)
  }
}
obj.b(); // undefined, Window對象, 此處或許有疑問, 可翻閱?提過的`!`
obj.c(); // 10, Object {...}
  • 不能返回預期的對象
let func = () => {  foo: 1  };
// undefined

因此,記得用圓括號把文字表達式包起來:

var func = () => ({ foo: 1 });

箭頭u函數在某些狀況加仍是頗有便利的, 可是新的語法, 可讀性有所轉變, 要多使用, 多看才行


for..of

// TODO

symbol

參考:
https://developer.mozilla.org...
// TODO

對比兩個值是否相等-Object.is()

Object.is() 方法肯定兩個值是不是 相同的值。

參考:

語法

Object.is(value1, value2); // 返回一個布爾值

與ES5 的 全等操做符比較

  • ES6:
Object.is(NaN, NaN); // true

Object.is(0, -0); // fasle
Object.is(-0, +0) // false

Object.is({},{})  // false

var a = function () {};
var b = function () {};
Object.is(a, b) //false
  • ES5
NaN === NaN // false;

0 === -0 // true
-0 === +0 // true

{} === {} // false

var a = function () {};
var b = function () {};
a === b //false

兼容ES5 環境

if (!Object.is) {
  Object.is = function(x, y) {
    // SameValue algorithm
    if (x === y) { // Steps 1-5, 7-10
      // Steps 6.b-6.e: +0 != -0
      return x !== 0 || 1 / x === 1 / y;
    } else {
      // Step 6.a: NaN == NaN
      return x !== x && y !== y;
    }
  };
}

把對象的值複製到另外一個對象裏 - Object.assign() - 淺拷貝

定義:

Object.assign() 方法用於將全部可枚舉的屬性的值從一個或多個源對象複製到目標對象。它將返回目標對象。

語法:

// target目標對象。
// sources(多個)源對象。
Object.assign(target, ...sources)

實例:

var obj = { a: 1 };
var copy = Object.assign({}, obj); // {a: 1}

合併對象:

var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign({},o1, o2, o3); // Object {a: 1, b: 2, c: 3}

注意

  • 繼承屬性和不可枚舉屬性是不能拷貝的
  • 原始類型會被包裝爲 object
var v1 = "abc";
var v2 = true;
var v3 = 10;
var v4 = Symbol("foo")

var obj = Object.assign({}, v1, null, v2, undefined, v3, v4); 
// 原始類型會被包裝,null 和 undefined 會被忽略。
// 注意,只有字符串的包裝對象纔可能有自身可枚舉屬性。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
  • 異常會打斷接下來的拷貝任務

設置對象的 prototype - Object.setPrototypeOf()

參考:

定義:

Object.setPrototypeOf() 方法設置一個指定的對象的原型 ( 即, 內部[[Prototype]]屬性)到另外一個對象或 null。

語法:

Object.setPrototypeOf(obj, prototype)
// obj          要設置其原型的對象。.
// prototype    該對象的新原型(一個對象 或 null).

實例:

var dict = Object.setPrototypeOf({}, null); // Object {}

proto

參考

es6 能夠設置對象的__proto__


super

參考:
https://developer.mozilla.org...

定義:

super 關鍵字用於調用一個對象的父對象上的函數。


迭代器 - Iterators

參考:
  • MDN -迭代器&生成器 : https://developer.mozilla.org...
  • ES6學習——迭代器(Iterators):迭代器接口高級應用 - Challenge Next Challenge - CSDN博客

http://blog.csdn.net/kittyjie...


生成器 - Generators

參考:

Classes - 類

  • JavaScript 現有的基於原型的繼承的語法糖, 提供了一個更簡單和更清晰的語法來建立對象並處理繼承。
  • 類其實是個「特殊的函數」,就像你可以定義的函數表達式和函數聲明同樣,類語法有兩個組成部分:類表達式和類聲明。
參考:

類聲明

使用class關鍵字聲明

// 聲明一個類名爲 Rectangle  的JS類
// constructor方法用於建立和初始化使用一個類建立的一個對象。只容許存在一個
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

類聲明不會聲明提高

類表達式

類表達式能夠是被命名的或匿名的。

/* 匿名類 */ 
let Rectangle = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

/* 命名的類 */ 
let Rectangle = class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

this

若是沒有指定this, this值將爲undefined。

class Animal { 
  speak() {
    return this;
  }
  static eat() {
    return this;
  }
}

let obj = new Animal();
let speak = obj.speak;
speak(); // undefined

let eat = Animal.eat;
eat(); // undefined

demo :

"use strict"
// 建立一個 Chef 類
class Chef {
    // 初始化
    // 接收參數
    constructor(food){
        this.food = food;
    }

    cook(){
        console.log(this.food)
    }

}
let qing = new Chef("?")
qing.cook(); // ?

類的 get 與 set

參考:
http://blog.csdn.net/qq_30100...
"use strict"
// 建立一個 Chef 類
class Chef {
    // 初始化
    // 接收參數
    constructor(food){
        this.food = food;
        this.dishs = [];
    }

    get menu(){
        return this.dishs;
    }

    set menu(dishs){
        this.dishs.push(dish)
    }

    cook(){
        console.log(this.food)
    }

}
let qing = new Chef()
console.log(qing.menu = "?") //?
console.log(qing.menu = "❦") // ❦

類的靜態方法-staitc

demo

"use strict"
// 建立一個 Chef 類
class Chef {
    // 初始化
    // 接收參數
    constructor(food){
        this.food = food;
        this.dishs = [];
    }

    get menu(){
        return this.dishs;
    }

    set menu(dishs){
        this.dishs.push(dish)
    }

    static cook(food){
        console.log(food)
    }

}

// 不須要實例化Chef便可以直接使用
Chef.cook("?") 
// 輸出 : ?

類的繼承-extends

demo

"use strict"
class Person{
    constructor(name, birthday){
        this.name = name
        this.birthday = birthday
    }

    intro(){
        return `${this.name}, ${this.birthday}`
    }
}

// 使得Chef類 繼承 Person類
class Chef extends Person{
    constructor(name, birthday){
        // 調用父類的constructor函數 
        super(name, birthday)
    }
}

let qing = new Chef('qing', "1949-10-1");

// 實例化後纔可以使用 Chef類 的intro方法
qing.intro() // "qing, 1949-10-1"

Set方法

參考:

定義:

Set 對象容許你存儲任何類型的惟一值,不管是原始值或者是對象引用。

語法:

new Set([iterable]);
// iterable 
// 若是傳遞一個可迭代對象,它的全部元素將被添加到新的 Set中。
// 若是不指定此參數或其值爲null,則新的 Set爲空

// 返回值
// 一個新的Set對象。

! 使用Set去重, Set中的元素只會出現一次, Set 中的元素是惟一的

DEMO:
  • 使用Set對象
let mySet = new Set();

mySet.add(1); // {1}
mySet.add(5); // {1, 5}
mySet.add("some text"); //{1, 5, "some text"}

mySet.has(1); // true
mySet.has(3); // false
mySet.has(5); // true
mySet.has(Math.sqrt(25));  // true
mySet.has("Some Text".toLowerCase()); // true

mySet.size; // 返回Set對象的值的個數 : 3

mySet.delete(5); //  從set中移除5並返回true
mySet.delete(8); //  不存在8, 返回false
mySet.has(5);    // false, 5已經被移除

mySet.size; // 2, 咱們剛剛移除了一個值

// 按照插入順序,爲Set對象中的每個值調用一次callBackFn。若是提供了thisArg參數,回調中的this會是這個參數。
mySet.forEach(callbackFn[, thisArg])

// 與values()方法相同,返回一個新的迭代器對象,該對象包含Set對象中的按插入順序排列的全部元素的值。
mySet.keys()

// 返回一個新的迭代器對象,該對象包含Set對象中的按插入順序排列的全部元素的值。
mySet.values()


mySet.clear() // 清空所有值

與 Array 的聯繫 , 互換

var myArray = ["value1", "value2", "value3"];

// 用Set構造器將Array轉換爲Set
var mySet = new Set(myArray);

mySet.has("value1"); // returns true

// 用...(展開操做符)操做符將Set轉換爲Array
console.log([...mySet]); // 與myArray徹底一致

Map方法

參考:
https://developer.mozilla.org...

定義:

Map 對象保存鍵值對。任何值(對象或者原始值) 均可以做爲一個鍵或一個值。

實例:

var myMap = new Map();
 
var keyObj = {},
    keyFunc = function () {},
    keyString = "a string";
 
// 添加鍵
myMap.set(keyString, "和鍵'a string'關聯的值");
myMap.set(keyObj, "和鍵keyObj關聯的值");
myMap.set(keyFunc, "和鍵keyFunc關聯的值");
 
myMap.size; // 3
 
// 讀取值
myMap.get(keyString);    // "和鍵'a string'關聯的值"
myMap.get(keyObj);       // "和鍵keyObj關聯的值"
myMap.get(keyFunc);      // "和鍵keyFunc關聯的值"
 
myMap.get("a string");   // "和鍵'a string'關聯的值"
                         // 由於keyString === 'a string'
myMap.get({});           // undefined, 由於keyObj !== {}
myMap.get(function() {}) // undefined, 由於keyFunc !== function () {}

注意:

  • Map 認爲 NaN === NaN
var myMap = new Map();
myMap.set(NaN, "not a number");
myMap.get(NaN); // "not a number"

相比較:

  • Map能夠得到length, Object不能夠
  • Map的鍵能夠是任意字, Object的只能爲字符串, 或者變量
  • Map 認爲 NaN === NaN
  • Map內置不少迭代, 查詢, 操做方法

結語

  • 花了半天時間學習了下ES6的部分新語法丶新特性。 不求精通, 但說涉獵。不實踐怎麼來的發言權 ;
  • ES6新增了不少方法和功能參數, 可是其實相對於ES5來, 變革性並非那麼大, 學起來興趣乏乏, 有點像雞肋;
  • ES6中我最感興趣的是Promise , Class, 期待ES8的異步函數(Async Functions) ;
  • 項目中打算深刻實踐ES6, 畢竟這波不虧 ? ;

原文地址: https://segmentfault.com/a/11... 轉載無需聯繫, 但請著名來源 @SF.GG-Starch。程序員就是要勇於, 樂於嚐鮮;
相關文章
相關標籤/搜索