Confused about JavaScript prototypal inheritance

我是研究僧i 提交于 2019-12-03 00:46:57

Let say, Dog is a Mammal.

function Mammal() {
  this.milk = true;
};

function Dog() { this.bark = true; } Dog.prototype = new Mammal;

So prototype of Dog points to an object of Mammal. This Mammal object has a reference to its constructor so when Dog is new, JavaScript see that Dog prototype is a Mammal so Mammal's constructor is called to produce a valid Mammal object (another one) then make it a Dog object using Dog constructor.

From this, the constructor of Dog.prototype is a Mammal (a Mammal Object that has extra fields and functions added) BUT constructor of Dog is Dog. The inheritance exist because the an instance of Dog has a Mammal as a prototype; hence, Dog is a Mammal. When a method is called and JS cannot find it from Dog.prototype, JS look in Mammal.prototype (which is an Object that has extra fields and functions added).

Hope this helps.

The .constructor property honestly doesn't matter very much, and has very little to do with inheriting from other objects in JavaScript. It's just a convenient handle to an object's constructor.

For example, if you have an instance of something, and you'd like to create another instance of that thing, but you don't have a direct handle on its constructor, you could do something like this:

const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]

const car2 = new myCar.constructor();
console.log(car2.constructor); // [Function: Racecar]

It's important to understand that the .constructor property and the class of an object are not synonymous. As you may have already guessed, the .constructor property is dynamic, just like most other things in JavaScript, so it should not be used for anything like type checking.

It's also important to understand that the .constructor property does not mean that something is a subclass of something else. In fact, there is no reliable way to find out if something is a subclass of something else in JavaScript. Because it's a dynamic language, and because there are so many ways to inherit properties from other objects (including copying properties from other objects after instantiation), type-safe subclasses don't exist in JavaScript like they exist in other languages.

The best way to know if something is a compatible type is to feature-test properties. In other words, duck type.

The instanceof operator ignores the .constructor property. Instead, it checks whether or not the constructor's .prototype exists (with an identity check) in the prototype chain of the object.

With manual constructor functions, inheritance can confuse the .constructor property connection (making it refer to the wrong constructor). You can fix it by manually wiring up the connection. For example, the canonical way to do so in ES5 is this:

function Car () {}

console.log(Car.prototype.constructor); // Car

function Racecar () {}

Racecar.prototype = Object.create(Car.prototype);
// To preserve the same relationship we have with the Car
// constructor, we'll need to reassign the .prototype.constructor:
Racecar.prototype.constructor = Racecar;

var myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]

ES6 classes do this for you automatically:

// ES6
class Car {}
class Racecar extends Car {}

const myCar = new Racecar();
console.log(myCar.constructor); // [Function: Racecar]

That said, I'm not a big fan of either constructor functions or ES6 classes, and I generally have little use for the .constructor property. Why? Because factory functions are far more flexible, far more powerful, and they don't have the pitfalls related to constructor functions and class inheritance. See "Factory Functions vs Constructor Functions vs Classes".

Don't worry about the constructor property - it is irrelevant. Skip those sentences and you might follow it better.

If you are still unsure of your understanding, google for __proto__ - the internal prototype reference on JS objects. It is even exposed to scripts on Firefox and Safari.

A good reference is https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/The_Employee_Example/Object_Properties/Inheriting_Properties

If you have an object obj, it's prototype is obj.prototype and constructor property referring to obj's constructor is obj.prototype.constructor.

For the object obj.prototype the situation is the same. Let's say proto = obj.prototype, then the reference to the constructor of proto would be found at proto.prototype.constructor.

This is the same as obj.prototype.prototype.constructor, so there is no conflict with obj.prototype.constructor.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!