[英]javascript prototypical inheritance confused
given the standard way of achieving inheritance like this 给出这样实现继承的标准方法
function BaseClass() {
}
function SubClass() {
BaseClass.call(this);
}
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
why is necesary to do 为什么需要这样做
SubClass.prototype = Object.create(BaseClass.prototype);
and end up with something like 并最终得到类似的东西
function F(){}
F.prototype = BaseClass.prototype;
SubClass.prototype = new F();
instead of just doing 而不只是做
Subclass.prototype = BaseClass.prototype;
Assigning values to things in JavaScript really just copies a reference (unless working with primitive types). 在JavaScript中为事物赋值实际上只是复制引用 (除非使用基本类型)。 So when you do this:
所以当你这样做时:
Subclass.prototype = BaseClass.prototype;
What you're really doing is assigning the prototype of SubClass
to the same location in memory as the prototype of BaseClass
, therefore any prototype related changes you make to SubClass
will also affect BaseClass
. 你真正在做的是将
SubClass
的原型分配到内存中与BaseClass
原型相同的位置,因此你对SubClass
所做的任何与原型相关的更改也会影响BaseClass
。 Here's a little example: 这是一个小例子:
function BaseClass() {
}
function SubClass() {
BaseClass.call(this);
}
SubClass.prototype = BaseClass.prototype;
SubClass.prototype.constructor = SubClass;
SubClass.prototype.subClassFunction = function(){
console.log("Added this to SubClass");
}
var baseObj = new BaseClass();
baseObj.subClassFunction(); // => "Added this to SubClass"
That's why you want to use 这就是你想要使用的原因
SubClass.prototype = Object.create(BaseClass.prototype);
because it will create a new and unique object with the specified prototype instead. 因为它将使用指定的原型创建一个新的 唯一对象。
You can read more about how this function works here . 您可以在此处详细了解此功能的工作原理。
Say BaseClass
has a method toString
: Say
BaseClass
有一个toString
方法:
BaseClass.prototype.toString = function() {
return 'foo'
}
But you redefine the toString
method in SubClass
: 但是你在
SubClass
重新定义了toString
方法:
SubClass.prototype.toString = function() {
return 'bar'
}
You'll expect: 你会期望:
var b = new BaseClass(), s = new SubClass()
b.toString() //=> 'foo'
s.toString() //=> 'bar'
But if you use assignment to create inheritance what you will get is: 但是如果你使用赋值创建继承,你会得到的是:
var b = new BaseClass(), s = new SubClass()
b.toString() //=> 'bar'
s.toString() //=> 'bar'
Because BaseClass.prototype
and SubClass.prototype
now reference the same object 因为
BaseClass.prototype
和SubClass.prototype
现在引用相同的对象
The syntax of JavaScript can be somewhat confusing. JavaScript的语法可能有点令人困惑。 In JS, there isn't class inheritance but instance-based inheritance.
在JS中,没有类继承,而是基于实例的继承。 An instance's parent is also called its prototype.
实例的父级也称为其原型。
When you write instance.something
or instance['something']
, the JS engine looks at the instance to see if it has a member called something
. 当你编写
instance.something
或instance['something']
,JS引擎会查看实例以查看它是否有一个名为something
的成员。 If it doesn't, then it looks at the instance's prototype. 如果没有,那么它会查看实例的原型。 If that object doesn't have the member
something
, it looks at the prototype's prototype, again and again until it finds the property or reaches an instance which inherits from null
. 如果该对象没有该成员的
something
,它会一次又一次地查看原型的原型,直到它找到该属性或者到达一个继承自null
的实例。 In that case it will simply return undefined
. 在这种情况下,它将简单地返回
undefined
。
Functions have a special property called prototype
which is something else. 函数有一个叫做
prototype
的特殊属性,这是另一回事。 The function's .prototype
is a simple object that has a constructor
property which refers back to the function itself. 函数的
.prototype
是一个简单的对象,它有一个constructor
属性,它返回函数本身。 When you create an object with the new
keyword, that object's prototype will be set to the function's .prototype
property. 使用
new
关键字创建对象时,该对象的原型将设置为函数的.prototype
属性。 This is where the confusion comes from: the .prototype
property of a constructor can be seen as the default prototype of all instances made with said constructor. 这就是混淆的地方:构造函数的
.prototype
属性可以看作是使用所述构造函数创建的所有实例的默认原型。
So when you add methods to a class by writing something like this: 因此,当您通过编写以下内容向类添加方法时:
MyClass.prototype.foo = function() {
alert('foo');
};
...you're actually storing the function in the prototype of all MyClass instances. ...实际上,您正在将函数存储在所有MyClass实例的原型中。 When the JS engine looks at the instances of MyClass, it will look for the
foo
member which it won't find. 当JS引擎查看MyClass的实例时,它将查找它找不到的
foo
成员。 Then it will look at the instance's prototype which happens to be set to MyClass.prototype
and it will find the foo
member and fetch it. 然后它将查看实例的原型,该原型碰巧被设置为
MyClass.prototype
,它将找到foo
成员并获取它。
It's important to make the difference between an instance's prototype and a function's .prototype
, but most people don't realize it. 重要的是在实例的原型和函数的
.prototype
之间做出区分,但是大多数人都没有意识到这一点。 When they speak of a class's prototype, they're talking about MyClass.prototype
. 当他们谈到一个类的原型时,他们谈论的是
MyClass.prototype
。 The instance prototype is accessible via __proto__
in many browsers, but that's not a standard feature of JavaScript and shouldn't be used in your code. 在许多浏览器中,可以通过
__proto__
访问实例原型,但这不是JavaScript的标准功能,不应在代码中使用。
Now let's look at the code you're using to simulate class inheritance. 现在让我们看看你用来模拟类继承的代码。
SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;
Object.create(parent)
can be seen as a function that does this: Object.create(parent)
可以看作是执行此操作的函数:
return {
__proto__ : parent
};
In other words, it creates a blank Object whose prototype is the passed object. 换句话说,它创建一个空白Object,其原型是传递的对象。 Since all SubClass instances will inherit from
Subclass.prototype
, replacing SubClass.prototype
with an object that inherits from BaseClass.prototype
makes sure all SubClass instances also inherit from BaseClass. 由于所有SubClass实例都将继承自
Subclass.prototype
,因此将SubClass.prototype
替换为继承自BaseClass.prototype
的对象可确保所有SubClass实例也从BaseClass继承。
However, as I said earlier, the default .prototype
attribute of a function is an empty object whose .constructor
is set to the function itself. 但是,正如我之前所说,函数的默认
.prototype
属性是一个空对象,其.constructor
设置为函数本身。 So by manually setting the .constructor
again, we're perfectly mimicking default prototype behavior. 因此,通过再次手动设置
.constructor
,我们完全模仿默认的原型行为。 If we don't do that, then instance.constructor
will return the first defined .constructor
property down the prototype chain, which will be BaseClass
. 如果我们不这样做,那么
instance.constructor
将在原型链中返回第一个定义的.constructor
属性,它将是BaseClass
。 It doesn't really change anything in terms of behavior unless our code actually depends on the constructor
property, but it's safer to have it. 除非我们的代码实际上依赖于
constructor
属性,否则它在行为方面并没有真正改变任何东西,但它更安全。
As a final note, like others mentioned before I could finally post this answer, you can't just do SubClass.prototype = BaseClass.prototype;
最后一点,就像我之前提到的那样,我最终可以发布这个答案,你不能只做
SubClass.prototype = BaseClass.prototype;
because then you wouldn't be able to add methods to the SubClass without adding them to the BaseClass. 因为那样你就无法在不将它们添加到BaseClass的情况下向SubClass添加方法。
Inheritance, the __proto__ : 继承,__ proto__ :
When an object SubClass
inherits from another object BaseClass
, in JavaScript that means that there is a special property SubClass.__proto__ = BaseClass
. 当一个对象
SubClass
继承自另一个对象BaseClass
,在JavaScript中意味着有一个特殊属性SubClass.__proto__ = BaseClass
。
Code : 代码:
function BaseClass() {
}
function SubClass() {
}
var BaseClass = new BaseClass();
var SubClass = new SubClass();
BaseClass.a = 5;
SubClass.b = 10;
SubClass.__proto__ = BaseClass;
console.log(SubClass);
Output : 输出:
Here, BaseClass
is inherited by SubClass
and BaseClass variable is accessable through the SubClass
. 这里,
BaseClass
由SubClass
继承, BaseClass variable is accessable through the SubClass
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.