追本溯源,ES6 和 ES5 的對比實現

詞語連線

讓咱們先來玩一個遊戲,根據 ES5,ES2015, ES2016,ES6,ES2017 這幾個詞的關係,進行連線。javascript

若是你有點「蒙圈」,不妨先來看看 Javascript 的發展歷史。前端

  • 2011 年,標準化組織 ECMA 發佈 ECMAScript 5.1 版
  • 發佈後,開始着手製定 ECMAScript 6.0 版本,即 ES6
  • 爲了讓標準的升級成爲常規流程,決定在每一年的 6 月份正式發佈一次,做爲當年的正式版本:
    • 2015 年 6 月發佈 《ECMAScript 2015 標準》(簡稱 ES2015),它是 ES6 的第一個版本:
    • 2016 年 6 月發佈 《ECMAScript 2016 標準》(簡稱 ES2016),進行了小幅修訂
    • 2017 年 6 月發佈 ES2017 標準

那麼上面遊戲的答案是: java

關係

ES6 與 ES5

做爲一個在 JS 高程《JavaScript 高級程序設計》 指引下走進前端的「老」同窗,我經常被 ES5 和 ES6 的寫法「困擾」,擔憂寫出來的代碼不夠「新」。時間與經驗的沉澱促進語言的「進化」,那麼觀察一個特性/語法的變遷,或許是一件有意思的事情。瀏覽器

今天咱們就來看看,ES6 中一些語法若是用 ES5 該如何實現。bash

let

ES5 只有全局做用域函數做用域,ES6 經過 let 語法增長了塊級做用域,加強了一些場景下的合理性。服務器

ES6函數

for (let i = 0; i < 3; i++) {
    // 
}
console.log(i); // ReferenceError: i is not defined
複製代碼

ES5學習

(function() {
    for (var i = 0; i < 3; i++) {
    // 
    }
})();
console.log(i); // ReferenceError: i is not defined
複製代碼

const

ES5 中是沒有常量的,一般用大寫的命名規範來「約定」常量,卻不能保證不被更改。ES6 中新增了 const。ui

ES6this

const a = '123';

try {
  a = '456';
} catch(err) {
  // err: TypeError: Assignment to constant variable
  console.log(a); // '123'
}
複製代碼

ES5

Object.defineProperties(window, {
  a: {
    value: '123',
    writable: false
  }
});

a = '456';
console.log(a); // '123'
複製代碼

Class

與其餘新增的語法特性不一樣,ES6 中的 Class 實質上是 JavaScript 現有的基於原型的繼承的語法糖。

聲明一個動物類

ES6

class Animal {
  constructor(type, name) {
    this.type = type;
    this.name = name;
  }
  static eat() {
  }
  speak() {
    console.log(this.name + ' say:');
  }
}
複製代碼

ES5

function Animal(type, name) {
    this.type = type;
    this.name = name;
}
Animal.eat = function () {
}
Animal.prototype.speak = function () {
    console.log(this.name + ' say');
}
複製代碼

實例化一個小明同窗

var a = new Animal('people', 'xiaoming');
a.speak();
複製代碼

聲明貓貓類(繼承動物類)

ES6

class Cat extends Animal {
    constructor(name) {
        super('cat', name);
    }
   
    speak() {
        super.speak();
        console.log('meow');
    }
}
複製代碼

ES5

function Cat(name) {
    Animal.call(this, 'cat', name);
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

// 靜態方法
Cat.eat = Animal.eat;

Cat.prototype.speak = function () {
  Animal.prototype.speak.call(this);
  console.log('meow');
};

複製代碼

實例化一隻名爲「卷卷」的喵,而後喵一聲

var juanjuan = new Cat('juanjuan');
juanjuan.speak(); // juanjuan say: meow
複製代碼

對比一下,ES6 更優美吧~

Module

ES6 import/export

// lib/math.js
export function sum(x, y) {
  return x + y;
}
export var pi = 3.141593;

// 引用
import { pi, sum } from 'lib/math';
console.log('2π = ' + math.sum(math.pi, math.pi));
複製代碼

ES5 require/exports

// lib/math.js
exports.sum = sum;
function sum(x, y) {
  return x + y;
}
var pi = exports.pi = 3.141593;

// 引用
var math = require('lib/math');
console.log('2π = ' + math.sum(math.pi, math.pi));
複製代碼

可是,上面這兩種寫法並不「等價」。這要從 javascript 的模塊體系提及。

javascript 一直沒有模塊體系,因而社區制定了一些模塊加載方案,比較通用的是 CommonJS 和 AMD 兩種, 前者用於服務器,後者用於瀏覽器。(爲了兼容還引入了UMD)。

CommonJS 和 AMD 模塊都是在運行時肯定模塊關係。即總體加載模塊(模塊下的全部方法),生成一個對象,而後在從這個對象上讀取方法。這種加載稱爲「運行時加載」

// CommonJS模塊
let { stat, exists, readFile } = require('fs');

// 等同於
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;
複製代碼

然而 ES6 模塊不是對象。

// ES6模塊
import { stat, exists, readFile } from 'fs';
複製代碼

上面代碼的實質是從 fs 模塊加載 3 個方法,其餘方法不加載。這種加載稱爲「編譯時加載」或者靜態加載,即 ES6 能夠在編譯時就完成模塊加載,效率要比 CommonJS 模塊的加載方式高。固然,這也致使了無法引用 ES6 模塊自己,由於它不是對象。

關於模塊這部分,其實值得展開研究。(我還沒整太明白)

結尾

語法的背後,是語言自己的「特性」,他們的出現是爲了解決一些場景的問題。追本溯源是一個很好的學習方式。咱們,下期再見~

相關文章
相關標籤/搜索