试图理解 JavaScript 中原型和构造函数之间的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28600238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 09:14:33  来源:igfitidea点击:

Trying to understand the difference between prototype and constructor in JavaScript

javascriptprototype

提问by Ein2012

I'm new to JavaScript ,to understand this concept i have read many articles regarding prototype and constructors but where ever i go i'm left with confusion.

我是 JavaScript 的新手,为了理解这个概念,我阅读了许多关于原型和构造函数的文章,但无论我走到哪里,我都感到困惑。

The confusion arises when people talk about constructor and prototype simultaneously.

当人们同时谈论构造函数和原型时,就会出现混淆。

In the following example

在下面的例子中

var employee = function Emp(name) {
    this.name = name;
}
var Hyman = new employee("Hyman Dwain");

employee.constructor //gives Function()

employee.prototype // gives  Emp {}

employee.prototype.constructor //gives Emp(name)

Hyman.constructor //gives Emp(name)

Hyman.prototype //gives undefined
  1. prototype is a way JS achieves inheritance,since Emp(name)is the base function prototype is referenced to the same function itself. Is that what happened?

  2. In what way employee.constructorand employee.prototype.constructordiffer?

  3. Why was Hyman.prototypeis undefinedi.e If it is inheriting from the function Emp(name)why it didn't reference that function?

  4. How can I clearly predict myself without typing in the console what the prototype or the constructor or the prototype.constructor ......yields

  1. 原型是 JS 实现继承的一种方式,因为Emp(name)基函数原型被引用到同一个函数本身。是这么回事吗?

  2. 在什么样的方式employee.constructoremployee.prototype.constructor不同?

  3. 为什么Hyman.prototypeundefinedie 如果它是从函数继承的,Emp(name)为什么它没有引用该函数?

  4. 我如何在不输入控制台的情况下清楚地预测自己的原型或构造函数或prototype.constructor ......产量

采纳答案by Tschallacka

Its a pretty hard thing to wrap your mind around if you are used to the ease of extending objects in other OOP languages, but I'll do my best to explain the uses of those and what is what. I am going to assume you are familiar with other OOP languages. Correct me if I'm wrong.

如果您习惯于在其他 OOP 语言中轻松扩展对象,这是一件非常困难的事情,但我会尽力解释这些的用途以及什么是什么。我假设您熟悉其他 OOP 语言。如我错了请纠正我。

All functions have the prototype Function(). They are inheriting all base functionality from Function like toString() and valueOf().

所有函数都有原型Function()。它们继承了 Function 的所有基本功能,如 toString() 和 valueOf()。

Then there is a constructor. That is what you use to initialize an object with.

然后是构造函数。这就是您用来初始化对象的内容。

p = new Foo();

p = new Foo();

So in this case we have two things.

所以在这种情况下,我们有两件事。

  • A function Foowith Functionas prototype(Foo)
  • A Functionobject with Foo()as constructor(p)
  • A function Foowith Functionasprototype(Foo)
  • Function具有Foo()as 构造函数的对象(p)

(following me yet?)

(还跟着我?)

The Foo()constructor can override some base functionality of the Functionconstructor, but also leave it as it is and make good use of it.

Foo()构造可以覆盖的一些基本功能Function构造,也离开它,因为它是和用好它。

If you are familiar with OOP principles, The prototype is the base class, the constructor your current class. in OOP the above would be class Foo extends Function

如果你熟悉OOP原理,原型就是基类,构造函数就是你当前的类。在 OOP 中,以上将是class Foo extends Function

You can also start inheritance with this entire setup of prototype and constructor making more complex objects as you go whilst sharing functionality.

您还可以通过原型和构造函数的整个设置开始继承,从而在共享功能的同时制作更复杂的对象。

For example this:

例如这个:

// make a object initialiser extending Function. in oop `class Foo extends Function`

function Foo(bar) {
    this.baz = bar;
}
Foo.prototype.append = function(what) {
    this.baz += " " + what;
};
Foo.prototype.get() {
    return this.baz
}

Now lets say we want different ways to get baz out of there. one for console logging and one for putting it on the title bar. We could make a big thing about our class Foo, but we dont do that, because we need to do wholly different things with the new classes but are made for different implementations. The only thing they need to share are the baz item and the setters and getters.

现在让我们说我们想要不同的方式让 baz 离开那里。一个用于控制台日志记录,另一个用于将其放在标题栏上。我们可以对我们的类 Foo 做大事,但我们不这样做,因为我们需要对新类做完全不同的事情,但它们是为不同的实现而设计的。他们唯一需要共享的是 baz 项以及 setter 和 getter。

So we need to extend it to use an OOP term. in OOp this would be the desired end result class Title extends Foo(){}. So lets take a look how to get there.

所以我们需要扩展它以使用 OOP 术语。在 OOp 中,这将是所需的最终结果class Title extends Foo(){}。那么让我们来看看如何到达那里。

function Title(what) {
    this.message = what;
}

At this point the Title function looks like this:

此时 Title 函数如下所示:

  • prototype Function
  • constructor Title
  • 原型函数
  • 构造器标题

So, to make it extends Foo we need to change the prototype.

因此,要使其扩展 Foo,我们需要更改原型。

Title.prototype = new Foo();
  • prototype Foo
  • constructor Foo
  • 原型 Foo
  • 构造函数 Foo

This is done by initializing a new Foo() object against the prototype. Now its basically a Foo object called Title. That is not what we want because now we cant access the message part in Title. We can make it properly extend Foo() by resetting the constructor to Title

这是通过针对原型初始化一个新的 Foo() 对象来完成的。现在它基本上是一个名为 Title 的 Foo 对象。这不是我们想要的,因为现在我们无法访问 Title 中的消息部分。我们可以通过将构造函数重置为 Title 来使其正确扩展 Foo()

Title.prototype.constructor = Title;
  • prototype Foo
  • Constructor Title
  • 原型 Foo
  • 构造函数

Now we are faced with one more problem. The constructor of Foo doesn't get initialized so we end up with an undefined this.baz

现在我们又面临一个问题。Foo 的构造函数没有被初始化,所以我们最终得到一个未定义的this.baz

To resolve that we need to call the parent. In java you would do that with super(vars), in php $parent->__construct($vars).

为了解决这个问题,我们需要打电话给父母。在 java 中,您可以使用super(vars), 在 php 中做到这一点$parent->__construct($vars)

In javascript we have to modify the Title class constructor to call the constructor of the parent object.

在javascript中我们必须修改Title类的构造函数来调用父对象的构造函数。

So the Title class constructor would become

所以 Title 类构造函数会变成

function Title(what) {
    Foo.call(this,what);
    this.message = what;
}

By using the Function object property Foo inherited we can initialism the Foo object in the Title object.

通过使用继承的函数对象属性 Foo,我们可以初始化 Title 对象中的 Foo 对象。

And now you have a properly inherited object.

现在你有了一个正确继承的对象。

So instead of using a keyword like extendlike other OOP languages it uses prototypeand constructor.

因此,extend它不像其他 OOP 语言那样使用关键字,而是使用prototypeconstructor

回答by Niddro

If you want to create a javascript objectyou can simply declare a new object and give it properties (I've chosen to objectify myself):

如果你想创建一个 javascript对象,你可以简单地声明一个新对象并给它属性(我选择对象化自己):

var myself= {
    name:"Niddro",
    age:32
};

This method allows you to make oneobject. If what you want to have is a prototypedescribing a person in general, where you can declare several people with the same setup. To create a prototype, you can use a constructor, ass seen below:

此方法允许您制作一个对象。如果你想要的是一个描述一个人的原型,你可以在其中声明几个具有相同设置的人。要创建原型,您可以使用构造函数,如下所示:

//Constructor
function generalNameForObject(param1, param2,...) {
    //Give the object some properties...
}

I have a prototype (a recepie) in mind that I want to call person and it should contain the properties name and age and I'll use a constructor to make it:

我有一个原型(收据),我想打电话给 person ,它应该包含属性名称和年龄,我将使用构造函数来制作它:

function person(name,age) {
    this.name=name;
    this.age=age;
}

The above construct function describes the prototype for my person objects.

上面的构造函数描述了我的人对象的原型。

Create a new person by calling the construct function:

通过调用构造函数创建一个新人:

var myself = new person("Niddro",31);
var OP = new person("rajashekar thirumala",23);

Some time passes and I realise that I've had a birthday so I need to change the property of the prototype:

过了一段时间,我意识到我已经过生日了,所以我需要更改原型的属性:

myself.age=32;

If you want to add properties to the construct, you need to manually add it into the construct function:

如果要为construct添加属性,则需要手动将其添加到construct函数中:

function person(name,age,rep) {
    this.name=name;
    this.age=age;
    this.reputation=rep;
}

Instead, you can add properties to the prototype by doing the following (here "prototype" is an actual command and not just a name):

相反,您可以通过执行以下操作向原型添加属性(这里的“原型”是一个实际的命令,而不仅仅是一个名称):

function person(name,age,rep) {
    this.name=name;
    this.age=age;
}
person.prototype.reputation=105;

note that this will add a reputation of 105 for all objects created.

请注意,这将为所有创建的对象增加 105 的声誉。

I hope this has given you some more insight on the relationship between the constructor and prototype.

我希望这能让您更深入地了解构造函数和原型之间的关系。

回答by Vishwanath

employee.constructor //gives Function()

employee.constructor //给出函数()

In JavaScript functions are also objects, which can be constructed using its own constructor which is Function. So you can write following code to get a instance of Function.

在 JavaScript 中,函数也是对象,可以使用它自己的构造函数 Function来构造。因此,您可以编写以下代码来获取 Function 的实例。

var employee2 = new Function('a', 'b', 'return a+b');

Same happens when you create function using function literal like in your case. And the constructor property of this object also refers to the same native Function object/class.

当您使用函数文字创建函数时也会发生同样的情况,就像您的情况一样。而这个对象的构造函数属性也引用了同一个原生的Function对象/类。

employee.prototype // gives Emp {}

employee.prototype // 给出 Emp {}

Each object in JavaScript has a prototype associated with it. Though only function objects prototype is directly accessible with the .prototype. This same prototype is copied on its objects prototype when you create objects with newkeyword. Primarily this copying is responsible for the inheritance/extension. Although the prototype is copied, it is not directly asseccible like in case of Function objects. It's available in non standard way with .__proto__. Following code will return true.

JavaScript 中的每个对象都有一个与之关联的原型。尽管只有函数对象原型可以通过.prototype. 当您使用new关键字创建对象时,将在其对象原型上复制相同的原型。这种复制主要负责继承/扩展。尽管原型被复制,但它不像 Function 对象那样直接可分解。它可以以非标准方式使用.__proto__. 以下代码将返回true。

Hyman.__proto__==employee.prototype

employee.prototype.constructor //gives Emp(name)

employee.prototype.constructor //给出 Emp(name)

As said in the documentation of Object.prototype.constructor. This returns a reference to the Object function that created the instance's prototype. Here the object being refered is employee.prototype and not employee. This is bit complex but prototype of object employee.prototype was created by the function Emp(name)

正如Object.prototype.constructor的文档中所说。这将返回对创建实例原型的 Object 函数的引用。这里被引用的对象是employee.prototype 和not employee。这有点复杂,但对象employee.prototype 的原型是由函数Emp(name) 创建的

Hyman.constructor //gives Emp(name)

Hyman.constructor // 给 Emp(name)

As said in the previous point, this objects prototype was created by function Emp(name) when you created the object using new Emp(),

正如前一点所说,当你使用 new Emp() 创建对象时,这个对象原型是由函数 Emp(name) 创建的,

Hyman.prototype //gives undefined

Hyman.prototype //给出未定义

Hyman is not a function object, so you cant access its prototype like that. You can access(not a standard way) the prototype of Hyman like following.

Hyman 不是一个函数对象,所以你不能像那样访问它的原型。您可以访问(非标准方式)Hyman 的原型,如下所示。

Hyman.__proto__

回答by Vishwanath

Constructor:

构造函数:

function Foo(x) {
    this.x =x;
}

Foois the constructor. A constructor is a function.

Foo是构造函数。构造函数是一个函数。

There are two ways to use this constructor Foo.

有两种方法可以使用此构造函数Foo

"Objects are created by using constructors in new expressions; for example, new Date(2009,11) creates a new Date object. Invoking a constructor without using new has consequences that depend on the constructor. For example, Date() produces a string representation of the current date and time rather than an object."

“对象是通过在 new 表达式中使用构造函数创建的;例如,new Date(2009,11) 创建一个新的 Date 对象。在不使用 new 的情况下调用构造函数的后果取决于构造函数。例如,Date() 生成一个字符串表示当前日期和时间而不是对象。”

Source ECMA-262

来源ECMA-262

That means if Fooreturns something (via return "somevalue";) then typeof Foo()is the type of the return value.

这意味着如果Foo返回某些内容 (via return "somevalue";),则typeof Foo()是返回值的类型。

On the other hand, when you call

另一方面,当你打电话

var o = new Foo();

JavaScript actually just does

JavaScript实际上只是

var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);

Prototype:

原型:

When you call o.a, then javascript first checks if ais a own property of the object o. If not javascript will look up the property chain to find a.

当您调用时o.a,javascript 首先检查是否a是对象的自己的属性o。如果不是,javascript 将查找属性链以找到a.

For more information about property-chain have a look at mdn.

有关属性链的更多信息,请查看mdn

The prototypeporperty of the constructor has a really powerful feature, that is not available in classes. If it's useful is another debate. The prototypeporperty of the constructor can alter properties of each instance that does link to that prototype in their prototype-chain.

prototype构造函数的属性有一个非常强大的特性,这是类中没有的。如果它有用是另一场辩论。该prototype构造的porperty可以改变所有做过链接到原型在他们的原型链实例的属性。

TL,DR:

TL,博士:

Note: This is not an exact definition, the purpose of the summary is just to give you a feeling about constructors and prototypes.

注意:这不是一个确切的定义,总结的目的只是让你对构造函数和原型有一个感受。

If you use a constructor with the newkeyword, then constructors and prototypes have kind of similar purpose even though they are completely different. A constructor initializes properties of the object, so it provides properties. A prototype also provides properties via the property-chain (prototype-based inheritance).

如果您使用带有new关键字的构造函数,则构造函数和原型具有相似的用途,即使它们完全不同。构造函数初始化对象的属性,因此它提供属性。原型还通过属性链(基于原型的继承)提供属性。

回答by abdulwahhab

Yet the truth is, this approach might be wrong for many situations. In Javascript when you bind a method to the this keyword, you are providing that method to only that particular instance and it does not really have any relationship with an object instance of that constructor, pretty much like a static method. Keeping in mind that functions are first-class citizens in Javascript, we can deal with them just like objects, in this case we're only adding a property to an instance of a function object. Thats only part of the story, you must also know that any method attached via this will get re-declared for every new instance we create, which could affect the memory usage of the application negatively if we wish to create so many instances.

然而事实是,这种方法在许多情况下可能是错误的。在 Javascript 中,当您将方法绑定到 this 关键字时,您仅向该特定实例提供该方法,并且它与该构造函数的对象实例实际上没有任何关系,就像静态方法一样。请记住,函数在 Javascript 中是一等公民,我们可以像处理对象一样处理它们,在这种情况下,我们只向函数对象的实例添加属性。这只是故事的一部分,您还必须知道通过 this 附加的任何方法都会为我们创建的每个新实例重新声明,如果我们希望创建如此多的实例,这可能会对应用程序的内存使用产生负面影响。