低版本浏览器如何运行ECMAScript6特性

作者:简简单单 2015-09-05

ECMAScript 6介绍

ECMAScript 6 于2015年6月正式成为了标准,关于ES6,我们最大的疑虑可能是客户端浏览器还没有完全支持它,也就node.js用用。

有很多种手段可以解决这个问题,比如:通过webpack(请参考博主webpack系列的文章)与babel-loader.
如下图,浏览器借助它们就能跑ES6语法了,也没有增加js负荷(1.6KB)。以下的ES6特性,都可以放心的使用。


BABEL官网链接

    Arrows and Lexical This
    Classes
    Enhanced Object Literals
    Template Strings
    Destructuring
    Default + Rest + Spread
    Let + Const
    Iterators + For..Of
    Map + Set + WeakMap + WeakSet
    Binary and Octal Literals
    Promises
    Reflect API
    Tail Calls

Arrows and Lexical This

Arrows are a function shorthand using the => syntax. They are syntactically similar to the related feature in C#, Java 8 and CoffeeScript. They support both expression and statement bodies. Unlike functions, arrows share the same lexical this as their surrounding code.
=>语法已经加入到js啦,用过java c# 或者CoffeeScript的同学可能对它很熟悉。与函数不同的是,=>里面的语句是与父级共享作用域的(不像function自己再开个)。

// Expression bodies
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);
// Statement bodies
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
});
// Lexical this
var bob = {
  _name: "Bob",
  _friends: [],
  printFriends() {
    this._friends.forEach(f =>
      console.log(this._name + " knows " + f));
  }
};


Classes

ES2015 classes are a simple sugar over the prototype-based OO pattern. Having a single convenient declarative form makes class patterns easier to use, and encourages interoperability. Classes support prototype-based inheritance, super calls, instance and static methods and constructors.
Classes支持属性的继承,调用父级的函数,静态方法,构造器。

class SkinnedMesh extends THREE.Mesh {
  constructor(geometry, materials) {
    super(geometry, materials);
    this.idMatrix = SkinnedMesh.defaultMatrix();
    this.bones = [];
    this.boneMatrices = [];
    //...
  }
  update(camera) {
    //...
    super.update();
  }
  static defaultMatrix() {
    return new THREE.Matrix4();
  }
}


Enhanced Object Literals

Object literals are extended to support setting the prototype at construction, shorthand for foo: foo assignments, defining methods and making super calls. Together, these also bring object literals and class declarations closer together, and let object-based design benefit from some of the same conveniences.
对象在语法方面的扩展:现在可以在构造阶段就配prototype,以前的foo:foo现在可以简写为foo。

var obj = {
    // __proto__
    __proto__: theProtoObj,
    // Does not set internal prototype
    '__proto__': somethingElse,
    // Shorthand for ‘handler: handler’
    handler,
    // Methods
    toString() {
     // Super calls
     return "d " + super.toString();
    },
    // Computed (dynamic) property names
    [ "prop_" + (() => 42)() ]: 42
};


    部分浏览器不支持 __proto__,参考这里

Template Strings

Template strings provide syntactic sugar for constructing strings. This is similar to string interpolation features in Perl, Python and more. Optionally, a tag can be added to allow the string construction to be customized, avoiding injection attacks or constructing higher level data structures from string contents.
ES6引入了Perl,Python中的模版字符串语法,支持了多行字符串。

// Basic literal string creation
`This is a pretty little template string.`

// Multiline strings
`In ES5 this is
 not legal.`

// Interpolate variable bindings
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

Destructuring

Destructuring allows binding using pattern matching, with support for matching arrays and objects. Destructuring is fail-soft, similar to standard object lookup foo["bar"], producing undefined values when not found.
Destructuring 使得我们可以引入更多的匹配式的代码

// list matching
var [a, , b] = [1,2,3];
// object matching
var { op: a, lhs: { op: b }, rhs: c }
       = getASTNode()
// object matching shorthand
// binds `op`, `lhs` and `rhs` in scope
var {op, lhs, rhs} = getASTNode()
// Can be used in parameter position
function g({name: x}) {
  console.log(x);
}
g({name: 5})
// Fail-soft destructuring
var [a] = [];
a === undefined;
// Fail-soft destructuring with defaults
var [a = 1] = [];
a === 1;


这里插一句,BABEL会把以上代码转换成如下

"use strict";
var _ref = [1, 2, 3];
var a = _ref[0];
var b = _ref[2];
var _getASTNode = getASTNode();
var a = _getASTNode.op;
var b = _getASTNode.lhs.op;
var c = _getASTNode.rhs;
var _getASTNode2 = getASTNode();
var op = _getASTNode2.op;
var lhs = _getASTNode2.lhs;
var rhs = _getASTNode2.rhs;
function g(_ref2) {
  var x = _ref2.name;
  console.log(x);
}
g({ name: 5 });
var _ref3 = [];
var a = _ref3[0];
a === undefined;
var _ref4 = [];
var _ref4$0 = _ref4[0];
var a = _ref4$0 === undefined ? 1 : _ref4$0;
a === 1;


Default + Rest + Spread

Callee-evaluated default parameter values. Turn an array into consecutive arguments in a function call. Bind trailing parameters to an array. Rest replaces the need for arguments and addresses common cases more directly.
默认参数已经得到支持,借助...我们可以将数组延展成参数,可以用来替代arguments,也可以用来传参。

function f(x, y=12) {
  // y is 12 if not passed (or passed as undefined)
  return x + y;
}
f(3) == 15
function f(x, ...y) {
  // y is an Array
  return x * y.length;
}
f(3, "hello", true) == 6
function f(x, y, z) {
  return x + y + z;
}
// Pass each elem of array as argument
f(...[1,2,3]) == 6


Let + Const

块级作用域,博主 这篇文章说的更详细点。


Iterators + For..Of

terator objects enable custom iteration like CLR IEnumerable or Java Iterable. Generalize for..in to custom iterator-based iteration with for..of. Don’t require realizing an array, enabling lazy design patterns like LINQ.
C#中的IEnumerable或者说JAVA中的Iterable在ES6中亦有实现,注意,使用for..of而非for..in

let fibonacci = {
  [Symbol.iterator]() {
    let pre = 0, cur = 1;
    return {
      next() {
        [pre, cur] = [cur, pre + cur];
        return { done: false, value: cur }
      }
    }
  }
}
for (var n of fibonacci) {
  // truncate the sequence at 1000
  if (n > 1000)
    break;
  console.log(n);
}


需要引入polyfill

Map + Set + WeakMap + WeakSet

Efficient data structures for common algorithms. WeakMaps provides leak-free object-key’d side tables.
新的WeakXXX解决了内存泄漏问题.

// Sets
var s = new Set();
s.add("hello").add("goodbye").add("hello");
s.size === 2;
s.has("hello") === true;
// Maps
var m = new Map();
m.set("hello", 42);
m.set(s, 34);
m.get(s) == 34;
// Weak Maps
var wm = new WeakMap();
wm.set(s, { extra: 42 });
wm.size === undefined
// Weak Sets
var ws = new WeakSet();
ws.add({ data: 42 });
// Because the added object has no other references, it will not be held in the set


需要引入polyfill

Binary and Octal Literals

Two new numeric literal forms are added for binary (b) and octal (o).


现在可以使用二进制与八进制了。

0b111110111 === 503 // true
0o767 === 503 // true

目前babel还不支持Number("0o767").

Promises

Promises are a library for asynchronous programming. Promises are a first class representation of a value that may be made available in the future. Promises are used in many existing JavaScript libraries.
关于Promises的资料有很多,现在js已经原生支持了。

需要引入polyfill

Reflect API

Full reflection API exposing the runtime-level meta-operations on objects. This is effectively the inverse of the Proxy API, and allows making calls corresponding to the same meta-operations as the proxy traps. Especially useful for implementing proxies.
没错。。。支持反射了。

var O = {a: 1};
Object.defineProperty(O, 'b', {value: 2});
O[Symbol('c')] = 3;
Reflect.ownKeys(O); // ['a', 'b', Symbol(c)]
function C(a, b){
  this.c = a + b;
}
var instance = Reflect.construct(C, [20, 22]);
instance.c; // 42


需要引入polyfill

Tail Calls

Calls in tail-position are guaranteed to not grow the stack unboundedly. Makes recursive algorithms safe in the face of unbounded inputs.
调用堆栈的深度无限制了。

function factorial(n, acc = 1) {
    "use strict";
    if (n <= 1) return acc;
    return factorial(n - 1, n * acc);
}
// Stack overflow in most implementations today,
// but safe on arbitrary inputs in ES2015
factorial(100000)

下面来自知乎关于ECMAScript6的class讨论

问:ECMAScript 6实现了class,对JavaScript前端开发有什么意义?

es6实现了class,对前端开发有什么意义?为什么typescript,coffeescript,react,es6都对class进行实现,class这API会对前端开发有什么影响?


回答:

于江水,前端

然而并没有什么卵用,就是代码格式变了下。

尤雨溪,meteor, vue.js

其实我对 ES6 Class 很无感,一来它不过是个语法糖,二来这个语法糖很坑爹,一些原来能做的事情用纯 class synatx 是做不了的,比如 prototype property 和 static property。因为没有这两个的语法支持,React 用了 ES6 class 以后就没法用 mixin 了,Angular 2 也是,虽然是 TypeScript,但组件的一些必须选项没法直接在 类声明里面表达,又不想倒退回 ES5 那样直接在构造函数上加属性,于是只好依赖 ES7 decorator... (Stage 1提案) 而支持直接在类声明里面声明 static property 的提案目前才 stage 0,所以 ES6 版本的 class 其实很废的。

另外说句不中听的话,搞不懂原型继承就别给 ES6 class 拍手叫好啦,还是去写 java 吧。

李遥,A Programmer

这下真的成为JavaScript了

品雪,人生如梦

貌似没人说关于为什么大家都要上 Class。

照例先吐槽:因为这帮人学 OO 都是从有类的语言开始的呀,没有类总感觉缺了点啥,心里不踏实。

其实主要是个编译期类型检查的好处,动态类型的一个问题是不到代码运行起来,不知道对不对,而弄错对象类型则是常见低级错误。

不过放到 JavaScript 这里,槽点就来了,比如你写了个 class Car,然后编译器应该会知道 myFirstCar.fly() 调了个不存在的方法而报错,可是实际上你随时可以通过 prototype chain 在某个地方给丫加个 fly() 方法,对于大部分正常的程序来说这事儿确实不合理,不过当熟知原型机制的人看到 class 恐怕妨不住会感觉有点错乱呀。

程Tony,会编程的社会观察家

没什么大用。大家都说的很明白了。 Syntax sugar。

本来是灵活的一比那啥的prototype,被套了这么个东西。我反正是选择无视的。

袁梓民,Web前端工程师
只是语法糖,除了缩短代码,并无犀利之处,感觉就和coffee差不多

聂鑫,初级程序员

纠正一下,并未“实现”,只是套了个语法糖而已。JavaScript中从来就没有class。

加入这个语法糖可以让有OOP基础的人更快上手js,至少是一个官方的实现了。但对熟悉js的人来说,这个东西没啥大影响;一个Object.creat()搞定继承,比class简洁清晰的多。

王哲,前端码农 / 顺道折腾下后端 / 果粉


在偷懒的时候,箭头函数绑定的this还挺好用的,可惜就Firefox支持

yibuyisheng,前端工程师


ES6 的 class 有优点也有缺点,整体说来,是利大于弊的,推荐使用。

缺点主要有:
1、语法和语义难对上了,也就是说从书写出来的代码是看不出来内部是通过原型实现相关功能点的。
2、类的写法有一定的限制性,不再像原型那么灵活了。

优点主要有:

1、语法更加紧凑,更加符合传统面相对象的写法了。
2、使 IDE 、类型检查器、代码风格检查器等工具更方便地检测代码语法,做静态分析。
3、 ES6 的类可以继承内置类,并使某些属性和内置类有一样的行为。比如可以继承 Array ,并且子类的 length 属性和 Array 的 length 属性一样会随着元素个数的变化而自动变化。
4、兼容以前的代码。
5、使初学者入门更快。
6、不再需要第三方的继承库。

最后, ES6 的类只是一个基础形式,后续 ECMAScript 版本还会继续添加一些内容进去,比如 trait 、不可变实例等。

其实,从多人开发的大型项目来看,其中使用的大多数语言都包含了类这个元素,并且类在这些项目中还被广泛使用。这就说明类有利于多人大型项目的开发。而 ES6 引入类,也表明了现在的 js 项目越来越复杂了,同时也为 js 在服务器端舞台上大放异彩奠定基础。

颜海镜,Web前端开发工程师

如果了解了原型这个东西还有啥用,语法糖而已,可以少写几行代码,不了解原型,等着掉坑里吧,不过这东西对于其他语言转过来的人很有用哈,javascript终于支持class,他们会认为是javascript很牛逼

知乎用户,http://i2p.kimleo.net 微信公众号:ki2mmy

关我屁事,我用TypeScript。

signer for

JS终于变得人性化了一点。

刚学JS那会,看到各种书籍和各个博客关于实现Javascript继承讨论,简直让人想把书给扔了,想把电脑屏给幕砸了。各种实现方法几十种,而且还乐在其中地分析哪种实现更简洁、哪种性能更好。虽然所有实现都是基于原型链的,但是代码里面的各种奇技淫巧,简直让人抓狂。其他语言用一个关键字解决继承问题,JS偏偏特立独行,各种实现方法看的人眼花缭乱,简直太丧心病狂,太没人道主义精神了。最让人哭笑不得的是,这本来就是当初JS设计的不合理,偏偏一大帮人却把JS的原型特性标榜为这就是JS最强大的地方。

对于我这个懒人来说,我还是拥抱ES6去吧,代码是为产品服务的,花时间去研究各种各样的JS继承实现方法,然后就以为自己的JS基础变得扎实了,还不如直接用ES6的class,花多点空余时间去陪女朋友~

知乎用户,游戏开发


做GUI开发的没有OO真的好么?本身之前用JS也是各种方式绕道实现OO。现在有了直接的方式难道不好了么?

林?,Web 前端,??家

有。
JavaScript最性感的地方便是基於原型的各???大的?承模式,ES6明目???地引入class?法糖,等於?Z恿初?W者延?OOP的?型?承,最??⒛?⒌?avaScript唯一?凫镀渌?Z言之?。

相关文章

精彩推荐