ES6基礎知識

1、聲明 let、const

1. let

1). 做用域是塊級做用域(在ES6以前,js只存在函數做用域以及全局做用域)javascript

if(1){
  let a=1;
  console.log(a)
}

2). 不存在變量聲明提早;css

console.log(b); //ReferenceError: b is not defined
let b=2;

3). 不能重複定義html

let a=1;
let a=2;
console.log(a);//Identifier 'a' has already been declared

4). 存在暫時性死區:能夠這樣來理解前端

var a=1if(1){
 console.log(a); 
  let a=2;
}

① 在一個塊級做用域中,變量惟一存在,一旦在塊級做用域中用let聲明瞭一個變量,那麼這個變量就惟一屬於這個塊級做用域,不受外部變量的影響;vue

② 不管在塊中的任何地方聲明瞭一個變量,那麼在這個塊級做用域中,任何使用這個名字的變量都是指這個變量,不管外部是否有其餘同名的全局變量;java

③ 暫時性死區的本質就是,只要一進入當前做用域,所要使用的變量就已經存在了,可是不可獲取,只有等到聲明變量的那一行代碼出現,才能夠獲取和使用該變量。node

④ 暫時性死區的意義:讓咱們標準化代碼。將全部的變量的聲明放在做用域的最開始。webpack

2.  constes6

const通常用來聲明常量,且聲明的常量是不容許改變的,只讀屬性,所以就要在聲明的同時賦值。const與let同樣,都是塊級做用域,存在暫時性死區,不存在變量聲明提早,不容許重複定義web

const A=1;//從新給常量A賦值會報錯 
A=3;// Uncaught TypeError: Assignment to constant variable.
//錯誤:賦值給常量

2、解構賦值(es6容許按照必定的模式,從數組或對象中提取值,給變量進行賦值)

//解構賦值,兩邊格式要一致
let [a,b,c] = [1,2,3];let [a,[b,c]] = [1,[2,3]];
//交互數據
let a = 10;
let b = 20;
[a,b] = [b,a];

3、聲明類與繼承:class、extend

用class關鍵字定義對象類型,用extends關鍵字實現繼承

const private2 = Symbol('I am symbol value')
class A {
   a1 = '1'  // ES7 實例屬性,須要new實例來訪問, ES6規定class沒有靜態屬性,只有靜態方法因此只能在constructor中定義屬性
   static a2 = '2'  // ES7的靜態屬性,直接 A.a2 訪問,不須要new實例
   getA1() {
         return  this.a1      // this指向new實例
   }
   static  getA2() {
        return   ‘2’    // 靜態方法
   }
   constructor(name) {
         //必定要有構造方法,若是沒有默認生成空構造方法
        this.a3 = '3'   // 這裏定義實例屬性
        this.name = name
    }

   // 私有方法寫法
   publicMethod() {
         private1()    // 私有方法1,能夠寫在class體外
         private2()   // 利用Symbol值來定義
   }
   [private2]() {
       // 這裏是私有方法
   }
}
const private1 = function() { // 這裏也是私有方法,但別export出去}
// 最後export class
export default A

// 經過extends繼承
class B extends A{
    constructor() {
      // 必定要在構造函數的第一句調用super
      super()    // 這是調用父類的構造方法
      this.b1 = '11'
      this.b2 = super.a1    // super直接調用時指向父類構造方法,範圍屬性時,指向父類實例,或調用父類靜態方法
    }
}

4、Promise的使用與實現

Promise是JS異步編程中的重要概念,異步抽象處理對象,是目前比較流行Javascript異步編程解決方案之一。

1. Promise 處理多個相互關聯的異步請求

const request = url => { 
    return new Promise((resolve, reject) => {
        $.get(url, data => {
            resolve(data)
        });
    })
};

// 請求data1
request(url).then(data1 => {
    return request(data1.url);   
}).then(data2 => {
    return request(data2.url);
}).then(data3 => {
    console.log(data3);
}).catch(err => throw new Error(err));

2. Promise使用

2.1 Promise 是一個構造函數, new Promise 返回一個 promise對象 接收一個excutor執行函數做爲參數, excutor有兩個函數類型形參resolve reject

const promise = new Promise((resolve, reject) => {
       // 異步處理
       // 處理結束後、調用resolve 或 reject
});

2.2 promise至關於一個狀態機

promise的三種狀態

  • pending
  • fulfilled
  • rejected

①promise 對象初始化狀態爲 pending
②當調用resolve(成功),會由pending => fulfilled
③當調用reject(失敗),會由pending => rejected

注意:promsie狀態 只能由 pending => fulfilled/rejected, 一旦修改就不能再變

2.3 promise對象方法

1)then方法註冊 當resolve(成功)/reject(失敗)的回調函數,then方法是異步執行的

// onFulfilled 是用來接收promise成功的值
// onRejected 是用來接收promise失敗的緣由
promise.then(onFulfilled, onRejected);

2)resolve(成功) onFulfilled會被調用

const promise = new Promise((resolve, reject) => {
   resolve('fulfilled'); // 狀態由 pending => fulfilled
});
promise.then(result => { // onFulfilled
    console.log(result); // 'fulfilled' 
}, reason => { // onRejected 不會被調用
    
})

3)reject(失敗) onRejected會被調用

const promise = new Promise((resolve, reject) => {
   reject('rejected'); // 狀態由 pending => rejected
});
promise.then(result => { // onFulfilled 不會被調用
  
}, reason => { // onRejected 
    console.log(rejected); // 'rejected'
})

4)promise.catch

在鏈式寫法中能夠捕獲前面then中發送的異常

promise.catch(onRejected)
至關於
promise.then(null, onRrejected);

// 注意
// onRejected 不能捕獲當前onFulfilled中的異常
promise.then(onFulfilled, onRrejected); 

// 能夠寫成:
promise.then(onFulfilled)
       .catch(onRrejected); 

3. promise chain

promise.then方法每次調用 都返回一個新的promise對象 因此能夠鏈式寫法

function taskA() {
    console.log("Task A");
}
function taskB() {
    console.log("Task B");
}
function onRejected(error) {
    console.log("Catch Error: A or B", error);
}

var promise = Promise.resolve();
promise
    .then(taskA)
    .then(taskB)
    .catch(onRejected) // 捕獲前面then方法中的異常

4. Promise的靜態方法

1)Promise.resolve 返回一個fulfilled狀態的promise對象

Promise.resolve('hello').then(function(value){
    console.log(value);
});

Promise.resolve('hello');
// 至關於
const promise = new Promise(resolve => {
   resolve('hello');
});

2)Promise.reject 返回一個rejected狀態的promise對象

Promise.reject(24);
new Promise((resolve, reject) => {
   reject(24);
});

3)Promise.all 接收一個promise對象數組爲參數

只有所有爲resolve纔會調用 一般會用來處理 多個並行異步操做

const p1 = new Promise((resolve, reject) => {
    resolve(1);
});

const p2 = new Promise((resolve, reject) => {
    resolve(2);
});

const p3 = new Promise((resolve, reject) => {
    reject(3);
});

Promise.all([p1, p2, p3]).then(data => { 
    console.log(data); // [1, 2, 3] 結果順序和promise實例數組順序是一致的
}, err => {
    console.log(err);
});

4)Promise.race 接收一個promise對象數組爲參數

Promise.race 只要有一個promise對象進入 FulFilled 或者 Rejected 狀態的話,就會繼續進行後面的處理

function timerPromisefy(delay) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve(delay);
        }, delay);
    });
}
var startDate = Date.now();
Promise.race([
    timerPromisefy(10),
    timerPromisefy(20),
    timerPromisefy(30)
]).then(function (values) {
    console.log(values); // 10
});

5. promise實現

/**
 * 摘自https://www.cnblogs.com/minigrasshopper/p/9141307.html
 * Promise類實現原理
 * 構造函數傳入一個function,有兩個參數,resolve:成功回調; reject:失敗回調
 * state: 狀態存儲 [PENDING-進行中 RESOLVED-成功 REJECTED-失敗]
 * doneList: 成功處理函數列表
 * failList: 失敗處理函數列表
 * done: 註冊成功處理函數
 * fail: 註冊失敗處理函數
 * then: 同時註冊成功和失敗處理函數
 * always: 一個處理函數註冊到成功和失敗
 * resolve: 更新state爲:RESOLVED,而且執行成功處理隊列
 * reject: 更新state爲:REJECTED,而且執行失敗處理隊列
**/

class PromiseNew {
  constructor(fn) {
    this.state = 'PENDING';
    this.doneList = [];
    this.failList = [];
    fn(this.resolve.bind(this), this.reject.bind(this));
  }

  // 註冊成功處理函數
  done(handle) {
    if (typeof handle === 'function') {
      this.doneList.push(handle);
    } else {
      throw new Error('缺乏回調函數');
    }
    return this;
  }

  // 註冊失敗處理函數
  fail(handle) {
    if (typeof handle === 'function') {
      this.failList.push(handle);
    } else {
      throw new Error('缺乏回調函數');
    }
    return this;
  }

  // 同時註冊成功和失敗處理函數
  then(success, fail) {
    this.done(success || function () { }).fail(fail || function () { });
    return this;
  }

  // 一個處理函數註冊到成功和失敗
  always(handle) {
    this.done(handle || function () { }).fail(handle || function () { });
    return this;
  }

  // 更新state爲:RESOLVED,而且執行成功處理隊列
  resolve() {
    this.state = 'RESOLVED';
    let args = Array.prototype.slice.call(arguments);
    setTimeout(function () {
      this.doneList.forEach((item, key, arr) => {
        item.apply(null, args);
        arr.shift();
      });
    }.bind(this), 200);
  }

  // 更新state爲:REJECTED,而且執行失敗處理隊列
  reject() {
    this.state = 'REJECTED';
    let args = Array.prototype.slice.call(arguments);
    setTimeout(function () {
      this.failList.forEach((item, key, arr) => {
        item.apply(null, args);
        arr.shift();
      });
    }.bind(this), 200);
  }
}

// 下面一波騷操做
new PromiseNew((resolve, reject) => {
  resolve('hello world');
  // reject('you are err');
}).done((res) => {
  console.log(res);
}).fail((res) => {
  console.log(res);
})

5、generator(異步編程、yield、next()、await 、async)

使用Generator能夠很方便的幫助咱們創建一個處理Promise的解釋器;

async/await這樣的語法,可讓咱們以接近編寫同步代碼的方式來編寫異步代碼(無需使用.then()或者回調函數)

1. Generator

Generator是一個函數,能夠在函數內部經過yield返回一個值(此時,Generator函數的執行會暫定,直到下次觸發.next()) 建立一個Generator函數的方法是在function關鍵字後添加*標識。

在調用一個Generator函數後,並不會當即執行其中的代碼,函數會返回一個Generator對象,經過調用對象的next函數,能夠得到yield/return的返回值。 不管是觸發了yield仍是returnnext()函數總會返回一個帶有valuedone屬性的對象。 value爲返回值,done則是一個Boolean對象,用來標識Generator是否還能繼續提供返回值。 P.S. Generator函數的執行時惰性的,yield後的代碼只在觸發next時纔會執行。

function * oddGenerator () {
  yield 1
  yield 3
  return 5
}
let iterator = oddGenerator()
let first = iterator.next()  // { value: 1, done: false }
let second = iterator.next() // { value: 3, done: false }
let third = iterator.next()  // { value: 5, done: true  }

2. Async

function getRandom () {
  return new Promise(resolve => {
    setTimeout(_ => resolve(Math.random() * 10 | 0), 1000)
  })
}

async function main () {
  let num1 = await getRandom()
  let num2 = await getRandom()

  return num1 + num2
}

console.log(`got data: ${await main()}`)

Async函數始終返回一個Promise

async function throwError () {
  throw new Error()
}
async function returnNumber () {
  return 1
}

console.log(returnNumber() instanceof Promise) // true
console.log(throwError() instanceof Promise)   // true

Await是按照順序執行的,並不能並行執行,JavaScript是單線程的,這就意味着await一隻能一次處理一個,若是你有多個Promise須要處理,則就意味着,你要等到前一個Promise處理完成才能進行下一個的處理,這就意味着,若是咱們同時發送大量的請求,這樣處理就會很是慢。

function delay () {
  return new Promise(resolve => setTimeout(resolve, 1000))
}

let tasks = [1, 2, 3, 4]

//要4s才能執行完
async function runner (tasks) {
  for (let task of tasks) {
    await delay()
  }
}
//優化,縮短執行時間
async function runner (tasks) {
  tasks = tasks.map(delay)
  await Promise.all(tasks)
}

console.time('runner')
await runner(tasks)
console.timeEnd('runner')

Generatorasync function都是返回一個特定類型的對象:

  • Generator: 一個相似{ value: XXX, done: true }這樣結構的Object
  • Async: 始終返回一個Promise,使用await或者.then()來獲取返回值

Generator是屬於生成器,一種特殊的迭代器,用來解決異步回調問題感受有些遊手好閒了。。 而async則是爲了更簡潔的使用Promise而提出的語法,相比Generator + co這種的實現方式,更爲專一,生來就是爲了處理異步編程。

6、箭頭函數this指向問題、拓展運算符

// 兩個參數:
(x, y) => x * x + y * y

// 無參數:
() => 3.14

// 可變參數:
(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum += rest[i];
    }
    return sum;
}

1. 不綁定this

var obj = {
   age: 1,
   say: function() {
      setTimeout(function() {
         console.log(this, this.age); // window undefined
      }, 0);
   },
}
var obj1 = {
   age: 1,
   say: function() {
      setTimeout(() => {
         console.log(this, this.age); // obj1 1
      }, 0);
   }
};

這裏能夠看出箭頭函數中訪問的this其實是其父級做用域中的this,箭頭函數自己的this是不存在的,這樣就至關於箭頭函數的this是在聲明的時候就肯定了(即this老是指向詞法做用域,也就是外層調用者handler),這個特性是頗有用的,因此,call()或者apply()調用箭頭函數時,沒法對this進行綁定,即傳入的第一個參數被忽略。

var handler = {
   id: '111',
   doSomething: function(e) {
       console.log(e);
   },
   init: function() {
      document.addEventListener('click', (event) => { // 這裏綁定事件,函數this就能夠訪問到handler的方法doSomething
         this.doSomething(event);
      }, false);
   }
}
handler.init();

2. 不能夠做爲構造函數來使用

var Person = (name) => { // Uncaught TypeError: Person is not a constructor
    this.name = name;
}
var person = new Person('Jack');

3. 不綁定arguments(若是有要使用arguments的時候可使用rest參數代替)

var foo = (val) => {
    console.log(arguments); // Uncaught ReferenceError: arguments is not defined
};
foo();
//這個特性也很好測試,可是實在要使用arguments對象要怎麼辦呢?咱們可使用es6的另外一個新特性rest參數,完美替代
var foo = (...args) => {
    console.log(args); // [1, 2, 3]
};
foo(1, 2, 3);

4. 不可使用yield命令,所以箭頭函數不能用做Generator函數

7、map和set有沒有用過,如何實現一個數組去重,map數據結構有什麼優勢?

JavaScript的默認對象表示方式{}能夠視爲其餘語言中的MapDictionary的數據結構,即一組鍵值對。可是JavaScript的對象有個小問題,就是鍵必須是字符串。但實際上Number或者其餘數據類型做爲鍵也是很是合理的。爲了解決這個問題,最新的ES6規範引入了新的數據類型Map。

Map的遍歷

  • keys():返回鍵名的遍歷器。
  • values():返回鍵值的遍歷器。
  • entries():返回全部成員的遍歷器。
  • forEach():遍歷 Map 的全部成員。
  • 須要特別注意的是,Map 的遍歷順序就是插入順序
var m = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);
m.get('Michael'); // 95

//初始化Map須要一個二維數組,或者直接初始化一個空Map。Map具備如下方法:
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.set('Bob', 59);
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 刪除key 'Adam'
m.get('Adam'); // undefined
//因爲一個key只能對應一個value,因此,屢次對一個key放入value,後面的值會把前面的值沖掉
//遍歷Map
var m = new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
m.forEach(function (value, key, map) {
    console.log(value);
});

SetMap相似,也是一組key的集合,但不存儲value。因爲key不能重複,因此,Set中,沒有重複的key

//要建立一個Set,須要提供一個Array做爲輸入,或者直接建立一個空Set:
var s1 = new Set(); // 空Set
var s2 = new Set([1, 2, 3]); // 含1, 2, 3

//重複元素在Set中自動被過濾:
var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}

//經過add(key)方法能夠添加元素到Set中,能夠重複添加,但不會有效果:
s.add(4);
s; // Set {1, 2, 3, 4}
s.add(4);
s; // 仍然是 Set {1, 2, 3, 4}

//經過delete(key)方法能夠刪除元素:
var s = new Set([1, 2, 3]);
s; // Set {1, 2, 3}
s.delete(3);
s; // Set {1, 2}

//遍歷Set
var s = new Set(['A', 'B', 'C']);
s.forEach(function (element, sameElement, set) {
    console.log(element);
});

數組去重

//1.for循環嵌套,利用splice去重
function newArr(arr){
    for(var i=0;i<arr.length;i++){
        for(var j=i+1;j<arr.length;j++)
            if(arr[i]==arr[j]){ 
            //若是第一個等於第二個,splice方法刪除第二個
            arr.splice(j,1);
            j--;
            }
        }
    }
    return arr;
}
var arr = [1,1,2,5,6,3,5,5,6,8,9,8];
console.log(newArr(arr))

//2.建新數組,利用indexOf去重
function newArr(array){ 
    //一個新的數組 
    var arrs = []; 
    //遍歷當前數組 
    for(var i = 0; i < array.length; i++){ 
        //若是臨時數組裏沒有當前數組的當前值,則把當前值push到新數組裏面 
        if (arrs.indexOf(array[i]) == -1){ 
            arrs.push(array[i])
        }; 
    } 
    return arrs; 
}
var arr = [1,1,2,5,5,6,8,9,8];
console.log(newArr(arr))

//3.ES6中利用Set去重
function newArr(arr){
    return Array.from(new Set(arr))
}
var arr = [1,1,2,9,6,9,6,3,1,4,5];
console.log(newArr(arr))

8、ES6怎麼編譯成ES5,css-loader原理,過程

如今的Chrome瀏覽器已經支持ES6了,可是有些低版本的瀏覽器仍是不支持ES6的語法,這就須要咱們把ES6的語法自動的轉變成ES5的語法。Webpack是有自動編譯轉換能力的,除了Webpack自動編譯,還可使用用Babel來完成。

  • 初始化項目
    打開終端或者經過cmd打開命令行工具,進入項目目錄,輸入下邊的命令:
     npm init -y 
    -y表明所有默認贊成,就不用一次次按回車了。命令執行完成後,會在項目根目錄下生產package.json文件。
{
  "name": "es6",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

能夠根據本身的須要進行修改,好比咱們修改name的值爲es6。

  • 全局安裝Babel-cli
     npm install -g babel-cli 
  • 本地安裝babel-preset-es2015 和 babel-cli
     npm install --save-dev babel-preset-es2015 babel-cli 
  • 新建.babelrc
    在根目錄下新建.babelrc文件,並打開錄入下面的代碼
{
    "presets":[
        "es2015"
    ],
    "plugins":[]
}

這個文件咱們創建完成後,如今能夠在終端輸入的轉換命令了,此次ES6成功轉化爲ES5的語法。 babel dist/index.js -o src/index.js 

  • 簡化轉化命令:
    在學習vue 的時候,可使用npm run build 直接利用webpack進行打包,在這裏也但願利用這種方式完成轉換。打開package.json文件,把文件修改爲下面的樣子。
{
  "name": "es6",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "babel src/index.js -o dist/index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel-cli": "^6.24.1",
    "babel-preset-es2015": "^6.24.1"
  }
}

修改好後,之後咱們就可使用  npm run build  來進行轉換了。

webpack的loaders是一塊很重要的組成部分。咱們都知道webpack是用於資源打包的,裏面的全部資源都是「模塊」,內部實現了對模塊資源進行加載的機制。可是Webpack自己只能處理 js模塊,若是要處理其餘類型的文件,就須要使用 loader 進行轉換。 

Loader 能夠理解爲是模塊和資源的轉換器,它自己是一個函數,接受源文件做爲參數,返回轉換的結果,例如可使用loader加載器能夠快速編譯預處理器(less,sass,coffeeScript)。 Loader 能夠在require()引用模塊的時候添加,也能夠在 webpack 全局配置中進行綁定,還能夠經過命令行的方式使用。

loader的特性是: 

  • loaders能夠串聯,他們應用於管道資源,最後的loader將返回javascript,其它的可返回任意格式(傳遞給下一個loader)
  • loaders 能夠同步也能夠異步
  • loaders在nodejs下運行而且能夠作一切可能的事 loader接受參數,可用於配置裏 
  • loaders能夠綁定到extension/RegExps 配置 
  • loaders能夠經過npm發佈和安裝 正常的模塊兒能夠處處一個
  • loader除了 loaders能夠訪問配置 插件能夠給loaders更多的特性
  • loaders能夠釋聽任意額外的文件
本部分摘自連接: https://www.jianshu.com/p/059c5b68d9d5

9、import和export    AMD

ES6以前已經出現了js模塊加載的方案,最主要的是CommonJS和AMD規範。commonjs主要應用於服務器,實現同步加載,如nodejs。AMD規範應用於瀏覽器,如requirejs,爲異步加載。同時還有CMD規範,爲同步加載方案如seaJS。

ES6在語言規格的層面上,實現了模塊功能,並且實現得至關簡單,徹底能夠取代現有的CommonJS和AMD規範,成爲瀏覽器和服務器通用的模塊解決方案。

ES6模塊主要有兩個功能:export和import

export用於對外輸出本模塊(一個文件能夠理解爲一個模塊)變量的接口

import用於在一個模塊中加載另外一個含有export接口的模塊。

CommonJS模塊的重要特性是加載時執行,即腳本代碼在require的時候,就會所有執行。一旦出現某個模塊被「循環加載」就只輸出已經執行的部分,尚未執行的部分是不輸出的。

ES6模塊是動態引用,若是使用import從一個模塊加載變量,那些變量不會緩存,而是成爲一個指向被加載模塊的引用,須要開發者本身保證,真正取值的時候可以取到值

impor/export(都是語法糖啦)最終都是編譯爲require/exports來執行的

CommonJS規範規定,每一個模塊內部,module變量表明當前模塊,這個變量是一個對象,他的exports屬性是對外的接口,加載某個模塊,實際上是加載該模塊module.exports屬性。export命令規定的是對外的接口,必須與模塊內部的變量創建一一對應的關係

AMD是RequireJS在推廣過程當中對模塊定義的規範化產出,它是一個概念,RequireJS是對這個概念的實現,就比如JavaScript語言是對ECMAScript規範的實現。AMD是一個組織,RequireJS是在這個組織下自定義的一套腳本語言

CMD---是SeaJS在推廣過程當中對模塊定義的規範化產出,是一個同步模塊定義,是SeaJS的一個標準,SeaJS是CMD概念的一個實現,SeaJS是淘寶團隊提供的一個模塊開發的js框架

CommonJS規範---是經過module.exports定義的,在前端瀏覽器裏面並不支持module.exports,經過node.js後端使用的。Nodejs端是使用CommonJS規範的,前端瀏覽器通常使用AMD、CMD、ES6等定義模塊化開發的

10、ES6轉成ES5的常見例子

bable.js

babel是一個轉譯器,感受相對於編譯器compiler,叫轉譯器transpiler更準確,由於它只是把同種語言的高版本規則翻譯成低版本規則,而不像編譯器那樣,輸出的是另外一種更低級的語言代碼。
可是和編譯器相似,babel的轉譯過程也分爲三個階段:parsing、transforming、generating,以ES6代碼轉譯爲ES5代碼爲例,babel轉譯的具體過程以下:

ES6代碼輸入 ==》 babylon進行解析 ==》 獲得AST
==》 plugin用babel-traverse對AST樹進行遍歷轉譯 ==》 獲得新的AST樹
==》 用babel-generator經過AST樹生成ES5代碼

此外,還要注意很重要的一點就是,babel只是轉譯新標準引入的語法,好比ES6的箭頭函數轉譯成ES5的函數;而新標準引入的新的原生對象,部分原生對象新增的原型方法,新增的API等(如Proxy、Set等),這些babel是不會轉譯的。須要用戶自行引入polyfill來解決

//摘自博客:https://blog.csdn.net/qq_42149830/article/details/88295747
function _defineProperties(target,prop){
        prop.forEach(ele => {        //可能會傳入多個屬性
            Object.defineProperty(target,ele.key,{
                value:ele.value,
                writable:true,
                configurable:true,
            })
        });//設置所設置的屬性是否可寫,可枚舉
}

function _createClass(_constructor,_prototypeProperties,_staticProperties){ //這裏傳入的三個參數分別是構造函數,原型上的屬性,靜態屬性
    if(_prototypeProperties){   //設置公有屬性
        _defineProperties(_constructor.prototype,_prototypeProperties)
    }
    if(_staticProperties){  //設置靜態屬性
        _defineProperties(_constructor,_staticProperties)
    }
}

function _classCallCheck(_this,_constructor){
    if(!(_this instanceof _constructor)){     //判斷是不是經過new(建立實例)來調用_constructor
            throw "TypeError: Class constructor AirPlane cannot be invoked without 'new'"
    }
}
var FatherPlane=(function(){
    function FatherPlane(name,color){
        _classCallCheck(this,FatherPlane)
        this.name=name||'liu';
        this.color=color||'red'
    }
    _createClass(FatherPlane,[
        {
            key:'fly',
            value:function(){
                console.log('fly')
            }
        }
    ],[
        {
           key:'static',
           value:function(){
               console.log('static')
           } 
        }
    ])
    return FatherPlane;
})()
var airplane=new FatherPlane()
相關文章
相關標籤/搜索