【问题标题】:How can I make a prototype of a prototype in JavaScript?如何在 JavaScript 中制作原型的原型?
【发布时间】:2014-07-08 01:29:48
【问题描述】:

我正在尝试在 Javascript 中创建原型的原型。我希望我的原型继承某些方法,而不是使用从头开始构建的普通原型,而不是以下功能。

因此,我在原型中添加了一个方法logDependencies(),而不是这段代码,以检查Car 实例中是否有Dependency 的任何实例:

function Dependency(data) {
    this.data = data;
}

function Car(color) {
    this.color = new Dependency(color);

    this.logDependencies = function () {
        for (var key in this)
            if (this.hasOwnProperty(key))
                if (this[key] instanceof Dependency)
                    console.log("Dependency: " + key);
    };
}

var lamborghini = new Car("red");

lamborghini.logDependencies();

我希望我的所有原型继承函数logDependencies(),而不需要我手动添加它。

我该怎么做?


更新:

对于那些对我的措辞感到困惑的人:

我正在尝试制作一个原型设计函数,它允许我创建继承某些属性和方法的原型,并将它们传递到继承链中。

Douglas Crockford 的相关文章(强调我自己的):

我的旅程很曲折,因为 JavaScript 本身就其原型性质存在冲突。在原型系统中,对象继承自对象。然而,JavaScript 缺少执行该操作的运算符。相反,它有一个新的运算符,这样new f() 会生成一个继承自f.prototype 的新对象。

这种间接方式旨在让受过经典培训的程序员更熟悉该语言,但未能做到这一点,正如我们从 Java 程序员对 JavaScript 的极低评价中可以看出的那样。 JavaScript 的构造函数模式并不吸引经典人群。它还掩盖了 JavaScript 真正的原型性质。因此,很少有程序员知道如何有效地使用该语言。

幸运的是,创建一个实现真正原型继承的运算符很容易。这是我工具包中的标准功能,我强烈推荐给你。

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

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

所以不是创建类,而是创建原型对象,然后使用对象函数创建新实例。对象在 JavaScript 中是可变的,因此我们可以扩充新实例,为它们提供新的字段和方法。然后这些可以作为更新对象的原型。我们不需要类来制作大量相似的对象。

为方便起见,我们可以创建函数来为我们调用对象函数,并提供其他自定义,例如用特权函数扩充新对象。 我有时将这些创建函数称为。如果我们有一个 maker 函数调用另一个 maker 函数而不是调用 object 函数,那么我们就有一个寄生继承模式。

我发现通过使用这些工具,再加上 JavaScript 的 lambda 和对象准字面量,我可以编写结构良好的大型、复杂和高效的程序。迄今为止,经典对象模型是当今最流行的,但我认为原型对象模型的能力更强,表达能力更强。

【问题讨论】:

  • 如果dependency被用作构造函数,那它为什么会有return语句呢?
  • 您是说您希望 logDependencies 在全球范围内可用,还是您希望在无需手动调用的情况下调用 logDependencies?
  • 我的意思是,如果你把它称为dependency('red'),return 语句是有意义的,但是如果你把它称为new dependency('red'),那么return 语句是没有意义的,因为new 的结果总是返回this
  • @joshboley 我说我想创建一个原型,从它自己的原型继承方法logDependencies()。继承某些方法的特殊原型。不,我不希望这些方法是全局的。
  • 好的@jt0dd,如果你实现了你的要求,你能举一个你希望顺利工作的代码示例吗?

标签: javascript prototype


【解决方案1】:

听起来你只是想添加到汽车的原型?或者您想将它添加到您创建的所有东西的原型中(不明智)?

car.prototype.logDependencies = function(){ return 'whatever'; }

var lamborghini = new car('red');

lamborghini.logDependencies(); // whatever 

以下是让一个体面的 JavaScript 开发人员生气的方法:

Object.prototype.logDependencies = function(){ return "I just don't give a..."; }

var anything = new Object();

anything.logDependencies(); // I just don't give a...

为了澄清,上述不好的原因在您发布的文章中进行了解释:

对象函数的问题在于它是全局的,而且是全局的 显然是有问题的。 Object.prototype.[someMethod] 的问题 是它绊倒了无能的程序,它可以产生 覆盖 [someMethod] 时的意外结果。

读过你的 cmets,我觉得你好像在寻找某种魔杖。也许您来自 Java 世界?还是 Actionscript 3 世界?类型更强,继承是经典的。 JavaScript 是一种非常具有延展性的语言,我们都设法以某种形式从其中挤出了其他语言的某些方面。但是,如果您要求 JavaScript 执行某种基于类的继承系统,而无需调用一些方法并到处声明一些变量,那么您将大失所望。

我建议您阅读 Douglas Crockford 的 other article,其中他解释了 JavaScript 的原型系统是多么有用,并暗示了如何利用经典的类继承特性。

【讨论】:

  • 请把“生气”从你的答案中去掉,这可能只会让没有真正掌握原型概念的OP感到困惑。至少你需要说明为什么这是错误的。
  • 诺诺诺。假设我想构建一个非常面向对象并利用依赖注入的框架。我想构建一个从“父”原型继承方法的原型。所有使用增强原型创建通过框架创建的原型都应继承findDependencies()等方法和其他相关方法,以便在应用程序引擎的每个组件中进行依赖注入。
  • Douglas Crockford talks about it - 真正的原型继承。
  • @jt0dd:原型是继承机制,就像c++中的:或java中的extends。与其专注于原型,不如问你想问的实际问题:你想要什么功能?
【解决方案2】:

如果您想要car 具有parent 原型化的所有功能的继承线,那么您可以使用:

car.prototype = Object.create(parent.prototype);

基本上,Object.create(obj) 返回一个原型设置为obj 的新对象。 car 的所有实例都将其原型设置为 car.prototype。因此,他们将可以通过原型链访问parent 的函数。

【讨论】:

  • 我正在考虑创建一个新的原型方法(或子原型)的原型,它从它的原型继承某些方法,并将它们传递给它所促进的任何对象原型.
  • 您的示例代码非常开放,提供的所有答案都符合您的要求,但您并不满意。你需要想出一个例子来更好地说明你想要完成的事情。
  • 我的示例是开放式的,因为要创建一个好的示例,我必须已经知道如何做我所要求的...查看所附文章的重点区域。如果你看到我的目标,也许你可以帮助我更好地表达我的问题。
  • @jt0dd - 为什么不写一些伪代码。也就是说,编写故意不工作但具有您想要的确切语法/结构的代码,以便人们可以告诉您如何获得您想要的功能。换句话说,不要在您的示例中使用“原型”,因为它会将继承机制与您想要的继承行为混淆。
【解决方案3】:

您始终可以使用 mixins 来共享功能。例如:

var mixinLogger = (function () {
    return function (that) {
        that.logDependencies = logDependencies;
        return that;
    };

    function logDependencies() {
        for (var key in this)
            if (this.hasOwnProperty(key) &&
                this[key] instanceof Dependency)
                console.log("Dependency: " + key);
    }
}());

你按如下方式使用它:

function Dependency(data) {
    this.data = data;
}

function Car(color) {
    this.color = new Dependency(color);
}

mixinLogger(Car.prototype);

使用 mixin 的优点是它们是可组合的。例如,如果您有两个 mixin(mixinAmixinB),那么您可以将它们链接如下:

mixinA(mixinB(Something.prototype));

您甚至可以创建一个由两者组合而成的新 mixin:

function compose() {
    var fs = arguments;
    var length = fs.length;

    return function (x) {
        var index = length;
        while (index > 0) x = fs[--index](x);
        return x;
    };
}

var mixinC = compose(mixinA, mixinB);

事实上,您可以根据需要组合任意数量的 mixin,以创建新的 mixin。

如果您想了解更多信息,请阅读博文“A fresh look at JavaScript Mixins”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    • 1970-01-01
    相关资源
    最近更新 更多