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

Ein*_*012 45 javascript prototype

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

当人们同时谈论构造函数和原型时会产生混淆.

在以下示例中

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

employee.constructor //gives Function()

employee.prototype // gives  Emp {}

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

jack.constructor //gives Emp(name)

jack.prototype //gives undefined
Run Code Online (Sandbox Code Playgroud)
  1. 原型是JS实现继承的一种方式,因为Emp(name)基本函数原型被引用到同一个函数本身.那是怎么回事?

  2. 以什么方式employee.constructoremployee.prototype.constructor不同?

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

  4. 如何在没有在控制台中输入原型或构造函数或prototype.constructor ......产生的内容的情况下清楚地预测自己

Tsc*_*cka 34

如果你已经习惯了在其他OOP语言中扩展对象的简易性,那么你可以很好地解决这个问题,但是我会尽力解释它们的用途以及它们的用途.我假设您熟悉其他OOP语言.如我错了请纠正我.

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

然后有一个构造函数.这就是你用来初始化一个对象的东西.

p = new Foo();

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

  • function FooFunction作为原型(美孚)
  • Function带有Foo()构造函数的对象(p)

(跟我来?)

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

如果您熟悉OOP priciples,那么原型是基类,构造函数是您当前的类.在OOP中,上面会是class Foo extends Function

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

例如:

// 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
}
Run Code Online (Sandbox Code Playgroud)

现在让我们说我们想要不同的方法让baz离开那里.一个用于控制台日志记录,一个用于将其放在标题栏上.我们可以对我们的类Foo做出很大的贡献,但是我们不这样做,因为我们需要对新类做完全不同的事情,但是为不同的实现做了.他们唯一需要分享的是baz项目以及setter和getter.

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

function Title(what) {
    this.message = what;
}
Run Code Online (Sandbox Code Playgroud)

此时Title函数如下所示:

  • 原型功能
  • 构造函数标题

所以,为了使它扩展到Foo,我们需要改变原型.

Title.prototype = new Foo();
Run Code Online (Sandbox Code Playgroud)
  • 原型Foo
  • 构造函数Foo

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

Title.prototype.constructor = Title;
Run Code Online (Sandbox Code Playgroud)
  • 原型Foo
  • 构造函数标题

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

要解决这个问题,我们需要调用父级.在java中,你可以super(vars)在php中使用它$parent->__construct($vars).

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

所以Title类构造函数会变成

function Title(what) {
    Foo.call(this,what);
    this.message = what;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 我讨厌Foo和Bar作为示例类的函数名称,即使经过10年的编程:-) (17认同)
  • 好吧,*戴上太阳镜*处理它:-p (7认同)
  • 我只是想当Foo Bar自己就足够了,但是如果你需要使用Title和Title.message作为后续,那么Foo和Bar应该用相关的隐喻代替 (4认同)

Vis*_*ath 8

employee.constructor //给出Function()

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

var employee2 = new Function('a', 'b', 'return a+b');
Run Code Online (Sandbox Code Playgroud)

使用函数文字创建函数时也会发生同样的情况.此对象的构造函数属性也引用相同的本机Function对象/类.

employee.prototype //给出Emp {}

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

jack.__proto__==employee.prototype
Run Code Online (Sandbox Code Playgroud)

employee.prototype.constructor //给出Emp(名字)

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

jack.constructor //给出Emp(名字)

如前所述,当您使用新的Emp()创建对象时,此对象原型是由函数Emp(name)创建的,

jack.prototype //给出undefined

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

jack.__proto__
Run Code Online (Sandbox Code Playgroud)


小智 6

构造函数:

function Foo(x) {
    this.x =x;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

来源ECMA-262

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

另一方面,当你打电话

var o = new Foo();
Run Code Online (Sandbox Code Playgroud)

JavaScript实际上只是做

var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);
Run Code Online (Sandbox Code Playgroud)

原型:

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

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

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

TL,博士:

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

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


Nid*_*dro 5

如果您想创建一个javascript 对象,则可以简单地声明一个新对象并为其赋予属性(我已选择对自己进行对象化):

var myself= {
    name:"Niddro",
    age:32
};
Run Code Online (Sandbox Code Playgroud)

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

//Constructor
function generalNameForObject(param1, param2,...) {
    //Give the object some properties...
}
Run Code Online (Sandbox Code Playgroud)

我想给人打电话一个原型(recepie),它应该包含属性名称和年龄,我将使用构造函数来实现:

function person(name,age) {
    this.name=name;
    this.age=age;
}
Run Code Online (Sandbox Code Playgroud)

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

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

var myself = new person("Niddro",31);
var OP = new person("rajashekar thirumala",23);
Run Code Online (Sandbox Code Playgroud)

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

myself.age=32;
Run Code Online (Sandbox Code Playgroud)

如果要向该构造添加属性,则需要手动将其添加到构造函数中:

function person(name,age,rep) {
    this.name=name;
    this.age=age;
    this.reputation=rep;
}
Run Code Online (Sandbox Code Playgroud)

相反,您可以通过执行以下操作为原型添加属性(此处“ prototype”是实际命令,而不仅仅是名称):

function person(name,age,rep) {
    this.name=name;
    this.age=age;
}
person.prototype.reputation=105;
Run Code Online (Sandbox Code Playgroud)

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

我希望这可以使您对构造函数和原型之间的关系有更多的了解。