Javascript原型的继承?
-
23-08-2019 - |
题
我'been做一些继承js为了更好地理解它,并且我发现的东西,混淆了我。
我知道,当你呼叫一个'constructor function'与新的关键词,你会得到一个新的对象,参考这一职能的原型。
我也知道,为了使继承原型必须更换所原型的构造函数的一个实例您想要的对象是'超'.
所以我做了这个愚蠢的示例,以试试这些概念:
function Animal(){}
function Dog(){}
Animal.prototype.run = function(){alert("running...")};
Dog.prototype = new Animal();
Dog.prototype.bark = function(){alert("arf!")};
var fido = new Dog();
fido.bark() //ok
fido.run() //ok
console.log(Dog.prototype) // its an 'Object'
console.log(fido.prototype) // UNDEFINED
console.log(fido.constructor.prototype == Dog.prototype) //this is true
function KillerDog(){};
KillerDog.prototype.deathBite = function(){alert("AAARFFF! *bite*")}
fido.prototype = new KillerDog();
console.log(fido.prototype) // no longer UNDEFINED
fido.deathBite(); // but this doesn't work!
(这样做的目的是在萤火虫的控制台)
1)为什么如果所有新的对象包含一个参考的创造者功能的原型,菲多。原型是不确定?
2)是继承链[obj]->[构造]->[原型]而[obj]->[原型]?
3)的'原'财产的对象(菲)过检查?如果是这样...为什么是'deathBite'定义(在最后一部分)?
解决方案
1)为什么如果所有新对象包含 参考生成器功能的 原型,fido.prototype是 未定义?
所有新对象做容纳于存在于在施工时其构造原型的参考。但是用于存储该参考属性名称不prototype
,因为它是在构造函数本身。一些JavaScript实现都允许通过一些属性名访问这个“隐藏”属性像__proto__
,别人不(例如微软)。
2)是对继承链[OBJ] - > [构造] - > [原型]代替 的[OBJ] - > [原型]
没有。在此请看: -
function Base() {}
Base.prototype.doThis = function() { alert("First"); }
function Base2() {}
Base2.prototype.doThis = function() { alert("Second"); }
function Derived() {}
Derived.prototype = new Base()
var x = new Derived()
Derived.prototype = new Base2()
x.doThis();
此提醒“第一”未二。如果继承链通过构造函数去我们会看到“第二”。当构造的对象在功能原型属性保持的电流基准转移到该对象隐藏参考其原型。
3)的“原型”属性提供了 对象(菲)检查过?如果是这样的话... 为什么是“deathBite”未定义(在 最后部分)?
分配到一个对象(除了其它功能)被称为prototype
属性没有特殊的意义,如前面所述的对象不经由这样的属性名保持到它的原型的引用。
其他提示
一旦它被实例化new
你不能改变一个对象的原型。
在你上面的例子一样,线
fido.prototype = new KillerDog();
简单地创建一个名为上的对象prototype
fido
新的属性,并将该属性到一个新的KillerDog
对象。这是不超过
fido.foo = new KillerDog();
由于你的代码代表...
// Doesn't work because objects can't be changed via their constructors
fido.deathBite();
// Does work, because objects can be changed dynamically,
// and Javascript won't complain when you use prototype
//as an object attribute name
fido.prototype.deathBite();
在特殊prototype
行为仅适用于在JavaScript构造,其中构造是function
s将与new
被调用。
按数字回答您的问题:
- 对象的原型属性没有被调用
prototype
. 。该标准使用[[prototype]]
来指定它。Firefox 以 __proto__ 的名义公开此属性。 - 继承链是
[obj]
⇒[prototype object]
. 。你原来的假设([obj]
⇒[constructor]
⇒[prototype]
)是不正确的,你可以通过修改轻松反驳它constructor
和/或constructor.prototype
, ,并检查可以在您的[obj]
——你会发现这些修改并没有改变任何东西。 prototype
不检查也不使用对象的属性。您可以将其设置为您喜欢的任何值。JavaScript 仅在对象构造期间在函数对象上使用它。
为了演示#3,这里的代码来自 道场:
dojo.delegate = dojo._delegate = (function(){
// boodman/crockford delegation w/ cornford optimization
function TMP(){}
return function(obj, props){
TMP.prototype = obj;
var tmp = new TMP();
if(props){
dojo._mixin(tmp, props);
}
return tmp; // Object
}
})();
正如你所看到的,它利用了以下事实: prototype
通过重用相同的函数仅在一处使用 TMP
对于具有不同原型的所有委托对象。实际上 prototype
在调用函数之前直接赋值 new
, ,之后会发生更改,不会影响任何创建的对象。
您可以在我的回答中找到对象创建的序列 JavaScript 中 [[Prototype]] 与原型的关系.
我知道它已经有了答案,但是,有一个更好的办法做到继承。调用构造函数只为继承的目的是不可取的。一项所述的不期望的效果是
function Base() {this.a = "A"}
function Child() {this.b = "B"};
Child.prototype = new Base();
现在您已经添加的属性“A”到孩子的原型,你没有打算。
下面是正确的方式(我没有发明这个,EXT-JS和其他库使用)
// This is used to avoid calling a base class's constructor just to setup inheritance.
function SurrogateCtor() {}
/**
* Sets a contructor to inherit from another constructor
*/
function extend(BaseCtor, DerivedCtor) {
// Copy the prototype to the surrogate constructor
SurrogateCtor.prototype = BaseCtor.prototype;
// this sets up the inheritance chain
DerivedCtor.prototype = new SurrogateCtor();
// Fix the constructor property, otherwise it would point to the BaseCtor
DerivedCtor.prototype.constructor = DerivedCtor;
// Might as well add a property to the constructor to
// allow for simpler calling of base class's method
DerivedCtor.superclass = BaseCtor;
}
function Base() {
this.a = "A";
}
Base.prototype.getA = function() {return this.a}
function Derived() {
Derived.superclass.call(this); // No need to reference the base class by name
this.b = "B";
}
extend(Base, Derived);
// Have to set methods on the prototype after the call to extend
// otherwise the prototype is overridden;
Derived.prototype.getB = function(){return this.b};
var obj = new Derived();
这是更简单的方法是增加一个第三参数,以延长在其中指定的派生类的方法,以便你不必调用延伸,然后添加方法原型不
extend(BaseCtor, DerivedCtor, {
getB: function() {return this.b}
});
然后还有很多其他的事情你可以为语法糖做的。
在博客它: HTTP:// JS -bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
值得注意的是,在写5(即最新版本的JavaScript语)你可以访问内部[[原型]]财产的一个实例通过 Object.getPrototypeOf
:
Object.getPrototypeOf(fido) === Dog.prototype