原文地址 ECMAScript 6 — New Features: Overview & Comparison
本文介绍 ECMAScript 6中的新特性并通过具体代码演示与ECMAScript 5的差别。译者额外增加了一些例子和说明 .
ECMAScript 6 是2015年推出的第6版本的ECMAScript标准(即Javascript标准),同时也被成为ECMAScript 2015.
ECMAScript 6 中定了了许多新的Javascript特性,包括新的类和模块,类似python的generators和generators表达式, 箭头函数, 二进制数据, 类型数组, 集合类型(maps, set & 弱maps), promises, reflection, proxy等。它也被称作 ES6 Harmony. (和谐ES6)
本文是该系列文章的第二篇
增强的对象属性
变量速写
缩短了对于对象属性的定义习惯
ECMAScript 6的实现
obj = { x, y }
对比ECMAScript 5的实现
obj = { x: x, y: y };
支持表达式计算属性的定义
支持表达式计算属性的定义
ECMAScript 6的实现
let obj = {
foo: "bar",
[ "baz" + quux() ]: 42
}
对比ECMAScript 5的实现
var obj = {
foo: "bar"
};
obj[ "baz" + quux() ] = 42;
函数属性
支持在对象中直接的函数符号定义, 普通函数和生产(generator)函数均可
ECMAScript 6的实现
obj = {
foo (a, b) {
…
},
bar (x, y) {
…
},
*quux (x, y) {
…
}
}
对比ECMAScript 5的实现
obj = {
foo: function (a, b) {
…
},
bar: function (x, y) {
…
},
// quux: ES5中没有这样的生产(generator)函数
…
};
释放赋值
数组的值匹配
数组可以很直观的释放其中的值到不同的变量中去
ECMAScript 6的实现
var list = [ 1, 2, 3 ]
var [ a, , b ] = list
[ b, a ] = [ a, b ]
对比ECMAScript 5的实现
var list = [ 1, 2, 3 ];
var a = list[0], b = list[2];
var tmp = a; a = b; b = tmp;
对象匹配的便捷符号
可以很直观的把对象中的属性释放到对应的变量中
ECMAScript 6的实现
var { op, lhs, rhs } = getASTNode() // 返回obj中有op, lhs, rhs属性
对比ECMAScript 5的实现
var tmp = getASTNode();
var op = tmp.op;
var lhs = tmp.lhs;
var rhs = tmp.rhs;
对象深层匹配
对于多层的对象属性,也能够通过符号直观的匹配
ECMAScript 6的实现
var { op: a, lhs: { op: b }, rhs: c } = getASTNode() //其中的lhs是一个有op属性的对象
对比ECMAScript 5的实现
var tmp = getASTNode();
var a = tmp.op;
var b = tmp.lhs.op;
var c = tmp.rhs;
参数上下文匹配
对函数传参的时候,也可以方便的把数组和对象释放成不同的参数
ECMAScript 6的实现
function f ([ name, val ]) { // 数组拆出值 相当于传入 (name, val)
console.log(name, val)
}
function g ({ name: n, val: v }) { // 对象拆出值, 相当于传入 (n, v)
console.log(n, v)
}
function h ({ name, val }) { // 对象拆出值, 相当于传入 (name, val)
console.log(name, val)
}
f([ "bar", 42 ])
g({ name: "foo", val: 7 })
h({ name: "bar", val: 42 })
对比ECMAScript 5的实现
function f (arg) {
var name = arg[0];
var val = arg[1];
console.log(name, val);
};
function g (arg) {
var n = arg.name;
var v = arg.val;
console.log(n, v);
};
function h (arg) {
var name = arg.name;
var val = arg.val;
console.log(name, val);
};
f([ "bar", 42 ]);
g({ name: "foo", val: 7 });
h({ name: "bar", val: 42 });
释放的容错机制
当释放的参数无法匹配上时,会自动容错到默认值
ECMAScript 6的实现
var list = [ 7, 42 ]
var [ a = 1, b = 2, c = 3, d ] = list
a === 7
b === 42
c === 3 // 匹配之前默认值3
d === undefined // 无匹配 成为默认undefined
对比ECMAScript 5的实现
var list = [ 7, 42 ];
var a = typeof list[0] !== "undefined" ? list[0] : 1;
var b = typeof list[1] !== "undefined" ? list[1] : 2;
var c = typeof list[2] !== "undefined" ? list[2] : 3;
var d = typeof list[3] !== "undefined" ? list[3] : undefined;
a === 7;
b === 42;
c === 3;
d === undefined;
模块
模块值的导入和导出
支持从模块中导入/导出值,但又不污染全局名字空间
ECMAScript 6的实现
// lib/math.js
export function sum (x, y) { return x + y } // 导出函数
export var pi = 3.141593 // 导出变量
// someApp.js
import * as math from "lib/math"
console.log("2π = " + math.sum(math.pi, math.pi))
// otherApp.js
import { sum, pi } from "lib/math"
console.log("2π = " + sum(pi, pi))
对比ECMAScript 5的实现
LibMath = {};
LibMath.sum = function (x, y) { return x + y };
LibMath.pi = 3.141593;
// someApp.js
var math = LibMath;
console.log("2π = " + math.sum(math.pi, math.pi));
// otherApp.js
var sum = LibMath.sum, pi = LibMath.pi;
console.log("2π = " + sum(pi, pi));
默认和通配符
可以通过通配符导出所有的符号, 通过标记default默认导出 (无需声明)
ECMAScript 6的实现
// lib/mathplusplus.js
export * from "lib/math"
export var e = 2.71828182846
export default (x) => Math.exp(x) //默认导出exp函数
// someApp.js
import exp, { pi, e } from "lib/mathplusplus"
console.log("e^{π} = " + exp(pi))
对比ECMAScript 5的实现
// lib/mathplusplus.js
LibMathPP = {};
for (symbol in LibMath)
if (LibMath.hasOwnProperty(symbol))
LibMathPP[symbol] = LibMath[symbol];
LibMathPP.e = 2.71828182846;
LibMathPP.exp = function (x) { return Math.exp(x) };
// someApp.js
var exp = LibMathPP.exp, pi = LibMathPP.pi, e = LibMathPP.e;
console.log("e^{π} = " + exp(pi));
类
类定义
更加直接,面向对象风格的类
ECMAScript 6的实现
class Shape {
constructor (id, x, y) { // 类的构造函数
this.id = id
this.move(x, y)
}
move (x, y) { // 类函数
this.x = x
this.y = y
}
}
对比ECMAScript 5的实现
var Shape = function (id, x, y) {
this.id = id;
this.move(x, y);
};
Shape.prototype.move = function (x, y) {
this.x = x;
this.y = y;
};
类的继承
面向对象风格的类继承方式
ECMAScript 6的实现
class Rectangle extends Shape {
constructor (id, x, y, width, height) {
super(id, x, y)
this.width = width
this.height = height
}
}
class Circle extends Shape { // Circle继承于Shape同时扩展了构造函数参数
constructor (id, x, y, radius) {
super(id, x, y)
this.radius = radius
}
}
对比ECMAScript 5的实现
var Rectangle = function (id, x, y, width, height) {
Shape.call(this, id, x, y);
this.width = width;
this.height = height;
};
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var Circle = function (id, x, y, radius) {
Shape.call(this, id, x, y);
this.radius = radius;
};
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle; // 需要通过prototype来替换构造函数
类的多继承,聚合
支持对多个类的继承(即对应的类函数的聚合) 需要注意的是以下代码例子中的 聚合(aggregation)函数是有现成的库可以使用的
ECMAScript 6的实现
var aggregation = (baseClass, ...mixins) => {
let base = class _Combined extends baseClass {
constructor (...args) {
super(...args)
mixins.forEach((mixin) => {
mixin.prototype.initializer.call(this)
})
}
}
let copyProps = (target, source) => {
Object.getOwnPropertyNames(source)
.concat(Object.getOwnPropertySymbols(source))
.forEach((prop) => {
if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
return
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))
})
}
mixins.forEach((mixin) => {
copyProps(base.prototype, mixin.prototype)
copyProps(base, mixin)
})
return base
}
class Colored {
initializer () { this._color = "white" }
get color () { return this._color }
set color (v) { this._color = v }
}
class ZCoord {
initializer () { this._z = 0 }
get z () { return this._z }
set z (v) { this._z = v }
}
class Shape {
constructor (x, y) { this._x = x; this._y = y }
get x () { return this._x }
set x (v) { this._x = v }
get y () { return this._y }
set y (v) { this._y = v }
}
class Rectangle extends aggregation(Shape, Colored, ZCoord) {}
var rect = new Rectangle(7, 42)
rect.z = 1000
rect.color = "red"
console.log(rect.x, rect.y, rect.z, rect.color)
对比ECMAScript 5的实现
var aggregation = function (baseClass, mixins) {
var base = function () {
baseClass.apply(this, arguments);
mixins.forEach(function (mixin) {
mixin.prototype.initializer.call(this);
}.bind(this));
};
base.prototype = Object.create(baseClass.prototype);
base.prototype.constructor = base;
var copyProps = function (target, source) {
Object.getOwnPropertyNames(source).forEach(function (prop) {
if (prop.match(/^(?:constructor|prototype|arguments|caller|name|bind|call|apply|toString|length)$/))
return
Object.defineProperty(target, prop, Object.getOwnPropertyDescriptor(source, prop))
})
}
mixins.forEach(function (mixin) {
copyProps(base.prototype, mixin.prototype);
copyProps(base, mixin);
});
return base;
};
var Colored = function () {};
Colored.prototype = {
initializer: function () { this._color = "white"; },
getColor: function () { return this._color; },
setColor: function (v) { this._color = v; }
};
var ZCoord = function () {};
ZCoord.prototype = {
initializer: function () { this._z = 0; },
getZ: function () { return this._z; },
setZ: function (v) { this._z = v; }
};
var Shape = function (x, y) {
this._x = x; this._y = y;
};
Shape.prototype = {
getX: function () { return this._x; },
setX: function (v) { this._x = v; },
getY: function () { return this._y; },
setY: function (v) { this._y = v; }
}
var _Combined = aggregation(Shape, [ Colored, ZCoord ]);
var Rectangle = function (x, y) {
_Combined.call(this, x, y);
};
Rectangle.prototype = Object.create(_Combined.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle(7, 42);
rect.setZ(1000);
rect.setColor("red");
console.log(rect.getX(), rect.getY(), rect.getZ(), rect.getColor());
基类的访问
对基类的构造函数和方法的直观访问。
ECMAScript 6的实现
class Shape {
…
toString () {
return `Shape(${this.id})`
}
}
class Rectangle extends Shape {
constructor (id, x, y, width, height) {
super(id, x, y)
…
}
toString () {
return "Rectangle > " + super.toString() // 通过super 访问父类
}
}
class Circle extends Shape {
constructor (id, x, y, radius) {
super(id, x, y)
…
}
toString () {
return "Circle > " + super.toString()
}
}
对比ECMAScript 5的实现
var Shape = function (id, x, y) {
…
};
Shape.prototype.toString = function (x, y) {
return "Shape(" + this.id + ")"
};
var Rectangle = function (id, x, y, width, height) {
Shape.call(this, id, x, y);
…
};
Rectangle.prototype.toString = function () {
return "Rectangle > " + Shape.prototype.toString.call(this);
};
var Circle = function (id, x, y, radius) {
Shape.call(this, id, x, y);
…
};
Circle.prototype.toString = function () {
return "Circle > " + Shape.prototype.toString.call(this); //没有super只能通过对应的原型中函数调用
};
静态成员
简单的支持类静态成员
ECMAScript 6的实现
class Rectangle extends Shape {
…
static defaultRectangle () {
return new Rectangle("default", 0, 0, 100, 100)
}
}
class Circle extends Shape {
…
static defaultCircle () {
return new Circle("default", 0, 0, 100)
}
}
var defRectangle = Rectangle.defaultRectangle()
var defCircle = Circle.defaultCircle()
对比ECMAScript 5的实现
var Rectangle = function (id, x, y, width, height) {
…
};
Rectangle.defaultRectangle = function () {
return new Rectangle("default", 0, 0, 100, 100);
};
var Circle = function (id, x, y, width, height) {
…
};
Circle.defaultCircle = function () {
return new Circle("default", 0, 0, 100);
};
var defRectangle = Rectangle.defaultRectangle();
var defCircle = Circle.defaultCircle();
Getter/Setter
Getter/Setter 支持直接在类中定义了
ECMAScript 6的实现
class Rectangle {
constructor (width, height) {
this._width = width
this._height = height
}
set width (width) { this._width = width }
get width () { return this._width }
set height (height) { this._height = height }
get height () { return this._height }
get area () { return this._width * this._height }
}
var r = new Rectangle(50, 20)
r.area === 1000
对比ECMAScript 5的实现
var Rectangle = function (width, height) {
this._width = width;
this._height = height;
};
Rectangle.prototype = {
set width (width) { this._width = width; },
get width () { return this._width; },
set height (height) { this._height = height; },
get height () { return this._height; },
get area () { return this._width * this._height; }
};
var r = new Rectangle(50, 20);
r.area === 1000;
网友评论