【问题标题】:Object.create vs direct prototypical inheritanceObject.create 与直接原型继承
【发布时间】:2011-09-14 08:51:34
【问题描述】:

我一直在玩 EcmaScript 5 规范中的 Object.create,我正在尝试创建一个多重继承类型结构。

假设我有几个函数:a、b 和 c。只处理原型,我可以这样做:

function a () {}
a.prototype = {
    fnA = function () {},
    propA = 500
};

function b () {}
b.prototype = a.prototype;
b.prototype.fnB = function () {};
b.prototype.propB = 300;

function c () {}
c.prototype = b.prototype;
c.prototype.fnC = function () {};
c.prototype.propC = 200;

但是使用 Object.create,我会这样做:

function a() {}
a.prototype = {
    fnA = function () {},
    propA = 500
};

var b = Object.create(new a());
b.fnB = function () {};
b.propB = 300;

var c = Object.create(b);
c.fnC = function () {};
c.propC = 200;

我想我两种方式都得到相同的结果。

这似乎有点笨拙,因为我返回的是对象而不是构造函数。在我看来,进行常规原型继承的侵入性较小,并且对于不需要任何特殊处理即可工作的模块化应用程序更有意义。

我错过了什么吗?尝试通过制作构造函数来制作 Object.create 有什么好处吗?还是这仅对复制现有对象有用?我只想访问附加到原型的属性和函数,而不是之后添加到对象的函数和属性。

或者这个(或者使用更好的深拷贝,但想法保持不变)?

function A () {}
A.prototype = {
    fn: function () {
        console.log(this.propA + 30);
    },
    propA: 20
};

function B () {}
Object.keys(A.prototype).forEach(function (item) {
    B.prototype[item] = A.prototype[item];
});
B.prototype.propA = 40;

function C () {}
Object.keys(B.prototype).forEach(function (item) {
    C.prototype[item] = B.prototype[item];
});
C.prototype.fn = function () {
    console.log(this.propA + 3);
};


var a = new A(),
    b = new B(),
    c = new C();

a.fn();
b.fn();
c.fn();

【问题讨论】:

    标签: javascript ecmascript-5 prototypal-inheritance object-create


    【解决方案1】:

    实际上,两种方式都不会得到相同的结果。考虑这一行:

    b.prototype = a.prototype;
    

    这样做是将b.prototype 设置为与a.prototype 完全相同的对象引用。如果您更改第一个对象(例如通过添加fnB 方法),您还将更改第二个对象。他们是一样的东西。在您的第一组代码结束时,您将拥有三个完全相同的原型,具有相同的方法和属性。

    原型继承的全部意义在于您定义一个“有趣”的对象(即具有您想要的所有行为),然后使用 Object.create 克隆它并修改克隆以满足您的需要(通常通过修改它的属性,而不是它的方法)。

    假设你有一个加法器对象:

    var adder = {x: 0, y: 0};
    adder.execute = function () {
      return this.x + this.y;
    }
    

    然后你创建一个克隆并设置它的属性:

    var myadder = Object.create(adder);
    myadder.x = 1;
    myadder.y = 2;
    console.log(myadder.execute()); // 3
    

    现在显然这是一个愚蠢的例子,但它表明您可以考虑原型继承,而不必在这些构造函数上编写构造函数和显式原型。

    【讨论】:

    • 对,我想是的。但是,如果我将 a 中的所有属性复制到 b 的原型中,然后在原型中添加东西,然后对 c 做同样的事情呢?这会达到同样的效果吗?
    • 最好使用Object.create。所以,b.prototype = Object.create(a.prototype); 然后我们使用更好的解决方案使较小的解决方案变得更好。
    • 我可以再做一个构造函数吗?假设我做 Object.create,我可以做 function new () {} new.prototype = Object.create(b); 或类似的东西吗?我只想要一个可导出的功能...
    • 当然。你可以做任何你想做的事。没有真正坚定的规则。只需选择对您来说更自然的东西,然后去做。
    • execute() 会抛出 ReferenceError 除非您将其更改为 return this.x + this.y;
    【解决方案2】:

    如果需要支持不支持Object.create()的浏览器可以使用这个

    function object(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }
    

    对象函数解开了 JavaScript 的构造函数模式,实现了真正的原型继承。它接受一个旧对象作为参数,并返回一个继承自旧对象的空新对象。如果我们尝试从新对象获取成员,但它缺少该键,则旧对象将提供该成员。对象继承自对象。还有什么比这更面向对象的呢?

    更多内容可以在这里阅读:Prototypal Inheritance in JavaScript

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 2012-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多