为什么要说一下生成器的原型继承关系呢,因为它的关系确实比较复杂,在ES6规范中仅有两张图片,其中一张就是描述生成器的原型链,可见其复杂性。废话不多说,我们直接看图:
我们用下面的简单代验证这个关系:
function* genFunc() {
yield;
}
var g = new genFunc();
先看一下(Generator).prototype,因为生成器上实现迭代器接口的方法都定义在了它上面:
规范中的return和throw方法都是可选的,Chrome浏览器默认实现了throw,并没有实现return。
接着看为什么生成器也是迭代器,我们知道迭代器必须定义一个名字叫Symbol.iterator的方法,这个方法定义在了(IteratorPrototype)上:
搞清了上面的一些关系,假如我们要给genFunc的所有实例都添加一个叫method的方法,应该怎么做比较好?显然我们应该在层次更低的原型上添加公用方法更好,因为这样不会影响其他对象。就拿genFunc来讲,method方法应该放在genFunc.prototype上面而不是(Generator).prototype上面。
genFunc.prototype.method = function(){
console.log("*genFunc -> method");
}
g.method();
如果我们想给所有生成器都添加一个公用方法叫commonMethod,应该怎么做?显然这次应该添加在(Generator).prototype上面,而不是(IteratorPrototype),因为添加在(IteratorPrototype)上会影响所有的迭代器,而迭代器未必都是生成器,自己仔细想想。
let Generator_prototype = Object.getPrototypeOf(genFunc).prototype;
//let Generator_prototype = Object.getPrototypeOf(genFunc.prototype);
Generator_prototype.commonMethod = function () { console.log("Generator -> commonMethod")};
g.commonMethod()
上面这张图还描述了迭代器的原型继承关系,如果们要给所有的迭代器都添加一个公用方法,应该怎么做?
var Iterator_prototype = Object.getPrototypeOf(Object.getPrototypeOf(genFunc.prototype));
Iterator_prototype.iterMethod = function(){console.log("Iterator -> iterMethod")};
g.iterMethod();
var iter = g[Symbol.iterator]();
iter.iterMethod();
var iter2 = [][Symbol.iterator]();
iter2.iterMethod();
是不是觉得上面的那段代码有点晕?所以我们更应该好好理解一下这样图的继承关系,这样才能灵活扩展迭代器和生成器。
*以上全部代码在Chrome 48下通过测试