重學ES6之出來混早晚要還的(五)

本系列博客爲ES6基礎語法的使用及總結,若有錯誤,歡迎指正。
重學ES6之出來混早晚要還的(五)主要包括 ES6模塊化ES6的繼承遍歷器等。html

其餘筆記:
重學ES6之出來混早晚要還的(一)
重學ES6之出來混早晚要還的(二)
重學ES6之出來混早晚要還的(三)
重學ES6之出來混早晚要還的(四)
重學ES6之出來混早晚要還的(六)
數據類型的轉換/判斷/比較前端

ES6模塊化(ES6 Module)

歷史上,JavaScript 一直沒有模塊(module)體系,沒法將一個大程序拆分紅互相依賴的小文件,再用簡單的方法拼裝起來。

在 ES6 以前,社區制定了一些模塊加載方案,最主要的有 CommonJS 和 AMD 兩種。前者用於服務器,後者用於瀏覽器。ES6 在語言標準的層面上,實現了模塊功能,並且實現得至關簡單,徹底能夠取代現有的 CommonJS 和 AMD 規範,成爲瀏覽器和服務器通用的模塊解決方案。es6

在過去爲了支持JS模塊化,可使用類、當即執行函數或者第三方插件(RequireJS、seaJS)來實現模塊化編程

前端模塊化開發

1.AMD 和 CMD

(1) AMDsegmentfault

全稱:Asynchronous Module Definition(異步模塊定義)數組

  • AMD規範是require.js推廣的、對模塊定義的規範
  • 非同步加載模塊,容許指定回調函數
  • AMD在使用模塊以前將依賴模塊所有加載完成

(2) CMD瀏覽器

全稱:Common Module Definition(通用模塊定義)服務器

  • CMD規範是SeaJS推廣的、對模塊定義的規範
  • 就近依賴,須要時再進行加載,因此執行順序和書寫順序一致

(3) AMD 和CMD 兩者異同網絡

  • 相同:AMD 和 CMD都是瀏覽器端的js模塊化規範
  • 異同:app

    • AMD提早執行,CMD延遲執行
    • AMD推崇依賴前置,CMD推崇依賴就近
    • require.js遵循AMD規範,SeaJS遵循CMD規範
    • AMD受網絡等因素執行順序可能和書寫順序不同(使用模塊以前將依賴模塊所有加載完成),CMD執行順序和書寫順序一致

2.CommonJS

CommonJS是服務端模塊的規範,NodeJS採用了這個規範。 CommonJS規範同步加載模塊,也就是:只有加載完成,才能執行後面的操做。

3.AMD和CommonJS的比較

  • AMD非同步加載模塊;CommonJS規範同步加載模塊
  • AMD推薦風格是經過module transport規範暴露接口,即經過返回一個對象來暴露模塊接口;CommonJS的風格是經過對module.exportsexports的屬性賦值來達到暴露模塊對象的目的

ES6模塊化

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

export 命令

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

1.常規導出

//分開導出
export let firstName = 'Michael';
export let lastName = 'Jackson';
export let year = 1958;

//一次性導出
let firstName = 'Michael';
let lastName = 'Jackson';
let year = 1958;

export {firstName, lastName, year};

2.一般狀況下,export輸出的變量就是原本的名字,可是可使用as關鍵字重命名。

變量名被修改後原有變量名自動失效

function v1() { ... }
function v2() { ... }

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};

export default 命令

1.export default命令,爲模塊指定默認輸出。

export default function () {
  console.log('foo');
}

上面代碼是一個模塊文件,它的默認輸出是一個函數。

其餘模塊加載該模塊時,import命令能夠爲該匿名函數指定任意名字,不須要知道原模塊輸出的函數名。

2.注意點

  • 一個模塊只能使用一次默認導出, 屢次無效
  • 默認導出時, 導入的名稱能夠和導出的名稱不一致

import 命令

使用export命令定義了模塊的對外接口之後,其餘 JS 文件就能夠經過import命令加載這個模塊。

1.常規導入

import命令接受一對大括號,裏面指定要從其餘模塊導入的變量名。大括號裏面的變量名,必須與被導入模塊對外接口的名稱相同。

import {firstName, lastName, year} from '那個js文件的路徑';

2.若是想爲輸入的變量從新取一個名字,import命令要使用as關鍵字,將輸入的變量重命名。

import { lastName as surname } from '那個js文件的路徑';

3.注意點

  • import後面的from指定模塊文件的位置,能夠是相對路徑,也能夠是絕對路徑,.js路徑能夠省略。
  • 接收導入變量名必須和導出變量名一致(根本上是解構賦值)
  • 其餘模塊加載默認模塊時,import命令能夠爲該匿名函數指定任意名字;不須要知道原模塊輸出的函數名。
  • 須要注意的是,加載默認模塊時import命令後面,不使用大括號。
// export-default.js
export default function () {
  console.log('foo');
}

// import-default.js
import customName from './export-default';
customName(); // 'foo'
  • 若是屢次重複執行同一句import語句,那麼只會執行一次,而不會執行屢次。

ES6的繼承

ES6類和對象

Class基本語法

1.在ES6以前經過構造函數來定義一個類

function Person(myName, myAge) {
     // 實例屬性
     this.name = myName;
     this.age = myAge;

     // 實例方法
     this.say = function () {
         console.log(this.name, this.age);
     }
     // 靜態屬性
     Person.num = 666;
     // 靜態方法
     Person.run = function () {
         console.log("run");
     }
 }
 let p = new Person("zs", 18); //建立一個Person實例
 p.say(); //調用實例方法,訪問實例屬性
 console.log(Person.num); //訪問靜態屬性
 Person.run(); //調用靜態方法
實例屬性/實例方法
經過實例對象訪問的屬性,稱之爲實例屬性;
經過實例對象調用的方法,稱之爲實例方法。

靜態屬性/靜態方法
經過構造函數訪問的屬性,稱之爲靜態屬性;
經過構造函數調用的方法,稱之爲靜態方法。

2.ES6引入了Class(類)這個概念,做爲對象的模板。

經過class關鍵字,能夠定義類。基本上,ES6的class能夠看做只是一個語法糖,它的絕大部分功能,ES5均可以作到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已。

2.1 定義類的兩種方式

//方式一
class User{
    ···
}

//方式二
const List = class{
    ···
};

2.2 類是一種特殊的函數

  • 函數存在提高,可是類不存在提高,在定義以前調用類會報錯
  • typeof檢查類返回function
class User{
    
}
console.log(typeof User); //function

2.3 上面的代碼用ES6的「類」改寫,就是下面這樣:

class Person{
    constructor(myName, myAge){
        this.name = myName;
        this.age = myAge;
    }
    // 定義實例方法
    say(){
        console.log(this.name, this.age);
    }
    // 定義靜態方法
    static run() {
        console.log("run");
    }
}
let p = new Person("zs", 18); //建立一個Person實例
p.say(); //調用實例方法
Person.run(); //調用靜態方法

3.constructor方法

constructor方法是類的默認方法,經過new命令生成對象實例時,自動調用該方法。一個類必須有constructor方法,若是沒有顯式定義,一個空的constructor方法會被默認添加。

  • constructor意義:類初始化時候執行的函數
  • 做用:初始化屬性, 傳入所須要的參數
  • 返回值:自動返回實例對象
  • 實例屬性都須要在constructor中添加

4.在類裏面定義方法注意點

  • 定義「類」的方法的時候,不須要加上function關鍵字,直接把函數定義放進去。
  • 方法之間不須要逗號分隔,加了會報錯。
  • static關鍵字表示定義靜態方法;ES6明確規定,Class內部只有靜態方法,沒有靜態屬性。
  • 實例方法寫在constructor外面,默認是添加到原型上面的

    class Point {
       constructor(){
         // ...
       }
    
       toString(){
         // ...
       }
    
       toValue(){
         // ...
       }
    }
    
    // 等同於
    Point.prototype = {
       toString(){},
       toValue(){}
    };


(以上上面代碼爲例打印p這個對象,能夠發現say()方法存在在原型上)

  • 類的內部全部定義的方法,都是不可枚舉的(non-enumerable)。

ES6繼承

ES6以前的繼承

1.兩個關鍵步驟

  • 在子類中經過call/apply方法藉助父類的構造函數
  • 將子類的原型對象設置爲父類的實例對象

2.三句關鍵代碼

function Person(myName, myAge) {
   this.name = myName;
   this.age = myAge;
}
Person.prototype.say =  function () {
   console.log(this.name, this.age);
};

function Student(myName, myAge, myScore) {
   // 1.在子類中經過call/apply方法藉助父類的構造函數
   Person.call(this, myName, myAge);
   this.score = myScore;
   this.study = function () {
     console.log("day day up");
   }
}
// 2.將子類的原型對象設置爲父類的實例對象
Student.prototype = new Person();
Student.prototype.constructor = Student;

let stu = new Student("zs", 18, 99);
stu.say();

ES6繼承

1.Class之間能夠經過extends關鍵字實現繼承

  • 格式:class b extends a
  • 意思:定義了一個b類,該類經過extends關鍵字,繼承了a類的全部屬性和方法。

2.super關鍵字

  • 表示父類的構造函數,用來新建父類的this對象。
  • 子類必須在constructor方法中調用super方法,不然新建實例時會報錯。
  • 注意,super雖然表明了父類a的構造函數,可是返回的是子類b的實例,即super內部的this指的是b

3.ES6實現繼承

class Person{
   constructor(myName, myAge){
      this.name = myName; 
      this.age = myAge; 
   }
   say(){
      console.log(this.name, this.age);
   }
}
// 如下代碼的含義: 告訴瀏覽器未來Student這個類須要繼承於Person這個類
class Student extends Person{
   constructor(myName, myAge, myScore){
      super(myName, myAge);
      this.score = myScore;
   }
   study(){
       console.log("day day up");
   }
}
let stu = new Student("zs", 18, 98);
stu.say();

4.小結

ES5的繼承,實質是先創造子類的實例對象this,而後再將父類的方法添加到this上面(Parent.apply(this))。ES6的繼承機制徹底不一樣,實質是先創造父類的實例對象this(因此必須先調用super方法),而後再用子類的構造函數修改this。

Object.getPrototypeOf()

Object.getPrototypeOf方法能夠用來從子類上獲取父類。

在ES6中可使用這個方法判斷,一個類是否繼承了另外一個類。

console.log(Object.getPrototypeOf(Student) === Person); //true

遍歷器Iterator

1.什麼是遍歷器
遍歷器是一個對象,該對象裏面有一個next方法會返回給咱們須要的數據

可遍歷對象就是部署了[Symbol.iterator]屬性的對象

2.[Symbol.iterator]

  • 可遍歷對象都有一個叫作[Symbol.iterator]的屬性
const arr = ['Ann','Bob','Charlie','Dolly'];
console.log(arr);

  • [Symbol.iterator]的屬性會返回一個函數
  • [Symbol.iterator]返回的函數執行以後會返回一個新對象Array Iterator {},該對象中又一個名稱叫作next的方法
const iterator = arr[Symbol.iterator]();
console.log(iterator);

  • next方法每次執行都會返回一個對象;該對象中存儲了當前取出的數據和是否取完了的標記
let res = iterator.next();
console.log(res);
let res2 = iterator.next();
console.log(res2);
let res3 = iterator.next();
console.log(res3);
let res4 = iterator.next();
console.log(res4);

  • 數據遍歷完以後,隨後再調用一直返回undefinedtrue
let res5 = iterator.next();
console.log(res5);
let res6 = iterator.next();
console.log(res6);


3.一點區別

第三篇說到Array.prototype.entries();[Symbol.iterator]();返回的都是新的Array Iterator對象,兩者等價

console.log(arr.entries());
console.log(arr[Symbol.iterator]());

兩者的返回的都是新的Array Iterator{}對象,細微的區別在於:

  • 使用.entries()返回的Array Iterator{}對象,再調用next()時,返回給咱們的數據中的value是以數組(即包含索引)的形式

  • 使用[Symbol.iterator]();返回的Array Iterator{}對象,再調用next()時,value返回的就是那個值


4.其餘方法返回Array Iterator{}

4.1 .keys方法

顧名思義,它的Array Iterator{}next()方法返回的是索引

let iterator = arr.keys();
console.log(iterator);
let res = iterator.next();
console.log(res);

let res2 = iterator.next();
console.log(res2);

let res3 = iterator.next();
console.log(res3);

4.2 .values()方法
顧名思義,它的Array Iterator{}next()方法返回的是值

let iterator = arr.values();
console.log(iterator); //Array Iterator {}
let res = iterator.next();
console.log(res);

let res2 = iterator.next();
console.log(res2);

let res3 = iterator.next();
console.log(res3);


5.實現一個遍歷器

(抄的,這個代碼太優雅了,必須分享)

Array.prototype.myIterator = function () {
    let i = 0;
    let items = this;
    return {
        next(){
            const done = i >= items.length;
            const value = done ? undefined : items[i++];
            return {
                value,
                done
            }
        }
    }
};

本博客部份內容ES6模塊化和ES6繼承參考了這些:

http://caibaojian.com/es6/mod...

http://caibaojian.com/es6/cla...

相關文章
相關標籤/搜索