node.js 4.0 是 node.js 与 io.js 回归统一之后正式推出的第一个版本。这说明从此以后, node.js 将采用 io.js 的理念,积极跟进 v8 引擎的更新,支持各种各样的ES6新特性而不必加上 harmony 标签。测试稳定后的新特性将会成为 node.js 的一等公民。新特性未来将分成三种组别,分别是:交付、展示、进行中。分别是稳定版和公测版以及测试版的意思。

 

目前发布的 4.0 测试版有以下稳定特性:

Block scoping 块级作用域

块是指由显式或隐式{}包含起来的代码,比如  if (…) {}  for (…) {} 括起来的部分即为块。在以往的标准中块是没有独立的作用域的,而是与函数体共享一个作用域。在作异步编程中有时会制造一些麻烦。ES6带来的块级作用域便是用来解决这一类的问题。

let

let 和 var 一样,是用来声明变量的,不同的时,var 是作用于函数体,而 let 则是作用于块级。请看代码:

1
2
3
4
5
for (var i = 0; i < 10; i++) {
  process.nextTick(function(){
    console.log(i);
  });
}

也许你会以为上面的代码会输出0到9,事实上这个只会输出10个9。因为 js 是按块级去执行代码,上面其实是先把循环0到9执行完了,再去一个个执行 nextTick 传入的函数。而每个函数引用的都是局部变量i,而这个时候i已经是9,自然就输出10个9了。

而let这个时候把 var 换成 let ,你会发现程序可以正确地输出 0~9 了,let 声明的是块级变量。也就是说每个 process.nextTick 会引用于属于它自己的 i ,而不是引用到同一个局部变量,如此一来程序便可以正确输出。

const

const 关键字就好理解了,毕竟各种语言都有。js 一向缺少定义常量的功能,const 就是用来定义常量的。需要注意的是如果 const 定义的是一个 Array 或 Object 这样类型的变量,那变量的本身内容是可能被修改的:

1
2
3
const FOOBAR = { "foo": 1, "bar": 2 };
FOOBAR.foo = 3; // this is legal.
FOOBAR = { "foo": 3, "bar": 4}; // this is illegal.

function-in-block

这个应该块级函数作用域方面的特性,没有找到太多资料。目测应该与 let 是一类的意思。根据说明文档,这个东西目前还不是按ES6标准实现。未来可能会发生变化。

Class 类 (仅严格模式可用)

这个是比较重量级的新特性了,OO编程的基本元素。虽说一直以来有 prototype 这样的东西可以实现相似的功能,但定义起来毕竟别扭,虽然有很多类库帮助方便的定义类,但这样也造成各种不统一。参考起别人的代码总要费些劲。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Square extends Polygon {
    constructor(height, width) {
        this.height = height;
        this.width = width;
        super.name = 'Square';
    }

    get area() {
        return this.height * this.width;
    }

    static areaEqual(a, b) {
        return a.area == b.area;
    }
}

很好,构造函数、属性、静态函数都有了,也不用写那么多 function ,这样定义一个类可要比以往写少很多代码了。结构明显清晰多了。

Collection 集合

Map 字典

基本上这是跟 Object 很类似的类型,在 ES6 出现以前我们一向是把 Object 当作字典来使用的。那么 Map 与 Object 相比有哪些优势?我们为什么要用 Map 而不是 Object:

  • Object 是有  prototype 的,也就是说在遍历的时候要特别处理,否则 prototype  的条目也会被包含进来。当然,用 Object.create(null) 也可以避免这个问题。
  • Object 只接受 String 类型作为键(KEY),而 Map 可以接受任意类型的变量作为键,这跟Java/.NET 的字典类型行为一致。
  • Map 内部有维护一个条目数量 size ,随时可以通过 size 属性来知道字典里面条目的数量,跟Array的length差不多。而 Object 则是没有这样的东东的,只能手动一个个地算。
  • 虽然目前 Object 实际上是有序的,但根据标准,Object 并不保证 key 的有序性。而 Map 规定是有序的,按插入顺序排列。

WeakMap 弱字典

这个跟 Map 是类似的东西,但它的键是弱引用。在 Map 中由于键是强引用,它会阻止垃圾回收系统对键和值进行回收。弱引用的在于它不会阻止垃圾回收对键值进行删除,当程序其它引用该键的变量解除引用后,GC便会进行回收,相应的,WeakMap 中的键值对也会被删除。因为受到垃圾回收的影响,所以 WeakMap 是无法对键值进行遍历。这个貌似可以用来做缓存系统?

Set 唯一集合

跟数组类似,不同的是 Set 针对相同的值只存储一个,另外的区别就是不能下标引用。以往在没有 Set 的情况下只能用  Object 的 Key 来代替,有了这个,在内存占用上会更有优势,另外还有 length  的属性可供使用,方便多了。

WeakSet 弱引用唯一集合

这个原理上跟 WeakMap  是一样的,只不过 Map 变成了 Set

TypedArray 强类型数姐

如果你接触的语言够多,会发现,弱类型语言的数组和强类型的数组是很不一样的。一般的强类型语言,数组Array是长度不变的(当然类型也是固定的),而弱类型数组更像是强类型中的 List 或者  LinkList ,长度可变,可以存储任意类型的数组。随着 js 在 web Server端的崛起,人们开始需要直接通过 js 操作二进制原始数组,而 TypedArray 就是对应这个需求出现的特性。

需要注意的是,在使用 Array.isArray 对 TypedArray 进行判断时是会返回 false 的。也就是它在本质上并非是 Array 。

在架构上,TypedArray 分为两种层,底层是 ArrayBuffer 类型,这是一种纯粹的二进制数据,没有格式,无法直接进行操作。要对原始数据进行操作,需要通过 View 层进行,分别是 Int8Array、Uint8Array、Int16Array、Uint16Array 等类型。

1
2
3
4
5
6
7
8
var buffer = new ArrayBuffer(16);

if (buffer.byteLength === 16) {
  console.log("Yes, it's 16 bytes.");
} else {
  console.log("Oh no, it's the wrong size!");
}
var int32View = new Int32Array(buffer);`

Generator 生成器

通过 function* 关键字,可以定义一个返回 Generator 的函数。Generator 某程度上跟 c# 的迭代器很相似。Generator 类似于 c# 中实现了 IEnumerable 的类。function* 返回的实际上是一个 Generator 实例,这个 Generator 在 yield 的地方会将值返回给调用方,然后再继续执行后面的指令。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
function* anotherGenerator(i) {
  yield i + 1;
  yield i + 2;
  yield i + 3;
}

function* generator(i){
  yield i;
  yield* anotherGenerator(i);
  yield i + 10;
}

var gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 11
console.log(gen.next().value); // 12
console.log(gen.next().value); // 13
console.log(gen.next().value); // 20

整个 Koa.js 都是基于生成器作为中间件链接动作,说明这个特性也是重量级的特性,将来应用必然会很广。

Binary & Octal literal 二进制和八进制字面量

1
2
3
4
0777 // 前面加零即为定义八进制字面量,若数字中有超过8的则视为定义十六进制字面量
0o777 // 前面加0o即为定义八进制字段量
0b00001111 // 前面加0b即为定义二进制字面量
0xA0A0A0 // 前面加0x即为定义十六进制字面量

Extended Object literal 扩展对象字面量

这是对 Object 实便声明的一种扩展,说起来挺复杂,不如直接看代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var obj = {
    // 指定 prototype
    __proto__: theProtoObj,
    // ‘handler: handler’ 简化声明方式
    handler,
    // 'toString: function()' 的简化声明方式
    toString() {
     // Super calls
     return "d " + super.toString();
    },
    // 动态属性名
    [ 'prop_' + (() => 42)() ]: 42
};

那么,没错,就是这么吊!

Promises 承诺对象

那么,也就是说 bluebird 可以退休了?也好!棒子的英语水平太牛逼了,看他们的文档实在是折磨人!

New String methods 新增的 String 方法

代替了一部份 lodash 的功能,详情请戳这里

Symbol 符号

这玩意大概是从 ruby 移植过来的概念,代表唯一且不可变的标识!嗯,太抽象了,说实话一直不太喜欢 ruby 的这种设定。有什么特别实用的地方吗?看 mozilla 的文档,貌似可以用来将一些信息隐式存储到 Object 实例中。因为 for in 和 Object.getOwnPropertyNames 都不会返回 Symbol 类型的键。由于唯一性,new Symbol(‘foo’) != new Symbol(‘foo’),详情还是戳这里,大家发现有什么应用的地方可以参详一下。

Template String 模板字符串

来自 Perl、Shell Script、PHP的精华!通过反引号``实现,可以跨行,支持变量自动替换。很实用的新特性。

ES5代码:

1
2
3
4
5
var a = 5;
var b = 10;
console.log("Fifteen is " + (a + b) + " and\nnot " + (2 * a + b) + ".");
// "Fifteen is 15 and
// not 20."

ES6代码:

1
2
3
4
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and
not ${2 * a + b}.`);

可以看到代码量又显著减少了。各种喜闻乐见啊有木有。

Arrow Function 箭头函数

可以说这个是我个人最喜欢的新特性了,能少打几个字不说,代码看起来也更简练直观!

1
2
3
4
5
6
7
8
9
var a = [
  "Hydrogen",
  "Helium",
  "Lithium",
  "Beryl­lium"
];

var a2 = a.map(function(s){ return s.length }); //es5
var a3 = a.map( s => s.length ); // es6

这个特性必须给五星好评。