对 JavaScript 原型继承感到困惑

发布于 2024-08-19 19:05:46 字数 714 浏览 3 评论 0原文

在《JavaScript权威指南第5版》一书中,第9.2节原型和继承,我发现了以下文字:

在上一节中,我展示了 new 运算符创建一个新的、空的 对象,然后调用构造函数 函数作为该对象的方法。 这不是完整的故事 然而。创建空后 对象,new 设置该对象的原型 目的。对象的原型是 原型属性的值 它的构造函数。全部 函数具有原型属性 这是自动创建的并且 当函数被初始化时 定义的。 的初始值 原型属性是一个具有 单一财产。此属性是 命名构造函数并引用回 构造函数 原型已关联。(您 可能还记得构造函数属性 来自第 7 章;这就是为什么每个 对象有一个构造函数属性。) 您添加到此的任何属性 原型对象将显示为 初始化对象的属性 构造函数。

现在,如果这是真的,那么原型继承怎么可能存在呢?我的意思是,假设构造函数的原型对象最初有一个构造函数属性。因为原型对象本身就是一个对象,所以我们经常使用prototype_object.constructor来确定它的构造函数。但现在 prototype_object 本身已经有一个 constructor 属性,并且它指向与原型关联的构造函数。在这种情况下,继承怎么可能存在呢?

In the book "JavaScript the definitive guide 5 edition", section 9.2 Prototypes and Inheritance, I find the following words:

In the previous section, I showed that
the new operator creates a new, empty
object and then invokes a constructor
function as a method of that object.
This is not the complete story,
however. After creating the empty
object, new sets the prototype of that
object. The prototype of an object is
the value of the prototype property of
its constructor function. All
functions have a prototype property
that is automatically created and
initialized when the function is
defined. The initial value of the
prototype property is an object with a
single property. This property is
named constructor and refers back to
the constructor function with which
the prototype is associated.
(You
may recall the constructor property
from Chapter 7 ; this is why every
object has a constructor property.)
Any properties you add to this
prototype object will appear to be
properties of objects initialized by
the constructor.

Now, if that is true, how could prototypal inheritance exists? I mean, let's say the prototype object of a constructor function has a constructor property initially. Because the prototype object itself is an object, to determine its constructor we often use prototype_object.constructor. But now the prototype_object already has a constructor property itself, and it points to the constructor function with which the prototype is associated. In this situation how can inheritance exists?

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

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

发布评论

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

评论(4

日裸衫吸 2024-08-26 19:05:46

老实说,.constructor 属性并不重要,并且与从 JavaScript 中的其他对象继承关系不大。它只是对象构造函数的一个方便的句柄。

例如,如果您有某个事物的实例,并且想要创建该事物的另一个实例,但您没有对其构造函数的直接句柄,则可以执行如下操作:

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

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

重要的是要了解.constructor 属性和对象的类不是同义词。正如您可能已经猜到的,.constructor 属性是动态的,就像 JavaScript 中的大多数其他内容一样,因此它不应该用于类型检查之类的任何内容。

同样重要的是要理解 .constructor 属性并不意味着某个东西是其他东西的子类。事实上,在 JavaScript 中没有可靠的方法来确定某个东西是否是其他东西的子类。因为它是一种动态语言,并且因为有很多方法可以从其他对象继承属性(包括实例化后从其他对象复制属性),所以类型安全子类在 JavaScript 中并不像在其他语言中那样存在。

了解某物是否兼容类型的最佳方法是对属性进行功能测试。换句话说,鸭子型。

instanceof 运算符忽略 .constructor 属性。相反,它检查构造函数的 .prototype 是否存在于对象的原型链中(通过身份检查)。

对于手动构造函数,继承可能会混淆 .constructor 属性连接(使其引用错误的构造函数)。您可以通过手动连接连接来修复它。例如,在 ES5 中执行此操作的规范方法是这样的:

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 类会自动为您执行此操作:

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

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

也就是说,我不太喜欢构造函数或 ES6 类,而且我通常很少使用 .constructor 属性。为什么?因为工厂函数更加灵活,更加强大,并且它们没有与构造函数和类继承相关的陷阱。请参阅“工厂函数与构造函数与类” ”

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".

小忆控 2024-08-26 19:05:46

假设,狗是哺乳动物。

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

函数狗() { this.bark = true; } Dog.prototype = 新的哺乳动物;

所以 Dog 的原型指向 Mammal 的一个对象。这个 Mammal 对象有一个对其构造函数的引用,因此当 Dog 是新的时,JavaScript 会看到 Dog 原型是一个 Mammal,因此调用 Mammal 的构造函数来生成一个有效的 Mammal 对象(另一个),然后使用 Dog 构造函数将其设为 Dog 对象。

由此可见,Dog.prototype 的构造函数是一个 Mammal(添加了额外字段和函数的哺乳动物对象),但 Dog 的构造函数是。继承的存在是因为 Dog 的实例有一个 Mammal 作为原型;因此,狗是哺乳动物。当调用一个方法并且 JS 无法从 Dog.prototype 中找到它时,JS 会查找 Mammal.prototype (这是一个添加了额外字段和函数的对象)。

希望这有帮助。

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.

瑶笙 2024-08-26 19:05:46

不用担心构造函数属性——它是无关紧要的。
跳过这些句子,你可能会更好地理解它。

如果您仍然不确定自己的理解,请谷歌搜索 __proto__ - JS 对象的内部原型参考。它甚至可以暴露于 Firefox 和 Safari 上的脚本。

一个很好的参考是 https://developer.mozilla.org/en/ Core_JavaScript_1.5_Guide/The_Employee_Example/Object_Properties/Inheriting_Properties

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

扛起拖把扫天下 2024-08-26 19:05:46

如果您有一个对象 obj,它的原型是 obj.prototype,引用 obj 构造函数的构造函数属性是 obj.prototype .构造函数

对于对象 obj.prototype 情况是相同的。假设 proto = obj.prototype,那么对 proto 构造函数的引用将在 proto.prototype.constructor 中找到。

这与 obj.prototype.prototype.constructor 相同,因此与 obj.prototype.constructor 不冲突。

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.

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