如何创建对象?

时间:2017-01-24 07:15:58

标签: javascript

我正在尝试理解原型和构造函数在JavaScript中是如何工作的,并且遇到了这种情况。

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

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

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

例如,我明确将Foo.prototype.constructor设置为obj2的其他内容,但obj2仍然具有属性bar。假设bar存储在Foo的原型中,这解释了为什么obj2具有属性bar以及为什么obj3Object创建,但是如果我创建了该怎么办?还有几个obj2 s,这意味着他们在Foo的原型上共享相同的变量bar,我认为情况并非如此。

有人可以对obj2obj3这样的原因做出更合理的解释吗?

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);

3 个答案:

答案 0 :(得分:1)

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

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

  1. 函数Foo()被调用,正如@slebetman所提到的,因为函数是用new关键字调用的,所以它被视为构造函数,创建一个空对象。

  2. 该对象链接到函数的原型,继承自Foo.prototype

  3. this绑定到新创建的对象。 this.bar = true已执行。 new Foo相当于new Foo(),即如果没有指定参数列表,则不带参数调用Foo。

  4. 构造函数返回的对象成为整个新表达式的结果。如果构造函数未显式返回对象,则使用在第一步中创建的对象。 (通常构造函数不返回值,但如果他们想要覆盖正常的对象创建过程,他们可以选择这样做。)

  5.   

    让我们说bar存储在Foo的原型中,这解释了为什么obj2具有属性栏以及为什么obj3是由Object创建的,但是如果我创建了几个obj2s,这意味着它们在Foo的原型上共享相同的变量栏,我认为情况并非如此。

    你是对的。

    bar是由obj1obj2拥有的财产,例如:

    console.log(obj1.hasOwnProperty("bar")); // true
    

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

    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.constructor3仍为Bar.prototype = 3

    • obj3发生了什么事?

    new Bar(),我的理论是,当Bar.prototype执行时,如第2步,创建的对象应该链接到Bar.prototype,但是console.log(Object.prototype === Object.getPrototypeOf(obj3)); // true 的值不引用对象,隐式指定了默认值,即Object.prototype。

    object.prototype.constructor

    由于Object引用了obj3.constructorObject也引用了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);