ES6入門

整理了ES6經常使用的一些語法,跟你們分享(promise、generator什麼的尚未梳理清楚,後續再更新。。。)git

1⃣️ 變量聲明-let 與 constes6

(首先關於測試結果:這裏有個小問題,若是用let/const聲明的變量,在控制檯調試的話,第一次輸出結果後,第二次若是你還想用,要麼把代碼放入編輯器中,再打開瀏覽器看結果,要麼就把變量名更改從新輸入結果,不然是會報錯的)
  let與const的做用與var 相似,都是用來聲明變量可是在實際應用中,它倆有各自的特殊用途
github

  (注意:ES6裏let和const沒有變量的提高,必定要聲明後再使用,但代碼編譯成ES5以後,變量提高依舊存在)express

  先舉個栗子編程

var name = 'aaron';

if(true) {
    var name = 'peter';
    console.log(name); // peter
}

console.log(name);  //peter

  咱們能夠看到,使用var聲明的變量,兩次輸出結果都是peter,那是由於ES5裏只有全局做用域和函數做用域,沒有塊級做用域,那麼咱們怎麼才能讓它兩次打印的結果分別是aaron 和 peter呢? 如今let就能夠派上用場了  數組

  改造一下上面的栗子promise

let name = 'aaron';

if(true) {
    let name = 'peter';
    console.log(name); // peter
}

console.log(name);  //aaron

  如今能夠看到,兩次的結果已經不相同了,let實際上爲JavaScript新增了塊級做用域。用它所聲明的變量,只在let命令所在的代碼塊內有效。瀏覽器

  下面再來看一發關於關於for循環的栗子,問題就是用來計數的循環變量泄露爲全局變量,會對咱們的一些操做帶來很大的影響,話很少說,來看栗子閉包

var a = [];
for (var i = 0; i < 10; i++) { a[i] = function() { console.log(i) }; } a[6](); //10

   本來咱們的需求是 a[6](),結果能夠輸出6,但不管咱們寫的是a[i](),最終輸出的結果都是10,由於for循環結束以後,i的值已經變成了10,而i又是全局變量,當函數之行的時候,首先在函數體內部沒有i這麼一個變量,因此它會去上一級做用域去尋找,本慄中它的上一級做用域就是全局做用域,因此也就找到了已經變爲10的全局變量i,因此a[i]();不管你[]內寫0~9哪一個數字,最終輸出結果都是10;app

  在沒有ES6以前,若是咱們想讓它的輸出就過就是6,就要使用到閉包(閉包這東西,我的的理解,用大白話說就是把你想要實現功能的方法,外面再給它包一個函數。內部return你要實現功能的方法,因爲函數的做用域,這樣能夠避免變量泄露變成全局變量,從而帶來一些咱們不想看到的結果)

var a = [];
function fn(i){
    function inner() {
        console.log(i);
    }
    return inner;
}
for (var i = 0; i < 10; i++) {
  a[i] = fn (i);
}
a[6](); //6

  講真,這樣很麻煩有沒有?如今有了ES6 的let ,徹底能夠不用這麼寫了

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function() {
        console.log(i)
    };
}
a[6](); //6

   只是改了幾個字母,var改爲了let,已經實現了咱們的需求,很方便有沒有?!

  const也用來聲明變量,可是聲明的是常量。一旦聲明,常量的值就不能改變。改變的話,瀏覽器會報錯

  栗子

const A = 1;
A = 2; // Uncaught TypeError: Assignment to constant variable.

  針對const的這個特性,咱們能夠在引用第三方庫的時,把須要聲明的變量,用const來聲明,這樣能夠避免將來不當心重命名而致使出現bug

const xxx = require('xxxxx');

 注意:當值爲基礎數據類型時,那麼這裏的值,就是指值自己。
    而當值對應的爲引用數據類型時,那麼這裏的值,則表示指向該對象的引用。這裏須要注意,正由於該值爲一個引用,只須要保證引用不變就能夠,咱們仍然能夠改變該引用所指向的對象。

  栗子

const obj = {
    a: 20,
    b: 30
}

obj.a = 30;
obj.c = 40; console.log(obj); // Object {a: 30, b: 30,c:40}
這種狀況下只要不是直接覆蓋obj的值,只改變屬性什麼的仍是還能夠

 2⃣️模版字符串

使用 反引號``(鍵盤上esc下面那個鍵) 將整個字符串包裹起來,而在其中使用 ${} 來包裹一個變量或者一個表達式
// es5
var a = 20;
var b = 30;
var string = a + "+" + b + "=" + (a + b);

// es6
const a = 20;
const b = 30;
const string = `${a}+${b}=${a+b}`;

 3⃣️解構(destructuring)賦值

  數組以序列號一一對應,這是一個有序的對應關係。
  對象根據屬性名一一對應,這是一個無序的對應關係。

  爲了更好的理解,直接上栗子吧
 數組的解構賦值
// es5
var arr = [1, 2, 3];
var a = arr[0];
var b = arr[1];
var c = arr[2];

// es6
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a,b,c) // 1,2,3
  對象的解構賦值
const MYOBJ = {
    className: 'trigger-button',
    loading: false,
    clicked: true,
    disabled: 'disabled'
}

如今咱們想要取得其中的2個值:loading與clicked:

// es5
var loading = MYOBJ.loading;
var clicked = MYOBJ.clicked;

// es6
const { loading, clicked } = MYOBJ;
console.log(loading);// false // 還能夠給一個默認值,當props對象中找不到loading時,loading就等於該默認值 const { loadings = false, clicked } = MYOBJ;
console.log(loadings);// false

 

4⃣️展開運算符(spread operater)

   在ES6中用...來表示展開運算符,它能夠將數組方法或者對象進行展開。上栗子

1.函數調用中使用展開運算符

  函數調用裏,將一個數組展開成多個參數,咱們會用到apply:

function test(a, b, c) { }
var args = [0, 1, 2];
test.apply(null, args);

  在ES6裏能夠這樣寫

function test(a,b,c) { }
var args = [0,1,2];
test(...args);

2.數組字面量中使用展開運算符

  有了ES6,咱們能夠直接加一個數組直接合併到另一個數組當中

const arr1 = [1, 2, 3];
const arr2 = [...arr1, 10, 20, 30];

// 這樣,arr2 就變成了[1, 2, 3, 10, 20, 30];

  展開運算符也能夠用在push函數中,能夠不用再用apply()函數來合併兩個數組:

var arr1=['a','b','c'];
var arr2=['d','e'];
arr1.push(...arr2); //['a','b','c','d','e']

3.用於解構賦值

let [arg1,arg2,...arg3] = [1, 2, 3, 4];
arg1 //1
arg2 //2
arg3 //['3','4']

  注意:解構賦值中展開運算符只能用在最後,不然會報錯

4.展開運算符能夠將僞數組變成真正的數組

var list=document.querySelectorAll('div');
var arr=[..list];

  Object.prototype.toString.apply(list) // "[object NodeList]"
  Object.prototype.toString.apply(arr) // "[object Array]"

 

關於對象展開
好像目前ES6還不支持這樣,如今這樣寫瀏覽器會報錯,ES7草案裏貌似有提到,因此對象展開這裏先了解一下就行了
const obj1 = { a: 1, b: 2, c: 3 } const obj2 = { ...obj1, d: 4, e: 5, f: 6 } // 結果相似於 const obj2 = Object.assign({}, obj1, {d: 4,e:5,f:6})
擴展: 方法用於將全部可枚舉的屬性的值從一個或多個源對象複製到目標對象。它將返回目標對象。 語法:
Object.assign()Object.assign(target, 一個或多個sources)

5⃣️ arrow function箭頭函數

  函數的快捷寫法,不須要經過 function 關鍵字建立函數,而且還能夠省略 return 關鍵字。(注意:箭頭函數自己沒有this,若是在箭頭函數內使用this,這個this必定是它上級的this,再有就是箭頭函數能夠代替函數表達式,但代替不了函數聲明,它仍是須要聲明才能使用的)。

 (parma)=>{expression},箭頭函數根據parma個數的不一樣,寫法上還能夠作以下改變
() => { expression } // 零個參數用 () 表示
x => { expression } // 一個參數能夠省略 ()
(x, y) => { expression } // 多參數不能省略 ()

注意: 在ES6中,會默認採用嚴格模式,所以this也不會自動指向window對象了,而箭頭函數自己並無this,所以this就只能是undefined,這一點,在使用的時候,必定要慎重慎重再慎重,否則踩了坑你都不知道本身錯在哪!這種狀況,若是你還想用this,就不要用使用箭頭函數的寫法。

  栗子

var person = {
    name: 'tom',
    getName: function() {
        return this.name;
    }
}

// 用ES6的寫法來重構上面的對象
const person = {
    name: 'tom',
    getName: () => this.name
}

// 可是編譯結果倒是
var person = {
    name: 'tom',
    getName: function getName() {
        return undefined.name;
    }
};

對上面的代碼稍做改動

const person = {
    name: 'tom',
    getName: function() {
        return setTimeout(() => this.name, 1000);
    }
}

// 編譯以後變成
var person = {
    name: 'tom',
    getName: function getName() {
        var _this = this;  // 使用了咱們在es5時經常使用的方式保存this引用

        return setTimeout(function () {
            return _this.name;
        }, 1000);
    }
};

6⃣️函數參數的默認值

以前咱們想要保證傳入函數的參數有一個默認值,一般須要這麼寫
function add(x) {
    var x = x || 20;
    return x;
}

console.log(add()); // 20

但這種方法是有缺陷的,好比說咱們若是傳入一個false

function add(x) {
    var x = x || 20;
    return x;
}

console.log(add(false)); // 20

打印結果是20 而不是fasle,顯然合格結果不是咱們想要的,若是咱們想要打印出false,就還要再作什麼if判斷等一些列操做,很麻煩,如今有了es6,咱們能夠很容易解決這個問題,下面咱們來看一下es6的寫法

function add(x = 20) {
    return x ;
}

console.log(add());// 20
console.log(add(false)); // false
能夠看到,es6很容易就解決了這個問題。
7⃣️對象字面量({})擴展
ES6針對對象字面量作了許多簡化語法的處理

1)精簡屬性:

const name = 'Jane';
const age = 20

// es6寫法
const person = {
  name,
  age
}

// es5寫法
var person = {
  name: name,
  age: age
};

2)精簡方法:

// es6寫法
const person = {
  name,
  age,
  getName() { // 只要不使用箭頭函數,this就仍是咱們熟悉的this
    return this.name
  }
}

// es5寫法
var person = {
  name: name,
  age: age,
  getName: function getName() {
    return this.name;
  }
};

3)屬性名錶達式:(這裏有點兒噁心,通過幾回代碼測試,最終肯定下面這樣解釋的話,可能會容易理解一些)

  在對象字面量中可使用中括號做爲屬性,表示屬性也能是一個變量了,並且這個變量的值還能夠改變

const name = 'Jane';

const person = {
  [name]: true,
  ['a'+'ge']: true
}
注意:上面的對象{}內寫了兩個[]屬性 ,切記[]裏面若是是一個變量的話,那麼這個變量必定要是一個已經聲明過的,不然結果就是undefined,[]若是是表達式,那麼訪問的時候,要向下面這樣寫
console.log(person['a'+'ge'])/console.log(person['age'])/console.log(oerson.age) // true
console.log(person[name]);// true  

注意:對象內用[變量]看成屬性時,訪問該屬性只能用[]語法,對象內給這個屬性賦什麼值,它就會變成什麼值,並且這個值也能夠經過[]裏面傳入訪問變量最初設置的值,也能夠訪問到,寫就是說像下面這樣寫 和上面結果是同樣的

 console.log(person['Jane']);  // true

對象的方法也能夠這樣寫

let obj = {  
    ['h'+'ello']() {  
        return 'hi';  
     }  
};  
console.log(obj.hello()); // hi  

 8⃣️class、extend、super

class、extend、super這三個特性涉及了ES5中最使人頭疼的的幾個部分:構造函數繼承原型...

ES6提供了更接近傳統語言的寫法,引入了Class(類)這個概念。新的class寫法讓對象原型的寫法更加清晰、更像面向對象編程的語法,也更加通俗易懂。

新舊語法對比

 class

// ES5
// 構造函數
function Person(name, age) {
  this.name = name;
  this.age = age;
}

// 原型方法
Person.prototype.getName = function() {
  return this.name
}

// ES6
class Person {
  constructor(name, age) {  // 構造函數
    this.name = name;
    this.age = age;
  }

  getName() {  // 原型方法
    return this.name
  }
}

上面代碼首先用class定義了一個「類」,能夠看到裏面有一個constructor方法,這就是構造方法,而this關鍵字則表明實例對象。

簡單地說,constructor內定義的方法和屬性是實例對象本身的,而constructor外定義的方法和屬性則是全部實例對象能夠共享的。這個和ES5裏的構造函數是差很少的意思,至關於把方法定義在構造函數裏是私有的,而把方法定義到原型中,全部實例共享

extend繼承

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  getName() {
    return this.name
  }
}

// Student類繼承Person類
class Student extends Person {
  constructor(name, age, gender, classes) {
    super(name, age);
    this.gender = gender;
    this.classes = classes;
  }

  getGender() {
    return this.gender;
  }
}

Class之間能夠經過extends關鍵字實現繼承,這比ES5的經過修改原型鏈實現繼承,要清晰和方便不少。上面定義了一個Cat類,該類經過extends關鍵字,繼承了Animal類的全部屬性和方法。

super關鍵字,它指代父類的實例(即父類的this對象)。子類必須在constructor方法中調用super方法,不然新建實例時會報錯。這是由於子類沒有本身的this對象,而是繼承父類的this對象,而後能夠對其進行加工。若是不調用super方法,子類就得不到this對象。

關於 super,像上面的栗子

// 構造函數中
// es5寫法
Person.call(this);
// es6寫法 
super(name, age);

class、extend/super三者的綜合實慄

class Animal {
    constructor(){
        this.type = 'animal'
    }
    says(say){
        console.log(this.type + ' says ' + say)
    }
}

let animal = new Animal()
animal.says('hello') //animal says hello

class Cat extends Animal {
    constructor(){
        super()
        this.type = 'cat'
    }
}

let cat = new Cat()
cat.says('hello') //cat says hello

9⃣️模塊的 Import 和 Export

import 用於引入模塊,export 用於導出模塊。

// 引入整個文件
import dva from 'dva';

// 引入函數(能夠是一個或多個)
import { connect } from 'dva';
import { Link, Route } from 'dva/router';

// 引入所有並做爲 github 對象
import * as github from './services/github';

// 導出默認
export default App;
// 部分導出,複合寫法是 export { App } from './file';  等價於import { App } from './file;export{App}
相關文章
相關標籤/搜索