让咱们先来玩一个游戏,根据 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 模块自己,由于它不是对象。
关于模块这部分,其实值得展开研究。(我还没整太明白)
语法的背后,是语言自己的“特性”,他们的出现是为了解决一些场景的问题。追本溯源是一个很好的学习方式。咱们,下期再见~