JavaScript 原型 - 请澄清

2024-05-15

有人可以帮我理解原型属性吗?我不明白原型属性是函数的属性还是函数内部的属性。

假设我们创建以下构造函数 Food。此时,函数 Food() 具有 Food.prototype 属性。由于 Food 是 Object 的实例,因此这意味着 Obect.prototype 是使用 Food() 创建的所有对象的原型属性。

function Food() {}

然后创建另一个构造函数 Pizza。 Pizza 拥有 Pizza.prototype 属性。

function Pizza(toppings) {
    this.toppings = toppings;
}

然后我们通过将Pizza 的prototype 属性设置为Food 的实例来使Pizza 继承自Food。 Pizza 的原型属性现在是 Food.prototype,因为 Food 是 Pizza 的父级。

Pizza.prototype = new Food();

然后我们创建一个 Pizza 实例

var myPizza = new Pizza("pepperoni");

myPizza 是否也有一个从 Pizza 继承的原型属性?如果是这样,myPizza.prototype == Object.prototype 吗?什么是Obejct.prototype?它是 Object() 的属性吗?只有函数才有原型属性吗? Object.prototype 是一个对象吗? Pizza.prototype 是否指的是创建 Pizza 构造函数的整个函数?这个函数本身是一个对象吗?

function Pizza(toppings) {
    this.toppings = toppings;
}

或者 Pizza.prototype 只是指 Pizza() 范围内的内容?

this.toppings = toppings;

Pizza.toppings 是 Pizza.prototype 的属性吗?但 Pizza.prototype 不是 Pizza() 的属性吗? toppings 仅仅是用 Pizza 构造函数创建的对象的属性吗? Pizza.prototype 是 Pizza 构造函数的属性吗?

目前原型链如下:

myPizza --> Pizza.prototype --> Food.prototype --> Object.prototype


我不会从问题的答案开始,而是从原型和构造函数的工作方式开始,以避免在尝试以部分理解的方式解释这些答案时出现混乱。那么,原型回顾一下:

  • JavaScript 中的每个值,除了null and undefined,有一个关联值:它的原型。

  • 原型用于查找属性。当你评价时x.foo,您检查该值是否x has an 自有财产– 其自身的属性 – 名为“foo”。如果是的话,x.foo是那个的值自有财产。如果没有,则继续查找x的原型。

  • 值的原型可以是null,意味着任何未找到自己财产的财产查找都会导致undefined.

  • 您可以使用该函数获取值的原型Object.getPrototypeOf https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf.

  • 您可以使用以下函数创建具有特定原型的新对象Object.create https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create.

构造函数在 JavaScript 中有一个名为“原型”的属性。该属性的值不是构造函数的原型;而是构造函数的原型。它是用构造函数创建的值的原型。以您的示例构造函数为例:

function Food() {}

如果你跑new Food(),将创建一个新对象,其原型设置为Food.prototype, and Food将被执行this设置为该新对象。换句话说,这个:

// create a new instance of Food
let f = new Food();

与此含义相同:

// create a new object with Food.prototype as its prototype
let f = Object.create(Food.prototype);

// initialize it using the constructor
Food.call(f);

现在,如上所述,属性查找的工作方式产生了一个原型链。如果x有原型y and y没有原型,x.foo在此链上查找:

x -> y -> null
  1. If x有一个自己的属性“foo”,x.foo评估其价值
  2. If y有一个自己的属性“foo”,x.foo评估其价值
  3. 我们已经达到了null,链的末端,所以x.foo is undefined

默认值prototype构造函数的属性是一个新的Object实例,所以a的原型链new Food()看起来像这样:

f -> Food.prototype -> Object.prototype -> null

你可以说一个值x是一个构造函数的实例C if x的原型是C.prototype or x的原型不为 null 并且是一个实例C. (If x is C.prototype, x不是一个实例C.) 这就是instanceof操作员工作原理²:

console.log({} instanceof Object);  // true
console.log(Object.prototype instanceof Object);  // false

你也可以这样说C继承自D if C.prototype是一个实例D.

JavaScript 中内置的所有内容都具有Object.prototype在其原型链上。功能有Object实例:

function f() {}
f instanceof Object  // true

所以构造函数也是:

function Food() {}
Food instanceof Object  // true

值得注意的是,这并没有说明实例之间的关系Food and Object。您可以设置Food.prototype = null to get new Food() instanceof Object === false,但情况仍然会是这样Food instanceof Object.

我希望这个框架足以解决您的问题。无论如何,这就是想法。仍然会明确地使用它来回应他们:

手头的问题

假设我们创建以下构造函数 Food。此时,函数 Food() 具有 Food.prototype 属性。由于 Food 是 Object 的实例,因此这意味着 Obect.prototype 是使用 Food() 创建的所有对象的原型属性。

所有创建的对象new Food()有一个原型Food.prototype。原型为Food.prototype is Object.prototype. Food是一个函数,这意味着它确实是一个实例Object,但相关实例Object这是Food.prototype.

然后我们通过将Pizza 的prototype 属性设置为Food 的实例来使Pizza 继承自Food。 Pizza 的原型属性现在是 Food.prototype,因为 Food 是 Pizza 的父级。

原型property函数的Pizza is now 一个物体与Food.prototype作为它的原型.

myPizza 是否也有一个从 Pizza 继承的原型属性?

myPizza不继承任何东西Pizza。它继承了对象的一切Pizza.prototype. Since Pizza.prototype没有名为“prototype”的属性,myPizza不继承名为“prototype”的属性。

什么是对象原型?它是 Object() 的属性吗?

Object.prototype字面意思是“原型”属性Object”,所以是的。这个值位于所有Object实例的原型链上,这很重要,因为JavaScript中的大多数东西都是Object的实例。除此之外,它就像其他任何东西一样prototype构造函数的属性。

只有函数才有原型属性吗?

使用定义的函数function or class关键字以名为的属性开头prototype。 (箭头函数没有,也不能用作构造函数。)您可以放置​​一个名为prototype在任何事情上。它仅在构造函数上才有意义——与 一起使用的函数new or instanceof.

Object.prototype 是一个对象吗?

当使用“object”来引用任何非原始值时,它是一个带有小写“o”的对象。它不是一个实例Object- 它有一个null原型。

这个函数本身是一个对象吗?

是的,函数就是对象。

Pizza.prototype 是否指的是创建 Pizza 构造函数的整个函数?

No. Pizza.prototype不是一个函数。它由以下人员使用Pizza构造函数但是Pizza构造函数不是它的实例,也不是由它创建的。

或者 Pizza.prototype 只是指 Pizza() 范围内的内容?

也与范围无关。当你评价时new Pizza(), Pizza is called与一个新实例Pizza as its this value. this不是函数的作用域。 “范围”是一些变量集可见的区域。

function Foo() {
    let x = 5;  // a variable in scope. unrelated to `this`.
}
function Foo() {
    this.x = 5;  // assigning to a property of the value `this`.
                 // unrelated to variables.
}

Pizza.toppings 是 Pizza.prototype 的属性吗?

它不是Pizza.toppings。有一个新对象——this– 并且您将参数的值分配给Pizza函数,命名为toppings,到该新对象的属性,也命名为toppings。新对象的原型是Pizza.prototype,但新对象不是Pizza.prototype本身,所以答案是“不”,toppings不是以下的财产Pizza.prototype.

但 Pizza.prototype 不是 Pizza() 的属性吗?

这是一个属性Pizza。 (只是确保Pizza()指的是函数,而不是调用函数得到的值。一定要准确!)

toppings 仅仅是用 Pizza 构造函数创建的对象的属性吗?

Right!

Pizza.prototype 是 Pizza 构造函数的属性吗?

Yes.

目前原型链如下:

myPizza --> Pizza.prototype --> Food.prototype --> Object.prototype

也正确。您可以通过上述内容进行确认getPrototypeOf.

Object.prototype.toString = function () { return 'Object.prototype'; };

function Food() {}
Food.prototype.toString = function () { return 'Food.prototype'; };

function Pizza(toppings) {
    this.toppings = toppings;
}

Pizza.prototype = Object.create(Food.prototype);
Pizza.prototype.toString = function () { return 'Pizza.prototype'; };

let myPizza = new Pizza();
myPizza.toString = function () { return 'myPizza'; };

let chainLink = myPizza;

while (true) {
    console.log(String(chainLink));
    
    if (chainLink === null) {
        break;
    }
    
    chainLink = Object.getPrototypeOf(chainLink);
}

请注意我已经写了Object.create(Food.prototype)代替new Food()这里。你不想在子构造函数之外运行父构造函数,尽管这在 ES3 中很常见。添加了 ES5Object.create。添加ES6class and extends,这就是您在实践中想要使用的。

¹ Primitives don’t have a [[Prototype]] in the spec but that doesn’t really matter because their property lookup and post-ES5 Object.getPrototypeOf work like they do.
² Primitives are strings, booleans, numbers, symbols, null, and undefined. Primitives are immutable – they don’t have any own properties. The distinction between objects and primitives isn’t that important in JavaScript, but because they don’t have any own properties it doesn’t make sense to use them as prototypes. They also don’t count as instanceof anything for what I’m going to claim are historical reasons.
³ By default, that is. You can ask one or all of them not to be with Object.setPrototypeOf. There’s no reason to do this.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript 原型 - 请澄清 的相关文章

随机推荐