首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对象是如何创建的?

对象是如何创建的?
EN

Stack Overflow用户
提问于 2017-01-24 07:15:57
回答 3查看 121关注 0票数 0

我试图了解原型和构造器是如何在JavaScript中工作的,并遇到了这种情况。

我总是想象在JavaScript中如何创建对象

  • 创建一个空对象。
  • 对象被链接到函数的原型
  • 对象搜索构造函数。
  • 该构造函数运行并将属性分配给该对象。
  • 对象由隐式return this返回。

这种理解方式似乎无法解释obj2obj3

例如,我显式地将Foo.prototype.constructor设置为obj2的其他东西,但是obj2仍然拥有属性bar。假设bar存储在Foo的原型中,这解释了为什么obj2拥有属性bar,为什么obj3是由Object创建的,但是如果我再创建几个obj2,这意味着它们在Foo的原型上共享相同的变量bar,我认为情况并非如此。

有人能更合理地解释一下为什么obj2obj3是这样的吗?

代码语言:javascript
复制
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);

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-01-25 04:56:52

我昨天看到你的帖子了,但当时我有点忙,现在我有空了,我想回答你的问题。

执行代码new Foo()时,会发生以下情况:

  1. 如前所述,函数Foo()被调用,因为函数是用new关键字调用的,因此它被视为构造函数,因此创建了一个空对象。
  2. 该对象链接到函数的原型,继承自Foo.prototype
  3. this绑定到新创建的对象。this.bar = true被执行。new Foo等价于new Foo(),即如果未指定参数列表,则调用Foo时不带参数。
  4. 构造函数返回的对象将成为整个新表达式的结果。如果构造函数没有显式返回对象,则使用在第一步中创建的对象。(通常构造函数不返回值,但如果要重写正常的对象创建过程,则可以选择返回。)

假设bar存储在Foo的原型中,这就解释了为什么obj2有属性条,为什么obj3是由对象创建的,但是如果我再创建几个obj2s,这意味着它们在Foo的原型上共享相同的变量条,我认为情况并非如此。

你是正确的。

barobj1obj2拥有的一个属性,例如:

代码语言:javascript
复制
console.log(obj1.hasOwnProperty("bar")); // true

但是,如果添加这样的属性:

代码语言:javascript
复制
Foo.prototype.bar2 = true;
console.log(obj1.hasOwnProperty("bar2")); // false

bar2的值由所有Foo实例共享,但是bar属性不是由Foo实例共享的,每个Foo实例可以有自己的bar值。

有人能更合理地解释一下为什么obj2和obj3是这样的吗?

  • obj2怎么了?

当您声明构造函数Foo时,Foo.prototype.constructor将自动指向Fooconsole.log(Foo.prototype)将显示实际上这是循环引用,在递归遍历对象时应该检测到循环引用。但是在您的例子中,Foo.prototype.constructor = 3,幸运的是,new Foo()表达式的过程不涉及Foo.prototype.constructor属性,因此它将被正确地执行,但是obj2.constructorFoo.prototype.constructor的值仍然是3

  • obj3怎么了?

Bar.prototype = 3,我的理论是,当new Bar()执行时,就像在步骤2中一样,创建的对象应该链接到Bar.prototype,但是由于Bar.prototype的值没有引用对象,所以隐式地分配了一个默认值,即Object.prototype。

代码语言:javascript
复制
console.log(Object.prototype === Object.getPrototypeOf(obj3)); // true

由于object.prototype.constructorObject的引用,obj3.constructor也引用了Object,但是obj3的实际构造函数仍然是Bar,因为步骤1也可以被console.log(obj3.foo); // true证明。

更多信息:How objects are created when the prototype of their constructor isn't an object?

票数 1
EN

Stack Overflow用户

发布于 2017-01-24 07:27:49

您的理解是几乎是正确的,但以下情况除外:

  • 对象搜索构造函数。

不,构造函数如下:

代码语言:javascript
复制
function Foo(){
  this.bar = true;
}

并且直接调用构造函数而不存在对象:

代码语言:javascript
复制
new Foo();
new Bar();

那只是个函数调用。因为new这个关键字,它有点特别。因此,为了修改一下您的理解,我将对您的描述做一些修改:

  • 函数被调用
  • 因为函数是用new关键字调用的,所以它被视为构造函数。
  • 创建一个空对象。
  • 对象被链接到函数的原型
  • 对象是通过隐式返回返回的

注意,在调用构造函数本身中创建构造函数时,对象根本不需要搜索构造函数。调用构造函数是第一步,而不是第三步。

请注意,这是对如何构造对象的非常高层次的描述。有几个细节,如如何对待this是被掩盖的。

票数 0
EN

Stack Overflow用户

发布于 2017-01-24 09:28:11

例如,我显式地将Foo.prototype.constructor设置为obj2的其他东西,但是obj2仍然拥有属性条。。。

在您的例子中,constructor只是Foo上的一个原型属性。它不是您所称的obj2的构造函数。obj2的构造函数是Foo。通过将名为constructor的属性应用于原型,您不会更改构造函数!

。。但假设bar存储在Foo的原型中,这就解释了为什么obj2有属性条。

与您的想法相反,bar不是存储在Foo的prototype中,它是存在于obj2实例上的一个属性,它是一个实例属性而不是一个原型属性。在您的示例中,原型属性是constructor

为了更清晰起见,请看下面的例子:

代码语言:javascript
复制
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);

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41822188

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档