我是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
prototype是JS实现继承的一种方式,因为Emp(name)
是基函数原型被引用到同一个函数本身。那是怎么回事?
employee.constructor
和employee.prototype.constructor
有何不同?
为什么jack.prototype
是undefined
,即如果它是从函数Emp(name)
继承的,为什么它没有引用该函数?
如何在没有在控制台中输入原型或构造函数或者prototype.constructor ......产生的内容的情况下清楚地预测自己
答案 0 :(得分:30)
如果你已经习惯了在其他OOP语言中扩展对象的简易性,那么你可以很好地解决这个问题,但是我会尽力解释它们的用途以及它们的用途。我假设您熟悉其他OOP语言。如果我错了,请纠正我。
所有函数都有原型Function()。它们继承了函数的所有基本功能,如toString()和valueOf()。
然后有一个构造函数。这就是你用来初始化对象的方法。
p = new Foo();
所以在这种情况下我们有两件事。
function Foo
为原型(Foo)Function
Function
对象,Foo()
作为构造函数(p)(跟我来?)
Foo()
构造函数可以覆盖Function
构造函数的某些基本功能,但也保留原样并充分利用它。
如果您熟悉OOP原则,那么原型是基类,构造函数是您当前的类。在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
}
现在让我们说我们想要不同的方法让baz离开那里。一个用于控制台日志记录,一个用于将其放在标题栏上。 我们可以为我们的类Foo做一件大事,但我们不这样做,因为我们需要对新类做完全不同的事情,但是为不同的实现做了。他们唯一需要分享的是baz项目以及setter和getters。
因此我们需要扩展它以使用OOP术语。在OOp中,这将是期望的最终结果class Title extends Foo(){}
。所以我们来看看如何到达那里。
function Title(what) {
this.message = what;
}
此时Title函数如下所示:
因此,为了使它扩展到Foo,我们需要更改原型。
Title.prototype = new Foo();
这是通过针对原型初始化新的Foo()对象来完成的。 现在它基本上是一个名为Title的Foo对象。这不是我们想要的,因为现在我们无法访问Title中的消息部分。 我们可以通过将构造函数重置为Title
来正确扩展Foo()Title.prototype.constructor = Title;
现在我们又遇到了一个问题。 Foo的构造函数没有初始化,所以最终得到一个未定义的this.baz
要解决这个问题,我们需要调用父级。在java中,您可以使用super(vars)
中的$parent->__construct($vars)
执行此操作。
在javascript中,我们必须修改Title类构造函数以调用父对象的构造函数。
所以Title类构造函数将成为
function Title(what) {
Foo.call(this,what);
this.message = what;
}
通过使用函数对象属性Foo继承,我们可以初始化Title对象中的Foo对象。
现在你有一个正确继承的对象。
因此,与其他OOP语言一样使用extend
之类的关键字时,它使用prototype
和constructor
。
答案 1 :(得分:8)
employee.constructor //给出Function()
在JavaScript中,函数也是对象,可以使用自己的构造函数Function来构造。因此,您可以编写以下代码来获取Function的实例。
var employee2 = new Function('a', 'b', 'return a+b');
使用函数文字创建函数时也会发生同样的情况。此对象的构造函数属性也引用相同的本机Function对象/类。
employee.prototype //给出了Emp {}
JavaScript中的每个对象都有一个与之关联的原型。虽然只有.prototype
可以直接访问函数对象原型。当您使用new
关键字创建对象时,会将相同的原型复制到其对象原型上。这种复制主要负责继承/扩展。虽然复制了原型,但它不像Function对象那样可以直接组合。它以.__proto__
的非标准方式提供。以下代码将返回true。
jack.__proto__==employee.prototype
employee.prototype.constructor //给出Emp(名称)
如Object.prototype.constructor的文件中所述。这将返回对创建实例原型的Object函数的引用。这里引用的对象是employee.prototype和not employee
。这有点复杂,但对象employee.prototype的原型是由函数Emp(name)
jack.constructor //给出Emp(名字)
正如前面所述,当你使用新的Emp()创建对象时,这个对象原型是由函数Emp(name)创建的,
jack.prototype //给出未定义的
jack不是一个函数对象,所以你无法像这样访问它的原型。您可以访问(不是标准方式)插孔原型,如下所示。
jack.__proto__
答案 2 :(得分:5)
如果你想创建一个javascript 对象,你可以简单地声明一个新对象并给它属性(我已选择自我客观化):
var myself= {
name:"Niddro",
age:32
};
此方法允许您创建一个对象。如果你想拥有一个原型来描述一般人,你可以用相同的设置声明几个人。要创建原型,您可以使用构造函数,如下所示:
//Constructor
function generalNameForObject(param1, param2,...) {
//Give the object some properties...
}
我有一个原型(一个recepie),我想要打电话给人,它应该包含属性名称和年龄,我将使用构造函数来实现它:
function person(name,age) {
this.name=name;
this.age=age;
}
上面的构造函数描述了我的人物对象的原型。
通过调用构造函数创建一个新人:
var myself = new person("Niddro",31);
var OP = new person("rajashekar thirumala",23);
一段时间过去了,我意识到我已经过了生日,所以我需要更改原型的属性:
myself.age=32;
如果要向构造添加属性,则需要手动将其添加到构造函数中:
function person(name,age,rep) {
this.name=name;
this.age=age;
this.reputation=rep;
}
相反,您可以通过执行以下操作向原型添加属性(此处"原型"是实际命令而不仅仅是名称):
function person(name,age,rep) {
this.name=name;
this.age=age;
}
person.prototype.reputation=105;
请注意,这会为所有创建的对象添加105的声誉。
我希望这能让你更深入地了解构造函数和原型之间的关系。
答案 3 :(得分:3)
构造强>
function Foo(x) {
this.x =x;
}
Foo
是构造函数。构造函数是一个函数。
有两种方法可以使用此构造函数Foo
。
“通过在新表达式中使用构造函数来创建对象;对于 例如,new Date(2009,11)创建一个新的Date对象。调用一个 不使用new的构造函数具有依赖于的结果 构造函数。例如,Date()生成一个字符串表示形式 当前的日期和时间而不是对象。“
来源ECMA-262
这意味着如果Foo
返回某些内容(通过return "somevalue";
),那么typeof Foo()
就是返回值的类型。
另一方面,当你打电话
var o = new Foo();
JavaScript其实就是
var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);
<强>原型:强>
当您致电o.a
时,javascript会首先检查a
是否为对象o
的属性。如果不是,javascript将查找属性链以查找a
。
有关属性链的更多信息,请查看mdn。
构造函数的prototype
属性具有非常强大的功能,在类中不可用。如果它有用是另一场辩论。构造函数的prototype
属性可以改变在原型链中链接到该原型的每个实例的属性。
<强>要点:强>
注意:这不是一个确切的定义,摘要的目的只是为了让您对控制器和原型有所了解。
如果你使用带有new
关键字的构造函数,那么构造函数和原型具有类似的目的,即使它们完全不同也很难。构造函数初始化对象的属性,因此它提供属性。原型还通过属性链(基于原型的继承)提供属性。
答案 4 :(得分:1)
原型只是对象, 而 构造函数是指向创建对象的函数的指针。
构造函数是指针。它指向创建要从中检索构造函数的点的Function()。 (即,构造函数只是对Function()的引用,我们可以根据需要多次调用它。)
构造函数的用途之一是帮助您创建对象的复制副本。由于构造函数属性是对创建对象的函数的引用,因此只要您有对象的副本,它就始终指向原始构造函数。https://coderwall.com/p/qjzbig/understanding-constructor-and-prototype
使用对象构造器: 通常,在许多情况下,单独创建的对象受到限制。它只会创建一个对象。
有时候我们喜欢拥有一个“对象类型”,可以用来创建许多一种类型的对象。
创建“对象类型”的标准方法是使用对象构造函数:
function person(first, last, email ) {
this.first_name = first;
this.last_name = last;
this.e_mail = email;
}
var myFather = new person("Ibm", "Muh", "ibm@gmail.com");
以上函数(人)是一个对象构造函数。一旦有了对象构造函数,就可以创建相同类型的新对象:
var myFather = new person("Sul", "Ahm", "sul@gmail.com");
每个JavaScript对象都有一个原型。 原型也是一个对象。
所有JavaScript对象都从其原型继承其属性和方法。
使用两种创建对象的方法来创建对象,即(1)对象文字,或(2)和new Object(),它们是从称为Object的原型继承而来的。原型。使用new Date()创建的对象继承了Date.prototype。
Object.prototype在原型链的顶部。
所有JavaScript对象(日期,数组,RegExp,函数等)都继承自Object.prototype。https://www.w3schools.com/js/js_object_prototypes.asp
关键字原型是Function()对象的属性。
原型的值是创建该特定对象的对象构造函数。让我们看几个原型:
Boolean.prototype // returns Object Boolean
String.prototype // returns Object String with methods such as "toUpperCase"
Function.prototype // returns function() {} or function Empty() {}
创建原型:
创建对象原型的标准方法是使用对象构造函数:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
}
var myFather = new Person("John", "Doe", 50);
通过构造函数,您可以使用new关键字从同一原型创建新对象,如上所示:
构造函数是Person对象的原型。 用大写首字母命名构造函数是一种好习惯。
将属性添加到原型
您不能像向现有对象添加新属性一样,向原型添加新属性,因为原型不是现有对象。
示例: Person.nationality =“英语”;
要将新属性添加到原型,必须将其添加到构造函数:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
this.nationality = "English";
}
所有本机和复杂对象都检索到其原始构造函数,在本例中为它们自己。唯一的例外是Function原型,它返回创建它的Function()函数。不要将它与构造函数混淆,因为它不一样。
Function.prototype === Function.constructor // returns false, Function.constructor is function Function(){}
还有一个额外的属性__proto__
,它引用实例对象的内部[[proto]]属性。与Function()对象不同,每个Object都有一个__proto__
。
不建议更新实例对象的原型,因为不应在运行时更改原型(您应该能够看到谁是谁的原型,否则您需要花费额外的计算来确保没有循环引用)。 / p>
答案 5 :(得分:0)
实际上,这种方法在许多情况下可能是错误的。在Javascript中,当您将方法绑定到this关键字时,您仅将该方法提供给该特定实例,并且它实际上与该构造函数的对象实例没有任何关系,非常类似于静态方法。请记住,函数是Javascript中的一等公民,我们可以像处理对象一样处理它们,在这种情况下,我们仅向函数对象的实例添加属性。那只是故事的一部分,您还必须知道,对于我们创建的每个新实例,通过此方法附加的任何方法都将被重新声明,如果我们希望创建这么多实例,这可能会对应用程序的内存使用产生负面影响。>