【问题标题】:create an object that extends another创建一个扩展另一个对象
【发布时间】:2013-06-23 21:45:39
【问题描述】:

我有一个这样的对象:

var source = (function(undefined) {
    var o;
    function s(o) {
        if(!o || typeof o === 'object') {
            o = o || {};
            o.a = typeof o.a === 'string' ? o.a : 'A';
            o.b = typeof o.b === 'string' ? o.b : 'B';
            this.o = o;
        }
    }
    s.prototype.v = function() {
        // some function
    };
    s.prototype.x = function() {
        // some function
    };
    return s;
})();

我想用另一个类似的来扩展第一个。

var extender = (function(undefined) {
    var o;
    function e(o) {
        if(!o || typeof o === 'object') {
            o = o || {};
            o.c = typeof o.c === 'number' ? o.c : 3;
            o.d = typeof o.d === 'number' ? o.d : 4;
            this.o = o;
        }
    }
    e.prototype.y = function(m) {
        // some function
    };
    e.prototype.z = function(m) {
        // some function
    };
    return e;
})();

我可以将this.s = new source(o); 添加到函数中,对我的第二个对象进行一些小的更改可以将所有内容与第一个对象联系起来,但我认为可能有更好的方法。

【问题讨论】:

  • 你到底为什么要调用你的变量undefined?这是您在 Javascript 中可以做的最邪恶的事情之一。
  • @Antimony:不;他正在创建一个本地undefined 变量以防其他人设置window.undefined。 jQuery 就是这样做的。
  • 为什么会有问题?和wtf为什么有人要设置window.undefined?
  • 不知道为什么有人会这样做。但避免问题是一个好习惯。我在这里发布的代码只是一个示例。真实的代码有一些验证需要 undefined 为 UNDEFINED。
  • @SLaks 哦,这是一个巧妙的技巧。

标签: javascript


【解决方案1】:

要将其他两个答案中的 sn-ps 结合到正确的解决方案中,您可能需要

var extender = (function(undefined) {
    // var o; - That's useless, `o` is a parameter of the constructor
    function e(o) {
        source.call(this, o); // invoke the `source` constructor on this instance
        o = this.o; // and get the created `o` object
        // …to extend it:
        o.c = typeof o.c === 'number' ? o.c : 3;
        o.d = typeof o.d === 'number' ? o.d : 4;
    }

    // make the prototype a new object inheriting `v` and `x`:
    e.prototype = Object.create(source.prototype);
    // then extend it
    e.prototype.y = function(m) {
        …
    };
    e.prototype.z = function(m) {
        …
    };
    return e;
})();

请参阅 Object.createcall 的文档。

【讨论】:

  • 呃,我没有。要评论它:-)
  • @tntu:不,不是。它将创建一个完整的instance,并调用构造函数——但没有任何参数(这将没有意义)。您只需要继承,创建由所有extender 对象共享的实例事物(在构造函数中)可能会产生严重的问题。
  • 那么两者都将指向同一个对象,您将基本上在source.prototype 上创建yz。使用common and old shim for Object.create 使其在旧版浏览器中顺利运行没有任何问题
  • 感谢您的努力。你赢了 :) 随意删除你的 cmets 以保持这个问题整洁。
  • @tntu:为什么要“整洁”?我知道我的帖子不是很全面,很多事情都没有很好地解释。对您额外问题的回答是我回答的一部分,并且仍然可以帮助其他人理解该主题(如果问题仍然存在,这可能会更好:-)
【解决方案2】:

你可以使用:-

Object.create(o);//where o is object to inherit from

跨浏览器:-

 if (typeof Object.create !== "function")
            Object.create = function(o) {
                function F() {}
                F.prototype = o;
                return new F();
 };

【讨论】:

  • 不。 Object.create 是新对象函数,用于从传递给它的对象创建新对象。现代浏览器对此提供支持。 “if”适用于不支持此功能的浏览器。
  • 是否有适用于所有浏览器的解决方案?另外,我需要从第二个的主要功能内部利用源对象。我需要能够将初始化参数传递给扩展器并从 ti 传递给源。
  • “if”用于跨浏览器实现。您可以将参数发送到 Object.create();欲了解更多信息:- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • else 案例中我该怎么办?
  • 没什么。你不需要其他任何东西。
【解决方案3】:

检查以下两行:

e.prototype = source.prototype;

source.call(this, o);

他们是解决方案。

当然,我必须对配置进行一些调整以确保两者都能正常运行。

var source = (function(undefined) {
    function s(o) {
        // config
        this.o = {};
        if(!o || typeof o === 'object') {
            o = o || {};
            this.o.a = typeof o.a === 'string' ? o.a : 'A';
            this.o.b = typeof o.b === 'string' ? o.b : 'B';
        }
    }
    s.prototype.x = function(m) {
        console.log(m);
    };
    return s;
})();
var extender = (function(undefined) {
    function e(o) {
        // instanciate parent
        source.call(this, o);
        // child config
        if(!o || typeof o === 'object') {
            o = o || {};
            e = this.o;
            e.c = typeof o.c === 'number' ? o.c : 1;
            e.d = typeof o.d === 'number' ? o.d : 2;
        }
    }
    // inherit
    e.prototype = source.prototype;
    // extend
    e.prototype.y = function(m) {
        console.log(m);
    };
    return e;
})();
var e = new extender({d:3});
console.log(e);

【讨论】:

  • 我不认为source.call(o) 是一个解决方案。您是否注意到它在您传递的o 参数上创建了o 属性(带有ab 子属性),而不是结果对象(thise 构造函数中)?
  • 还要注意您should not use new 用于原型对象的创建。在你的情况下,你甚至可能得到issues with nested objects
  • 尝试登录 source.prototype.y 并感到惊讶 :-)
  • 您希望y 仅出现在extender.prototype 上,而vx 都出现在两者上?如果您将它们分配给彼此,那么将只有一个对象 - 并且所有属性都无处不在。
  • 这就是我想要的。这不成问题。谢谢你的解释。现在我知道你和我的区别了。你可以说你的继承而我的继承。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-09
  • 1970-01-01
  • 2012-03-07
  • 1970-01-01
  • 2011-09-21
  • 2011-05-07
相关资源
最近更新 更多