Javascript 原型继承?

发布于 2024-07-11 09:31:25 字数 1078 浏览 3 评论 0原文

为了更好地理解它,我在 js 中做了一些继承,我发现了一些让我困惑的东西。

我知道,当您使用 new 关键字调用“构造函数”时,您会得到一个引用该函数原型的新对象。

我还知道,为了进行原型继承,您必须将构造函数的原型替换为您想要成为“超类”的对象的实例。

所以我做了这个愚蠢的例子来尝试这些概念:(

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!

这是在Firebug的控制台中完成的)

1)为什么如果所有新对象都包含对创建者函数原型的引用,fido.prototype是未定义的?

2) 是否继承链[obj] -> [构造函数]-> [prototype] 而不是 [obj] -> [原型] ?

3)我们的对象(fido)的“prototype”属性是否被检查过? 如果是这样...为什么'deathBite'未定义(在最后一部分)?

I'been doing some inheritance in js in order to understand it better, and I found something that confuses me.

I know that when you call an 'constructor function' with the new keyword, you get a new object with a reference to that function's prototype.

I also know that in order to make prototypal inheritance you must replace the prototype of the constructor function with an instance of the object you want to be the 'superclass'.

So I did this silly example to try these concepts:

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!

(This was done in Firebug's console)

1) Why if all new objects contain a reference to the creator function's prototype, fido.prototype is undefined?

2) Is the inheritance chain [obj] -> [constructor] -> [prototype] instead of [obj] -> [prototype] ?

3) is the 'prototype' property of our object (fido) ever checked? if so... why is 'deathBite' undefined (in the last part)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

记忆消瘦 2024-07-18 09:31:25

1) 为什么如果所有新对象都包含
引用创建者函数的
原型,fido.prototype 是
未定义?

所有新对象都保留对其构造函数在构造时存在的原型的引用。 然而,用于存储此引用的属性名称不是原型,因为它位于构造函数本身。 某些 Javascript 实现确实允许通过某些属性名称(如 __proto__)访问此“隐藏”属性,而其他实现则不允许(例如 Microsoft)。

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

这提醒“第一”而不是第二。 如果继承链通过构造函数,我们会看到“Second”。 当构造一个对象时,Functions 原型属性中保存的当前引用将转移到该对象对其原型的隐藏引用。

3) 是我们的“原型”属性
对象(fido)检查过吗? 如果是这样...
为什么'deathBite'未定义(在
最后一部分)?

为对象(函数除外)分配一个名为 prototype 的属性没有特殊含义,如前所述,对象不会通过这样的属性名称维护对其原型的引用。

1) Why if all new objects contain a
reference to the creator function's
prototype, fido.prototype is
undefined?

All new objects do hold a reference to the prototype that was present on their constructor at the time of construction. However the property name used to store this reference is not prototype as it is on the constructor function itself. Some Javascript implementations do allow access to this 'hidden' property via some property name like __proto__ where others do not (for example Microsofts).

2) Is the inheritance chain [obj] ->
[constructor] -> [prototype] instead
of [obj] -> [prototype] ?

No. Take a look at this:-

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

This alerts "First" not Second. If the inheritance chain went via the constructor we would see "Second". When an object is constructed the current reference held in the Functions prototype property is transfered to the object hidden reference to its prototype.

3) is the 'prototype' property of our
object (fido) ever checked? if so...
why is 'deathBite' undefined (in the
last part)?

Assigning to an object (other than a Function) a property called prototype has no special meaning, as stated earlier an object does not maintain a reference to its prototype via such a property name.

千笙结 2024-07-18 09:31:25

一旦使用 new 实例化对象,就无法更改其原型。

在上面的示例中,类似这样的行

fido.prototype = new KillerDog();

只是在对象 fido 上创建一个名为 prototype 的新属性,并将该属性设置为新的 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 中的构造函数,其中构造函数是用 new 调用的函数

You cannot change an object's prototype once it's been instantiated with new.

In your example above, lines like

fido.prototype = new KillerDog();

simply creates a new attribute named prototype on the object fido, and sets that attribute to a new KillerDog object. It's no different than

fido.foo = new KillerDog();

As your code stands...

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

The special prototype behavior applies only to constructors in javascript, where constructors are functions that will be called with new.

书间行客 2024-07-18 09:31:25

用数字回答你的问题:

  1. 对象的原型属性不称为prototype。 标准使用[[prototype]]来指定它。 Firefox 以 __proto__ 的名义公开此属性。
  2. 继承链是[obj][prototype object]。 您最初的假设 ([obj][constructor][prototype]) 是不正确的,您可以通过修改 轻松反驳它constructor 和/或 constructor.prototype,并检查可以在 [obj] 上调用哪些方法 - 您会发现这些修改不会改变任何内容。
  3. 对象上的 prototype 属性不会被检查和使用。 您可以将其设置为您喜欢的任何值。 JavaScript 仅在对象构造期间在函数对象上使用它。

为了演示#3,这里是来自 Dojo 的代码:

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 调用函数之前直接赋值的,之后它会被更改,不会影响任何创建的对象。

您可以在我对 [Prototype 之间的关系]] 和 JavaScript 中的原型

Answer by numbers to your questions:

  1. Object's prototype property is not called prototype. The standard uses [[prototype]] to designate it. Firefox makes this property public under the name of __proto__.
  2. The inheritance chain is [obj][prototype object]. Your original assumption ([obj][constructor][prototype]) is incorrect and you can easily disprove it by modifying constructor and/or constructor.prototype, and checking what methods can be called on your [obj] — you will discover that these modifications do not change anything.
  3. prototype property on objects are not checked and not used. You can set it to whatever you like. JavaScript uses it on function objects only during the object construction.

To demonstrate the #3 here is the code from Dojo:

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

As you can see it takes advantage of the fact that prototype is used only in one place by reusing the same function TMP for all delegated objects with different prototypes. In fact prototype is assigned directly before invoking the function with new, and it will be changed after that not affecting any created objects.

You can find the object created sequence in my answer to Relation between [[Prototype]] and prototype in JavaScript.

吝吻 2024-07-18 09:31:25

我知道这个问题已经得到解答,但是,有更好的方法来进行继承。 仅仅为了继承的目的而调用构造函数是不可取的。 不良影响之一是。

function Base() {this.a = "A"}
function Child() {this.b = "B"};

Child.prototype = new Base();

现在,您已将属性“a”添加到了 Child 的原型中,但您并不打算这样做。

这是正确的方法(我没有发明这个,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

I know it's already been answered but, there's a better way to do inheritance. Calling a constructor just for the purpose of inheritance is not desirable. One of the undesired effects is.

function Base() {this.a = "A"}
function Child() {this.b = "B"};

Child.prototype = new Base();

Now You've added property "a" to the prototype of Child that you didn't intend to.

Here's the right way (I didn't invent this, Ext-JS and other libs use this)

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

An even easier way is to add a third parameter to extend where you specify the method of the derived class so that you don't have to call extend and then add methods to the prototype

extend(BaseCtor, DerivedCtor, {
  getB: function() {return this.b}
});

Then there are many other things you could do for syntactic sugar.

Blogged about it: http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html

非要怀念 2024-07-18 09:31:25

值得注意的是,在 ECMAScript 5(即 JavaScript 语言的最新版本)中,您可以通过 Object.getPrototypeOf

Object.getPrototypeOf(fido) === Dog.prototype

Worth noting that in ECMAScript 5 (i.e. the latest version of the JavaScript language) you can get access to the internal [[Prototype]] property of an instance via Object.getPrototypeOf:

Object.getPrototypeOf(fido) === Dog.prototype
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文