我正在尝试理解原型和构造函数在JavaScript中是如何工作的,并且遇到了这种情况。
我总是想象如何在JavaScript中创建对象是
return this
这种理解方式似乎无法解释obj2
和obj3
。
例如,我明确将Foo.prototype.constructor
设置为obj2
的其他内容,但obj2
仍然具有属性bar
。假设bar
存储在Foo的原型中,这解释了为什么obj2
具有属性bar
以及为什么obj3
由Object
创建,但是如果我创建了该怎么办?还有几个obj2
s,这意味着他们在Foo的原型上共享相同的变量bar
,我认为情况并非如此。
有人可以对obj2
和obj3
这样的原因做出更合理的解释吗?
function Foo(){
this.bar = true;
}
console.log('obj1');
var obj1 = new Foo();
console.log(obj1);
console.log(obj1.constructor === Foo);
console.log('obj2');
Foo.prototype.constructor = 3; //a dummy value
var obj2 = new Foo();
console.log(obj2);
console.log(obj2.constructor === Foo);
function Bar(){
this.foo = true;
}
console.log('obj3');
Bar.prototype = 3;
var obj3 = new Bar();
console.log(obj3);
console.log(obj3.constructor === Bar);
console.log(obj3.constructor === Object);
答案 0 :(得分:1)
昨天我看到了你的帖子,但当时我有点忙,现在我有空,我想回答你的问题。
执行代码new Foo()
时,会发生以下情况:
函数Foo()被调用,正如@slebetman所提到的,因为函数是用new
关键字调用的,所以它被视为构造函数,创建一个空对象。
该对象链接到函数的原型,继承自Foo.prototype
。
this
绑定到新创建的对象。 this.bar = true
已执行。 new Foo
相当于new Foo()
,即如果没有指定参数列表,则不带参数调用Foo。
构造函数返回的对象成为整个新表达式的结果。如果构造函数未显式返回对象,则使用在第一步中创建的对象。 (通常构造函数不返回值,但如果他们想要覆盖正常的对象创建过程,他们可以选择这样做。)
让我们说bar存储在Foo的原型中,这解释了为什么obj2具有属性栏以及为什么obj3是由Object创建的,但是如果我创建了几个obj2s,这意味着它们在Foo的原型上共享相同的变量栏,我认为情况并非如此。
你是对的。
bar
是由obj1
和obj2
拥有的财产,例如:
console.log(obj1.hasOwnProperty("bar")); // true
但是如果你添加这样的属性:
Foo.prototype.bar2 = true;
console.log(obj1.hasOwnProperty("bar2")); // false
所有bar2
个实例共享Foo
的值,但bar
个实例不共享Foo
属性,每个Foo
实例都可以有自己的bar
值。
有人可以给出更合理的解释为什么obj2和obj3是这样的吗?
当您声明构造函数Foo
时,Foo.prototype.constructor
会自动指向Foo
,console.log(Foo.prototype)
会显示,实际上这称为循环引用 ,递归遍历对象时应检测到的。但在您的情况下,Foo.prototype.constructor = 3
,幸运的是,new Foo()
表达式的过程不涉及Foo.prototype.constructor
属性,因此它将正确完成,但obj2.constructor
或Foo.prototype.constructor
或3
仍为Bar.prototype = 3
。
new Bar()
,我的理论是,当Bar.prototype
执行时,如第2步,创建的对象应该链接到Bar.prototype
,但是console.log(Object.prototype === Object.getPrototypeOf(obj3)); // true
的值不引用对象,隐式指定了默认值,即Object.prototype。
object.prototype.constructor
由于Object
引用了obj3.constructor
,Object
也引用了obj3
,但Bar
的事实< / em>构造函数仍为console.log(obj3.foo); // true
,因为第1步,import java.util.ArrayList;
public class Characters {
/* Fields */
private String name;
private String allegiance;
private String status;
private int seasonSeen;
/* Constructor */
public Characters(String name, String allegiance, String status, int seasonSeen) {
this.name = name;
this.allegiance = allegiance;
this.status = status;
this.seasonSeen = seasonSeen;
}
/* Methods */
public String getName() {
return name;
}
public String getallegiance() {
return allegiance;
}
public String getStatus() {
return status;
}
public int getseasonSeen() {
return seasonSeen;
}
}
也可以证明这一点。
更多信息:How objects are created when the prototype of their constructor isn't an object?
答案 1 :(得分:0)
您的理解几乎正确,除此之外:
不,构造函数是这样的:
function Foo(){
this.bar = true;
}
您在没有现有对象的情况下直接调用构造函数:
new Foo();
new Bar();
这只是一个函数调用。由于new
关键字,它有点特殊。所以,要稍微修改一下你的理解,我会采取你的描述并稍加改动:
new
关键字调用该函数,所以它被视为构造函数注意,在对构造函数本身的调用中创建构造函数时,对象无需搜索构造函数。对构造函数的调用是第一步,而不是第三步。
请注意,这是对对象构造方式的高级描述。有几个细节,例如this
如何处理被掩盖。
答案 2 :(得分:0)
例如,我明确地将Foo.prototype.constructor设置为某种东西 否则为obj2,但obj2仍然有属性栏。 [..]
在您的情况下,constructor
只是Foo
上的原型属性。对于obj2
来说,不 构造函数就像你所说的那样。 obj2
的构造函数为Foo
。通过将名为constructor
的属性应用于原型,您不会更改构造函数!
[..]但是让我们说吧存放在Foo的原型中, 这解释了为什么obj2有属性栏[..]
与您的信念相反,bar
未存储在Foo
的原型中。它是obj2
实例上存在的属性。它是一个实例属性而不是一个原型属性。您的案例中的原型属性为constructor
。
更清晰地看一下这些例子:
function Foo() {
this.bar = true;
}
var obj = new Foo();
console.log('The instance property "bar" is ' + obj.bar);
Foo.prototype.baz = 4;
console.log('The prototype property "baz" is ' + obj.baz);
Foo.prototype.bar = 5;
console.log('The prototype property "bar"=' + Foo.prototype.bar + ' is overridden by instance property "bar"=' + obj.bar);