讓咱們先來玩一個遊戲,根據 ES5,ES2015, ES2016,ES6,ES2017 這幾個詞的關係,進行連線。javascript
若是你有點「蒙圈」,不妨先來看看 Javascript 的發展歷史。前端
標準化組織 ECMA
發佈 ECMAScript 5.1 版
ECMAScript 6.0 版本
,即 ES6
《ECMAScript 2015 標準》
(簡稱 ES2015
),它是 ES6 的第一個版本:《ECMAScript 2016 標準》
(簡稱 ES2016
),進行了小幅修訂ES2017
標準那麼上面遊戲的答案是: java
做爲一個在 JS 高程《JavaScript 高級程序設計》 指引下走進前端的「老」同窗,我經常被 ES5 和 ES6 的寫法「困擾」,擔憂寫出來的代碼不夠「新」。時間與經驗的沉澱促進語言的「進化」,那麼觀察一個特性/語法的變遷,或許是一件有意思的事情。瀏覽器
今天咱們就來看看,ES6 中一些語法若是用 ES5 該如何實現。bash
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
複製代碼
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'
複製代碼
與其餘新增的語法特性不一樣,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 更優美吧~
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 模塊自己,由於它不是對象。
關於模塊這部分,其實值得展開研究。(我還沒整太明白)
語法的背後,是語言自己的「特性」,他們的出現是爲了解決一些場景的問題。追本溯源是一個很好的學習方式。咱們,下期再見~