JavaScript 基于原型的继承的好例子

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2064731/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 22:37:58  来源:igfitidea点击:

Good Example of JavaScript's Prototype-Based Inheritance

javascriptprototypal-inheritance

提问by Alex Reisner

I have been programming with OOP languages for over 10 years but I'm learning JavaScript now and it's the first time I've encountered prototype-based inheritance. I tend to learn fastest by studying good code. What's a well-written example of a JavaScript application (or library) that properly uses prototypal inheritance? And can you describe (briefly) how/where prototypal inheritance is used, so I know where to start reading?

我已经使用 OOP 语言编程超过 10 年,但我现在正在学习 JavaScript,这是我第一次遇到基于原型的继承。我倾向于通过学习好的代码来学得最快。正确使用原型继承的 JavaScript 应用程序(或库)编写良好的示例是什么?您能否(简要地)描述一下原型继承是如何/在何处使用的,以便我知道从哪里开始阅读?

采纳答案by Gregory Pakosz

Douglas Crockford has a nice page on JavaScript Prototypal Inheritance:

Douglas Crockford 在JavaScript Prototypal Inheritance上有一个不错的页面:

Five years ago I wrote Classical Inheritancein JavaScript. It showed that JavaScript is a class-free, prototypal language, and that it has sufficient expressive power to simulate a classical system. My programming style has evolved since then, as any good programmer's should. I have learned to fully embrace prototypalism, and have liberated myself from the confines of the classical model.

五年前,我用 JavaScript编写了Classical Inheritance。它表明 JavaScript 是一种无类的原型语言,并且它具有足够的表达能力来模拟经典系统。从那时起,我的编程风格发生了变化,任何优秀的程序员都应该如此。我学会了完全接受原型,并将自己从经典模型的限制中解放出来。

Dean Edward's Base.js, Mootools's Classor John Resig's Simple Inheritanceworks are ways to do classical inheritancein JavaScript.

Dean Edward 的Base.jsMootools 的 ClassJohn Resig 的 Simple Inheritance作品是在 JavaScript 中进行经典继承的方法。

回答by Dynom

As mentioned, the movies by Douglas Crockford give a good explanation about the why and it covers the how. But to put it in a couple of lines of JavaScript:

如前所述,道格拉斯·克罗克福德 (Douglas Crockford) 的电影很好地解释了原因和方法。但是把它放在几行 JavaScript 中:

// Declaring our Animal object
var Animal = function () {

    this.name = 'unknown';

    this.getName = function () {
        return this.name;
    }

    return this;
};

// Declaring our Dog object
var Dog = function () {

    // A private variable here        
    var private = 42;

    // overriding the name
    this.name = "Bello";

    // Implementing ".bark()"
    this.bark = function () {
        return 'MEOW';
    }  

    return this;
};


// Dog extends animal
Dog.prototype = new Animal();

// -- Done declaring --

// Creating an instance of Dog.
var dog = new Dog();

// Proving our case
console.log(
    "Is dog an instance of Dog? ", dog instanceof Dog, "\n",
    "Is dog an instance of Animal? ", dog instanceof Animal, "\n",
    dog.bark() +"\n", // Should be: "MEOW"
    dog.getName() +"\n", // Should be: "Bello"
    dog.private +"\n" // Should be: 'undefined'
);

The problem with this approach however, is that it will re-create the object every time you create one. Another approach is to declare your objects on the prototype stack, like so:

然而,这种方法的问题在于,每次创建对象时它都会重新创建对象。另一种方法是在原型堆栈上声明您的对象,如下所示:

// Defining test one, prototypal
var testOne = function () {};
testOne.prototype = (function () {
    var me = {}, privateVariable = 42;
    me.someMethod = function () {
        return privateVariable;
    };

    me.publicVariable = "foo bar";
    me.anotherMethod = function () {
        return this.publicVariable;
    };

    return me;

}());


// Defining test two, function
var testTwo = ?function() {
    var me = {}, privateVariable = 42;
    me.someMethod = function () {
        return privateVariable;
    };

    me.publicVariable = "foo bar";
    me.anotherMethod = function () {
        return this.publicVariable;
    };

    return me;
};


// Proving that both techniques are functionally identical
var resultTestOne = new testOne(),
    resultTestTwo = new testTwo();

console.log(
    resultTestOne.someMethod(), // Should print 42
    resultTestOne.publicVariable // Should print "foo bar"
);

console.log(
    resultTestTwo.someMethod(), // Should print 42
    resultTestTwo.publicVariable // Should print "foo bar"
);



// Performance benchmark start
var stop, start, loopCount = 1000000;

// Running testOne
start = (new Date()).getTime(); 
for (var i = loopCount; i>0; i--) {
    new testOne();
}
stop = (new Date()).getTime();

console.log('Test one took: '+ Math.round(((stop/1000) - (start/1000))*1000) +' milliseconds');



// Running testTwo
start = (new Date()).getTime(); 
for (var i = loopCount; i>0; i--) {
    new testTwo();
}
stop = (new Date()).getTime();

console.log('Test two took: '+ Math.round(((stop/1000) - (start/1000))*1000) +' milliseconds');

There is a slight downside when it comes to introspection. Dumping testOne, will result in less useful information. Also the private property "privateVariable" in "testOne" is shared in all instances, als helpfully mentioned in the replies by shesek.

内省时有一个轻微的缺点。转储 testOne,将导致不太有用的信息。此外,“testOne”中的私有属性“privateVariable”在所有情况下都是共享的,shesek 的回复中也提到了这一点。

回答by Vlad Bezden

function Shape(x, y) {
    this.x = x;
    this.y = y;
}

// 1. Explicitly call base (Shape) constructor from subclass (Circle) constructor passing this as the explicit receiver
function Circle(x, y, r) {
    Shape.call(this, x, y);
    this.r = r;
}

// 2. Use Object.create to construct the subclass prototype object to avoid calling the base constructor
Circle.prototype = Object.create(Shape.prototype);

回答by Roland Bouman

I would take a look at YUI, and at Dean Edward's Baselibrary: http://dean.edwards.name/weblog/2006/03/base/

我会看看YUI和 Dean Edward 的Base图书馆:http: //dean.edwards.name/weblog/2006/03/base/

For YUI you can take a quick look at the lang module, esp. the YAHOO.lang.extendmethod. And then, you can browse the source of some widgets or utilities and see how they use that method.

对于 YUI,您可以快速查看lang 模块,尤其是。该YAHOO.lang.extend方法。然后,您可以浏览一些小部件或实用程序的来源,并了解它们如何使用该方法。

回答by Kevin Jones

There's also Microsoft's ASP.NETAjax library, http://www.asp.net/ajax/.

还有 Microsoft 的ASP.NETAjax 库,http://www.asp.net/ajax/

There are a lot of good MSDN articles around as well, including Create Advanced Web Applications With Object-Oriented Techniques.

还有很多很好的 MSDN 文章,包括使用面向对象技术创建高级 Web 应用程序

回答by supershnee

This is the clearest example I've found, from Mixu's Node book (http://book.mixu.net/node/ch6.html):

这是我找到的最清晰的例子,来自 Mixu 的 Node 书(http://book.mixu.net/node/ch6.html):

I favor composition over inheritance:

Composition - Functionality of an object is made up of an aggregate of different classes by containing instances of other objects. Inheritance - Functionality of an object is made up of it's own functionality plus functionality from its parent classes. If you must have inheritance, use plain old JS

If you must implement inheritance, at least avoid using yet another nonstandard implementation / magic function. Here is how you can implement a reasonable facsimile of inheritance in pure ES3 (as long as you follow the rule of never defining properties on prototypes):

function Animal(name) {
  this.name = name;
};
Animal.prototype.move = function(meters) {
  console.log(this.name+" moved "+meters+"m.");
};

function Snake() {
  Animal.apply(this, Array.prototype.slice.call(arguments));
};
Snake.prototype = new Animal();
Snake.prototype.move = function() {
  console.log("Slithering...");
  Animal.prototype.move.call(this, 5);
};

var sam = new Snake("Sammy the Python");
sam.move();

This is not the same thing as classical inheritance - but it is standard, understandable Javascript and has the functionality that people mostly seek: chainable constructors and the ability to call methods of the superclass.

我更喜欢组合而不是继承:

组合 - 对象的功能由包含其他对象实例的不同类的聚合组成。继承 - 对象的功能由它自己的功能加上来自其父类的功能组成。如果必须继承,请使用普通的旧 JS

如果你必须实现继承,至少避免使用另一个非标准的实现/魔法函数。以下是如何在纯 ES3 中实现合理的继承副本(只要您遵循永远不要在原型上定义属性的规则):

function Animal(name) {
  this.name = name;
};
Animal.prototype.move = function(meters) {
  console.log(this.name+" moved "+meters+"m.");
};

function Snake() {
  Animal.apply(this, Array.prototype.slice.call(arguments));
};
Snake.prototype = new Animal();
Snake.prototype.move = function() {
  console.log("Slithering...");
  Animal.prototype.move.call(this, 5);
};

var sam = new Snake("Sammy the Python");
sam.move();

这与经典继承不是一回事——但它是标准的、易于理解的 Javascript,并且具有人们主要寻求的功能:可链接的构造函数和调用超类方法的能力。

回答by Tomasz Durka

I suggest looking at PrototypeJS' Class.create:
Line 83 @ http://prototypejs.org/assets/2009/8/31/prototype.js

我建议查看 PrototypeJS 的 Class.create:
Line 83 @ http://prototypejs.org/assets/2009/8/31/prototype.js

回答by Chris S

The best examples I've seen are in Douglas Crockford's JavaScript: The Good Parts. It's definitely worth buying to help you get a balanced view on the language.

我见过的最好的例子是 Douglas Crockford 的JavaScript: The Good Parts。绝对值得购买,以帮助您对语言有一个平衡的看法。

Douglas Crockfordis responsible for the JSON format and works at Yahoo as a JavaScript guru.

Douglas Crockford负责 JSON 格式,并作为 JavaScript 专家在雅虎工作。

回答by Chris S

Adding an example of Prototype based inheritance in Javascript.

在 Javascript 中添加基于原型的继承示例。

// Animal Class
function Animal (name, energy) {
  this.name = name;
  this.energy = energy;
}

Animal.prototype.eat = function (amount) {
  console.log(this.name, "eating. Energy level: ", this.energy);
  this.energy += amount;
  console.log(this.name, "completed eating. Energy level: ", this.energy);
}

Animal.prototype.sleep = function (length) {
  console.log(this.name, "sleeping. Energy level: ", this.energy);
  this.energy -= 1;
  console.log(this.name, "completed sleeping. Energy level: ", this.energy);
}

Animal.prototype.play = function (length) {
  console.log(this.name, " playing. Energy level: ", this.energy);
  this.energy -= length;
  console.log(this.name, "completed playing. Energy level: ", this.energy);
}

// Dog Class
function Dog (name, energy, breed) {
  Animal.call(this, name, energy);
  this.breed = breed;
}

Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

Dog.prototype.bark = function () {
  console.log(this.name, "barking. Energy level: ", this.energy);
  this.energy -= 1;
  console.log(this.name, "done barking. Energy level: ", this.energy);
}

Dog.prototype.showBreed = function () {
  console.log(this.name,"'s breed is ", this.breed);
}

// Cat Class
function Cat (name, energy, male) {
  Animal.call(this, name, energy);
  this.male = male;
}

Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;

Cat.prototype.meow = function () {
  console.log(this.name, "meowing. Energy level: ", this.energy);
  this.energy -= 1;
  console.log(this.name, "done meowing. Energy level: ", this.energy);
}

Cat.prototype.showGender = function () {
  if (this.male) {
    console.log(this.name, "is male.");
  } else {
    console.log(this.name, "is female.");
  }
}

// Instances
const charlie = new Dog("Charlie", 10, "Labrador");
charlie.bark();
charlie.showBreed();

const penny = new Cat("Penny", 8, false);
penny.meow();
penny.showGender();

ES6 uses far easier implementation of inheritance witn the use of constructor and super keywords.

ES6 通过使用构造函数和 super 关键字使用更简单的继承实现。

回答by fuweichin

There is a snippet JavaScript Prototype-based Inheritancewith ECMAScript version specific implementations. It will automatically choose which to use between ES6, ES5 and ES3 implementations according to current runtime.

有一个片段JavaScript Prototype-based Inheritancewith ECMAScript version specific implementations。它将根据当前运行时自动选择在 ES6、ES5 和 ES3 实现之间使用哪个。