AFAIK,JS通过将原型链分配给新创建的对象来提供继承性。所以,下面的代码对我来说似乎是正确的方法:
function Animal(name){
this.name = name;
}
Animal.prototype.getName = function(){return this.name;};
function Cat(){
Animal.apply(this, arguments);
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.sayHi = function(){return 'Hi, my name is '+this.name+', and I am a "'+this.constructor.name+'" instance';};
这实际上是对的吗?并且,我已经读过,变异对象的原型是一个缓慢的阻止操作,影响所有后来的调用。但在这里,我们只是改变了Animal.prototype
和Cat.prototype
。那么,那很糟糕吗?如果是我们如何处理它?或者我误解了原型变异警告的一些事情?如果是这样,它究竟意味着什么?
答案 0 :(得分:1)
你走在正确的轨道上。你不想改变Animal
的原型,因为这打破了继承的概念。正如评论中所提到的,使用Object.create()
是将属性和方法从一个对象继承到另一个对象的正确方法。使用您的示例,一个简单的原型继承示例就是这样实现的:
function Animal(name) {
this.name = name;
}
Animal.prototype = {
getName: function() {
return this.name;
}
};
function Cat(name, color) {
Animal.call(this, name);
this.color = color;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.getColor = function() {
return this.color;
};
var animal = new Animal('Bob');
var cat = new Cat('Tabby', 'black');
console.log(cat.getName());
console.log(cat.getColor());
console.log(animal.getName());
console.log(animal.getColor()); // throws an error
答案 1 :(得分:1)
这实际上是否正确?
因为它不包含任何可能被认为是不良做法的东西,是的。在结果方面是否正确无法确定。
并且,我已经读过,变异对象的原型是一个缓慢的阻止操作,
我不知道这意味着什么。但是,修改你不拥有的对象并不是一种好的做法,所以不要搞乱内置对象或宿主对象(有很多文章说明为什么没有,例如What's wrong with extending the DOM和Extending builtin natives. Evil or not? )。
影响所有后来的调用。
修改原型可能会影响所有将其作为[[Prototype]]
的对象,这就是原型继承的重点。
但是我们刚刚改变了Animal.prototype和Cat.prototype。那么,那是不是很糟糕?
本身,没有。如果它达到你需要的结果,那就好了。您正在定义构造函数,原型属性和继承方案,因此这取决于您。可能有更高效或更容易维护的方案,但这是另一个主题。
复杂的继承方案在javascript中很少有用,只是没有多少要求它。大多数内置对象只有一个或两个级别的继承(例如,函数实例继承自Function.prototype和Object.prototype)。主机对象(例如DOM元素)可能具有更长的链,但这是为了方便而不是真正必要的(至少有一个非常流行的浏览器直到最近才实现主机对象的原型继承)。
答案 2 :(得分:0)
您在JavaScript中的继承相当复杂,您必须对原型对象有一个很好的理解。我建议您使用TypeScript的继承模式。您可以试试Playground
看看这个:
var extends = this.extends || function (class, parent) {
for (var property in parent) {
if (parent.hasOwnProperty(property)) {
class[property] = parent[property];
}
}
function newClass() {
this.constructor = class;
}
newClass.prototype = parent.prototype;
class.prototype = new newClass();
};
var Animal = (function () {
function Animal(name) {
this.name = name;
}
return Animal;
})();
var Cat = (function (_super) {
extends(Cat, _super);
function Cat(name) {
_super.call(this, name);
}
Cat.prototype.sayHi = function () {
return "Hello my name is:" + this.name;
};
return Cat;
})(Animal);
答案 3 :(得分:0)
您似乎将函数的prototype
属性与所有对象(包括函数)的内部[[proto]]
属性混合在一起。它们是两个不同的东西。
不鼓励改变对象的内部[[proto]]
属性。这可以通过setPrototypeOf
或__proto__
访问者完成,该访问者继承自Object.prototype
:
var a = {}; // `a` inherits directly from `Object.prototype`
var b = {}; // `b` inherits directly from `Object.prototype`
a.__proto__ = b; // `a` now inherits directly from `b`
// or
Object.setPrototypeOf(a, b); // `a` now inherits directly from `b`
这是不鼓励的,在创建对象后改变对象的内部[[proto]]
属性。但是,应该注意的是,在创建对象时,可以将任何对象指定为其内部[[proto]]
属性。
例如,许多JavaScript程序员希望创建从Function.prototype
以外的某个对象继承的函数。目前只能通过在创建函数后改变函数的内部[[proto]]
属性来实现。但是,in ES6 you will be able to assign the internal [[proto]]
property of an object when it is created(从而避免了改变对象的内部[[proto]]
属性的问题。)
例如,考虑一下这个错误的代码:
var callbackFunctionPrototype = {
describe: function () {
alert("This is a callback.");
}
};
var callback = function () {
alert("Hello World!");
};
callback.__proto__ = callbackFunctionPrototype; // mutating [[proto]]
callback.describe();
可以在ES6中重写如下:
var callbackFunctionPrototype = {
describe: function () {
alert("This is a callback.");
}
};
// assigning [[proto]] at the time of creation, no mutation
var callback = callbackFunctionPrototype <| function () {
alert("Hello World!");
};
callback.describe();
因此,改变对象的内部[[proto]]
属性(使用setPrototypeOf
或__proto__
访问器)是不好的。但是,修改函数的prototype
属性很好。
函数的prototype
属性(让我们调用函数F
)仅影响new F
创建的对象。例如:
var myPrototype = {
describe: function () {
alert("My own prototype.");
}
};
function F() {}
var a = new F; // inherits from the default `F.prototype`
alert(a.constructor === F); // true - inherited from `F.prototype`
F.prototype = myPrototype; // not mutating the `[[proto]]` of any object
var b = new F; // inherits from the new `F.prototype` (i.e. `myPrototype`)
b.describe();
要了解有关JavaScript继承的更多信息,请阅读以下问题的答案:
JavaScript inheritance and the constructor property
希望有所帮助。