JavaScript 原型 - 请澄清 [英] JavaScript Prototype - Please Clarify

查看:38
本文介绍了JavaScript 原型 - 请澄清的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

假设我们创建了以下构造函数 Food.此时,函数 Food() 具有属性 Food.prototype.既然 Food 是 Object 的一个实例,那么这意味着 Obect.prototype 是所有用 Food() 创建的对象的原型属性.

function Food() {}

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

function Pizza(配料){this.toppings = 浇头;}

然后我们通过将 Pizza 的原型属性设置为 Food 的一个实例,让 Pizza 继承自 Food.Pizza 的prototype 属性现在是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(配料){this.toppings = 浇头;}

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

this.toppings = 配料;

Pizza.toppings 是 Pizza.prototype 的属性吗?但是 Pizza.prototype 不是 Pizza() 的属性吗?浇头只是用 Pizza 构造函数创建的对象的属性吗?而 Pizza.prototype 是 Pizza 构造函数的一个属性?

目前的原型链如下:

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

解决方案

我不是从问题的答案开始,而是从原型和构造函数的工作方式开始,以避免在试图用部分理解.所以,原型回顾:

  • JavaScript 中的每个值,除了 nullundefined,都有一个关联的值:它的原型.¹

  • 原型用于查找属性.当你评估 x.foo 时,你会检查值 x 是否有一个 own 属性——一个自身的属性——名为foo".如果是,x.foo 就是那个自己的属性的值.如果不是,则继续查找 x 的原型.

  • 值的原型可以是 null,这意味着任何没有找到自己的属性的属性查找都会导致 undefined.

  • 您可以使用函数 Object.getPrototypeOf.

  • 您可以使用 Object.create.

JavaScript 中的

构造函数有一个名为prototype"的属性.这个属性的值不是构造函数的原型;它是用构造函数创建的值的原型.以您的示例构造函数为例:

function Food() {}

如果您运行 new Food(),将创建​​一个新对象,其原型设置为 Food.prototype,并且 Food 将在 this 设置为那个新对象的情况下执行.换句话说,这是:

//创建一个新的 Food 实例让 f = 新食物();

和这个意思一样:

//创建一个以 Food.prototype 为原型的新对象让 f = Object.create(Food.prototype);//使用构造函数初始化它Food.call(f);

现在,上面总结的属性查找的工作方式产生了一个原型链.如果 x 有一个原型 yy 没有原型,x.foo 会在这个链上查找:

x ->y ->空值

  1. 如果 x 有一个自己的属性foo",x.foo 会计算为它的值
  2. 如果 y 有一个自己的属性foo",x.foo 会计算为它的值
  3. 我们到达了null,链的末端,所以x.fooundefined

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

f ->Food.prototype ->Object.prototype ->空值

如果x的原型是C,你可以说x是构造函数C的一个实例.prototypex 的原型不为 null 并且是 C 的实例.(如果x C.prototypex 不是C的实例.) 这就是 instanceof 操作符的工作原理²:

console.log({} instanceof Object);//真的console.log(Object.prototype instanceof Object);//假

如果C.prototypeD 的一个实例,你也可以说C 继承自D.

JavaScript 中内置的所有内容在其原型链上都有 Object.prototype.函数是 Object 实例:

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

所以构造函数也是:

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

需要注意的是,这并没有说明 FoodObject 实例之间的关系.可以设置Food.prototype = null来得到new Food() instanceof Object === false,但是Food instanceof Object.

我希望这个框架足以解决您的问题.反正就是这个想法.仍然会使用它明确回应他们:

手头的问题

<块引用>

假设我们创建了以下构造函数 Food.此时,函数 Food() 具有属性 Food.prototype.既然 Food 是 Object 的一个实例,那么这意味着 Obect.prototype 是所有用 Food() 创建的对象的原型属性.

所有用 new Food() 创建的对象都有一个 Food.prototype 的原型.Food.prototype 的原型是Object.prototype.Food 是一个函数,也就是说它确实是Object 的一个实例,但是这里Object 的相关实例是Food.原型.

<块引用>

然后我们通过将Pizza的prototype属性设置为Food的一个实例来让Pizza继承Food.Pizza 的prototype 属性现在是Food.prototype,因为Food 是pizza 的父级.

函数Pizza的原型属性现在是一个以Food.prototype为原型的对象.

<块引用>

myPizza 是否也有继承自 Pizza 的原型属性?

myPizza 没有从 Pizza 继承任何东西.它继承了对象 Pizza.prototype 的所有内容.由于 Pizza.prototype 没有名为prototype"的属性,myPizza 不会继承名为prototype"的属性.

<块引用>

什么是Object.prototype?它是 Object() 的属性吗?

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

<块引用>

只有函数有原型属性吗?

使用functionclass 关键字定义的函数以名为prototype 的属性开头.(箭头函数没有,也不能用作构造函数.)你可以在任何东西上放置一个名为 prototype 的属性.它只有在构造函数上才有意义——一个与 newinstanceof 一起使用的函数.

<块引用>

Object.prototype 是对象吗?

当使用object"来指代任何非原始²值时,它是一个带有小写o"的对象.它不是 Object 的实例——它有一个 null 原型.

<块引用>

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

是的,函数是对象³.

<块引用>

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

没有.Pizza.prototype 不是函数.它由 Pizza 构造函数使用,但 Pizza 构造函数不是它的实例,也不是由它创建的.

<块引用>

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

也与范围无关.当您评估 new Pizza() 时,Pizza调用Pizza 的新实例作为它的 这个值.this 不是函数的作用域.范围"是一组变量可见的区域.

function Foo() {让 x = 5;//作用域中的变量.与`this`无关.}

function Foo() {这个.x = 5;//赋值给一个值为 `this` 的属性.//与变量无关.}

<块引用>

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

这不是 Pizza.toppings.有一个新对象 - this - 你将一个参数的值分配给 Pizza 函数,命名为 toppings,给一个属性那个新对象,也被命名为 toppings.新对象的原型是 Pizza.prototype,但新对象不是 Pizza.prototype 本身,所以答案是不",toppings 不是 Pizza.prototype 的属性.

<块引用>

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

它是 Pizza 的一个属性.(只需确保 Pizza() 指的是该函数,而不是您通过调用该函数获得的值.必须准确!)

<块引用>

配料是否只是使用 Pizza 构造函数创建的对象的属性?

没错!

<块引用>

而 Pizza.prototype 是 Pizza 构造函数的一个属性?

是的.

<块引用>

目前的原型链如下:

myPizza -->Pizza.prototype -->Food.prototype -->对象.原型

也正确.你可以用前面提到的 getPrototypeOf 来确认.

Object.prototype.toString = function () { return 'Object.prototype';};功能食品(){}Food.prototype.toString = function () { return 'Food.prototype';};功能比萨(浇头){this.toppings = 浇头;}Pizza.prototype = Object.create(Food.prototype);Pizza.prototype.toString = function () { return 'Pizza.prototype';};让 myPizza = new Pizza();myPizza.toString = function () { return 'myPizza';};让 chainLink = myPizza;而(真){console.log(String(chainLink));if (chainLink === null) {休息;}chainLink = Object.getPrototypeOf(chainLink);}

请注意,我在这里编写了 Object.create(Food.prototype) 而不是 new Food().您不想在子构造函数之外运行父构造函数,尽管这在 ES3 中很常见.ES5 添加了 Object.create.ES6 添加了 classextends,这是你在实践中想要使用的.

¹ 原语在规范中没有 [[Prototype]] 但这并不重要,因为它们的属性查找和 ES5 后的 Object.getPrototypeOf 像它们一样工作.
² 原语是字符串、布尔值、数字、符号、nullundefined.原语是不可变的——它们没有任何自己的属性.对象和基元之间的区别在 JavaScript 中并不那么重要,但是因为它们没有任何自己的属性,所以将它们用作原型是没有意义的.他们也不算是instanceof,因为我要声称是历史原因.
³ 默认情况下,即.您可以要求其中一个或全部不要使用 Object.setPrototypeOf.没有理由这样做.

Can someone please help me understand the prototype property? I don't understand whether the prototype property is a property of the function or of what's inside the function.

Let's say we create the following constructor, Food. At this point, the function Food() has the property Food.prototype. Since Food is an instance of Object, then this means that Obect.prototype is the prototype attribute of all objects created with Food().

function Food() {}

Then create another constructor Pizza. Pizza has the property Pizza.prototype.

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

Then we make Pizza inherit from Food by setting Pizza's prototype property to be an instance of Food. The prototype attribute of Pizza is now Food.prototype since Food is the parent of pizza.

Pizza.prototype = new Food();

Then we create an instance of Pizza

var myPizza = new Pizza("pepperoni");

Does myPizza also have a prototype property that it inherits from Pizza? If so, is myPizza.prototype == Object.prototype? What is Obejct.prototype? Is it a property of Object()? Do only functions have the prototype property? Is Object.prototype an object? Does Pizza.prototype refer to the entire function that creates the Pizza constructor? Is this function an object itself?

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

Or does the Pizza.prototype just refer to what is inside the scope of Pizza()?

this.toppings = toppings;

Is Pizza.toppings a property of Pizza.prototype? But isn't Pizza.prototype a property of Pizza()? Is toppings only a property of an object created with the Pizza constructor? And Pizza.prototype is a property of the Pizza constructor?

Current prototype chain is as follows:

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

解决方案

Instead of starting with answers to the questions, I’m going to start with the way prototypes and constructors work to avoid confusion in trying to interpret those answers with partial understanding. So, prototype recap:

  • Every value in JavaScript, except null and undefined, has an associated value: its prototype.¹

  • The prototype is used to look up properties. When you evaluate x.foo, you check to see if the value x has an own property – a property on itself – named "foo". If it does, x.foo is the value of that own property. If not, the lookup continues on x’s prototype.

  • A value’s prototype can be null, meaning any property lookup that didn’t find an own property results in undefined.

  • You can get a value’s prototype with the function Object.getPrototypeOf.

  • You can create a new object with a specific prototype with the function Object.create.

Constructors in JavaScript have a property named "prototype". The value of this property isn’t the prototype of the constructor; it’s the prototype of values created with the constructor. Taking your example constructor:

function Food() {}

If you run new Food(), a new object will be created with its prototype set to Food.prototype, and Food will be executed with this set to that new object. In other words, this:

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

means the same thing as this:

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

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

Now, the way property lookups work, summarized above, gives rise to a prototype chain. If x has a prototype y and y has no prototype, x.foo gets looked up on this chain:

x -> y -> null

  1. If x has an own property "foo", x.foo evaluates to its value
  2. If y has an own property "foo", x.foo evaluates to its value
  3. We’ve reached null, the end of the chain, so x.foo is undefined

The default value of the prototype property of constructors is a new Object instance, so the prototype chain of a new Food() looks like this:

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

and you can say that a value x is an instance of a constructor C if x’s prototype is C.prototype or x’s prototype is not null and an instance of C. (If x is C.prototype, x is not an instance of C.) This is how the instanceof operator works²:

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

You can also say that C inherits from D if C.prototype is an instance of D.

Everything built into JavaScript has Object.prototype on its prototype chain. Functions are Object instances:

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

and so constructors are too:

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

It’s important to note that this doesn’t say anything about the relationship between instances of Food and Object. You can set Food.prototype = null to get new Food() instanceof Object === false, but it will still be the case that Food instanceof Object.

I hope that this framework is enough to address your questions. That was the idea, anyway. Still going to respond to them explicitly using it:

The questions at hand

Let's say we create the following constructor, Food. At this point, the function Food() has the property Food.prototype. Since Food is an instance of Object, then this means that Obect.prototype is the prototype attribute of all objects created with Food().

All objects created with new Food() have a prototype of Food.prototype. The prototype of Food.prototype is Object.prototype. Food is a function, which means it’s true that it’s an instance of Object, but the relevant instance of Object here is Food.prototype.

Then we make Pizza inherit from Food by setting Pizza's prototype property to be an instance of Food. The prototype attribute of Pizza is now Food.prototype since Food is the parent of pizza.

The prototype property of the function Pizza is now an object with Food.prototype as its prototype.

Does myPizza also have a prototype property that it inherits from Pizza?

myPizza doesn’t inherit anything from Pizza. It inherits everything from the object Pizza.prototype. Since Pizza.prototype does not have a property named "prototype", myPizza does not inherit a property named "prototype".

What is Object.prototype? Is it a property of Object()?

Object.prototype literally means "the ‘prototype’ property of Object", so yes. This value is on the prototype chain of all instances of Object, which is only significant because most things in JavaScript are instances of Object. Apart from that, it’s like any other prototype property of a constructor.

Do only functions have the prototype property?

Functions defined using the function or class keywords start with a property named prototype. (Arrow functions don’t, and can’t be used as constructors.) You can put a property named prototype on anything. It only has meaning when it’s on a constructor – a function used with new or instanceof.

Is Object.prototype an object?

It’s an object with a lowercase "o", when using "object" to refer to any non-primitive² value. It is not an instance of Object – it has a null prototype.

Is this function an object itself?

Yes, functions are objects³.

Does Pizza.prototype refer to the entire function that creates the Pizza constructor?

No. Pizza.prototype is not a function. It’s used by the Pizza constructor but the Pizza constructor is not an instance of it and was not created by it.

Or does the Pizza.prototype just refer to what is inside the scope of Pizza()?

Nothing to do with scope, either. When you evaluate new Pizza(), Pizza is called with a new instance of Pizza as its this value. this is not the scope of a function. A "scope" is an area where some set of variables is visible.

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

Is Pizza.toppings a property of Pizza.prototype?

It’s not Pizza.toppings. There’s a new object – this – and you’re assigning the value of a parameter to the Pizza function, named toppings, to a property of that new object, also named toppings. The new object’s prototype is Pizza.prototype, but the new object is not Pizza.prototype itself and so the answer is that "no", toppings is not a property of Pizza.prototype.

But isn't Pizza.prototype a property of Pizza()?

It’s a property of Pizza. (Just making sure Pizza() refers to the function and not the value you get by calling the function. Gotta be precise!)

Is toppings only a property of an object created with the Pizza constructor?

Right!

And Pizza.prototype is a property of the Pizza constructor?

Yes.

Current prototype chain is as follows:

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

Also correct. You can confirm it with the aforementioned 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);
}

Note that I’ve written Object.create(Food.prototype) instead of new Food() here. You don’t want to run the parent constructor outside the child constructor, though it was common in ES3. ES5 added Object.create. ES6 added class and extends, which is what you’ll want to use in practice.

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

这篇关于JavaScript 原型 - 请澄清的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆