简体   繁体   English

如何用JavaScript制作原型?

[英]How can I make a prototype of a prototype in JavaScript?

I'm trying to create a prototype of a prototype in Javascript. 我正在尝试用Javascript创建原型的原型。 Instead of the following functionality, utilizing normal prototypes, built from scratch, I'd like my prototypes to inherit certain methods without me adding them to each one. 除了使用普通的原型(从头开始构建)之外,我还希望我的原型继承某些方法,而不用将它们添加到每个方法中,而不是使用以下功能。

So instead of this code, where I've added a method logDependencies() within the prototype to check if there are any instances of Dependency within the Car instance: 因此,代替此代码,我在原型内添加了方法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();

I'd like to instead have all of my prototypes inherit the function logDependencies() , without me manually adding it. 我想让我的所有原型都继承函数logDependencies() ,而无需手动添加它。

How can I do this? 我怎样才能做到这一点?


Update: 更新:

For those of you confused by my wording: 对于那些我的措辞感到困惑的人:

I'm trying to make a prototyping function that allows me to create prototypes who inherit certain properties and methods, passing them down the inheritance chain. 我正在尝试创建一个原型功能 ,该功能使我可以创建继承某些属性和方法的原型,并将它们传递给继承链。

A related article by Douglas Crockford (emphasis my own): 道格拉斯·克罗克福德(Douglas Crockford)的相关文章(强调我自己):

My journey was circuitous because JavaScript itself is conflicted about its prototypal nature. 我的旅程是circuit回曲折的,因为JavaScript本身与其原型性质存在冲突。 In a prototypal system, objects inherit from objects. 在原型系统中,对象从对象继承。 JavaScript, however, lacks an operator that performs that operation. 但是,JavaScript缺少执行该操作的运算符。 Instead it has a new operator, such that new f() produces a new object that inherits from f.prototype . 相反,它具有一个新的运算符,例如, new f()会生成一个继承自f.prototype的新对象。

This indirection was intended to make the language seem more familiar to classically trained programmers, but failed to do that, as we can see from the very low opinion Java programmers have of JavaScript. 这种间接作用旨在使经过经典训练的程序员对这种语言更加熟悉,但是却没有做到这一点,正如我们从Java程序员对JavaScript的极低评价中可以看到的那样。 JavaScript's constructor pattern did not appeal to the classical crowd. JavaScript的构造器模式对古典人群没有吸引力。 It also obscured JavaScript's true prototypal nature. 它还掩盖了JavaScript的真正原型性质。 As a result, there are very few programmers who know how to use the language effectively. 结果,很少有知道如何有效使用该语言的程序员。

Fortunately, it is easy to create an operator that implements true prototypal inheritance. 幸运的是,创建实现真正原型继承的运算符很容易。 It is a standard feature in my toolkit, and I highly recommend it for yours. 这是我工具箱中的标准功能,我强烈建议您使用它。

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

The object function untangles JavaScript's constructor pattern, achieving true prototypal inheritance. 对象函数解开了JavaScript的构造函数模式,实现了真正的原型继承。 It takes an old object as a parameter and returns an empty new object that inherits from the old one. 它以旧对象作为参数,并返回一个从旧对象继承的空新对象。 If we attempt to obtain a member from the new object, and it lacks that key, then the old object will supply the member. 如果我们尝试从新对象中获取成员,但缺少该密钥,则旧对象将提供该成员。 Objects inherit from objects. 对象从对象继承。 What could be more object oriented than that? 还有什么比这更面向对象的呢?

So instead of creating classes, you make prototype objects, and then use the object function to make new instances. 因此,您无需创建类,而是创建原型对象,然后使用对象函数创建新实例。 Objects are mutable in JavaScript, so we can augment the new instances, giving them new fields and methods. 对象在JavaScript中是可变的,因此我们可以扩展新实例,为它们提供新的字段和方法。 These can then act as prototypes for even newer objects. 然后,它们可以充当甚至新对象的原型。 We don't need classes to make lots of similar objects. 我们不需要类来制作许多相似的对象。

For convenience, we can create functions which will call the object function for us, and provide other customizations such as augmenting the new objects with privileged functions. 为方便起见,我们可以创建将为我们调用对象函数的函数,并提供其他自定义功能,例如使用特权函数扩展新对象。 I sometimes call these maker functions. 我有时称这些制造商功能。 If we have a maker function that calls another maker function instead of calling the object function, then we have a parasitic inheritance pattern. 如果我们有一个生成器函数调用另一个生成器函数而不是调用对象函数,那么我们将具有寄生继承模式。

I have found that by using these tools, coupled with JavaScript's lambdas and object quasi-literals, I can write well-structured programs that are large, complex, and efficient. 我发现通过使用这些工具,再结合JavaScript的lambda和对象准文字,我可以编写结构合理的程序,这些程序既大型,复杂又高效。 The classical object model is by far the most popular today, but I think that the prototypal object model is more capable and offers more expressive power. 迄今为止,经典的对象模型是最受欢迎的,但是我认为原型对象模型更强大,并且提供了更多的表达能力。

It sounds like you just want to add to the prototype of car? 听起来您只是想添加到汽车原型中? Or do you want to add it to the prototype of everything you create (ill-advised)? 还是要将其添加到您创建的所有内容的原型中(不建议使用)?

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

var lamborghini = new car('red');

lamborghini.logDependencies(); // whatever 

Here's how you get a decent JavaScript developer angry: 这是使生气的JavaScript开发人员生气的方法:

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

var anything = new Object();

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

To clarify, the reason that the above is bad is explained in the article you posted: 要澄清的是,您发布的文章中解释了上述问题的原因:

The problem with the object function is that it is global, and globals are clearly problematic. 对象函数的问题在于它是全局的,而全局显然是有问题的。 The problem with Object.prototype.[someMethod] is that it trips up incompetent programs, and it can produce unexpected results when [someMethod] is overridden. Object.prototype。[someMethod]的问题在于,它会触发不合格的程序,并且当[someMethod]被覆盖时,它可能会产生意外的结果。

Having read your comments, it sounds to me as if you are after a magic wand of sorts. 阅读了您的评论后,对我来说听起来好像您是在追逐魔杖。 Perhaps you are coming from a Java world? 也许您来自Java世界? Or an Actionscript 3 world? 还是Actionscript 3世界? Where types are stronger, and inheritance is classical. 类型更强,继承是经典。 JavaScript is a pretty malleable language, and we've all managed to squeeze aspects of other languages out of it in some-form-or-other. JavaScript是一种非常具有延展性的语言,我们所有人都设法以某种形式将其他语言的各个方面挤出来。 But if what you're asking JavaScript to do is to enforce some sort of class-based inheritance system without you calling a few methods and declaring a few variables here-and-there, then you're in for disappointment. 但是,如果您要JavaScript执行的是实施某种基于类的继承系统而又不调用一些方法并且不需声明一些变量的情况,那么您将感到失望。

I suggest you read Douglas Crockford's other article , in which he explains how useful JavaScript's prototypal system is - and hints at how to leverage classical inheritence-like features. 我建议您阅读Douglas Crockford的一篇文章 ,其中他解释了JavaScript原型系统的实用性,并暗示了如何利用类似经典继承的功能。

If you want something along the lines of inheritance where car has all the functions that parent has prototyped, then you can use: 如果您想要继承car拥有parent原型化的所有功能的继承路线,则可以使用:

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

Basically, Object.create(obj) returns a new object whose prototype is set to obj . 基本上, Object.create(obj)返回其原型设置为obj的新对象。 All instances of car had their prototype set to car.prototype . car所有实例的原型都设置为car.prototype Thus they will have access to parent 's functions via the prototype chain. 因此,他们将可以通过原型链访问parent的功能。

You could always use mixins for sharing functionality. 您总是可以使用mixin共享功能。 For example: 例如:

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);
    }
}());

You use it as follows: 您可以如下使用它:

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

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

mixinLogger(Car.prototype);

The advantage of using mixins is that they are composable. 使用mixin的优点在于它们是可组合的。 For example if you have two mixins ( mixinA and mixinB ) then you can chain them as follows: 例如,如果您有两个mixin( mixinAmixinB ),则可以按以下方式链接它们:

mixinA(mixinB(Something.prototype));

You could even create a new mixin which is composition of the two: 您甚至可以创建一个新的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);

In fact you could compose as many mixins as you wish, to create new mixins. 实际上,您可以根据需要组成任意数量的mixin,以创建新的mixin。

If you want to learn more then you should read the blog post " A fresh look at JavaScript Mixins ". 如果您想了解更多,那么您应该阅读博客文章“ JavaScript Mixins的新外观 ”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM