2017-01-24 66 views
0

我想了解原型和构造函数如何在JavaScript中工作,并遇到这种情况。如何创建对象?

我总是想象的对象是怎么在JavaScript创建由

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

这种理解方式似乎不能解释obj2obj3

例如,我明确将Foo.prototype.constructor设置为obj2的其他值,但obj2仍具有属性bar。比方说,bar存储在Foo的原型,这可以解释为什么obj2拥有财产bar为什么被Object创建obj3,但如果我创建一对夫妇更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);

+0

http://stackoverflow.com/questions/572897/how-does-javascript-prototype-work – Abhitalks

+0

JavaScript对象本质上是包含属性变量(内容或以其他方式) - 这些属性可以是方法,或者只是值。原型(Object.prototype.prototype)修改这些属性。 – Crowes

+0

@Abhitalks如果你确实看过我说过的话,你就会知道我已经明白你的链接在说什么了。第二个要点我已经在谈论链接'__proto__',我只是没有明确地写'__proto__'或'[[Prototype]]'。 – kevguy

回答

1

我昨天看了你的帖子,但我当时有点忙,现在我自由了,我会喜欢回答你的问题。

当执行代码new Foo(),下面的事情发生:

  1. 函数foo()被调用时,如@slebetman提到的,由于函数被调用与new关键字然后它被当作一个构造函数,创建一个空对象。

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

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

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

比方说,巴存储在Foo的原型,这可以解释为什么obj2有属性栏,为什么obj3是由Object创建的,但是如果我创建了更多的obj2s,这意味着它们会在Foo的原型上共享相同的变量条,我认为情况并非如此。

你说得对。

barobj1obj2拥有的物业,例如:

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

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

Foo.prototype.bar2 = true; 
console.log(obj1.hasOwnProperty("bar2")); // false 

bar2值由所有Foo共享实例,但bar属性不被Foo实例共享,每个Foo实例可能拥有自己的值为。

有人可以给出更合理的解释,为什么obj2和obj3是这样的?

  • obj2发生了什么事?

在声明构造FooFoo.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。

console.log(Object.prototype === Object.getPrototypeOf(obj3)); // true 

由于object.prototype.constructor的参考Objectobj3.constructor同时参阅Object,但obj3事实上构造仍然是Bar,由于步骤1,其也可以通过证明console.log(obj3.foo); // true

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

+0

关于'obj3',我认为它是'Number'好像是'3'被装箱到一个对象,但事实并非如此。显然,这个任务不会被忽略,否则构造函数将仍然是'Bar'。然后我想知道原型是如何变成“Object”的。我已经在Firefox Chrome Safari中测试过,它们的表现都一样。所以我认为这应该是ECMA-262中明确规定的内容。但是,我没有找到正确的地方。你能否提供更多关于内部机制的信息? – Leo

+0

@Leo这是我的理论,但我找不到任何文件来支持它,所以我问这个问题 - http://stackoverflow.com/questions/41846565/how-objects-are-created-when -the-prototype-of-their-constructor-is-a-primitive-n –

+0

@Leo我认为它就像'自动创建全局变量'一样,但是你知道,在严格模式下,它不会抛出错误。 –

0

你的理解是除了这几乎正确的:

  • 一个构造函数

没有对象的搜索,构造函数是这样的:

function Foo(){ 
    this.bar = true; 
} 

而你直接调用构造函数不存在的对象:

new Foo(); 
new Bar(); 

这只是一个函数调用。这有点特殊,因为关键词new。因此,修改你的理解有点我要带你的描述,并改变了一点:

  • 一个函数被调用
  • ,因为函数被调用,new关键字,然后它被视为构造
  • 创建一个空的对象
  • 的对象链接到该函数的原型
  • 对象是由隐式返回该
返回

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

请注意,这是对如何构建对象的非常高级的描述。有几个细节比如如何处理this

+0

我知道当你执行'new Foo()'时,'this'将被设置为创建的对象,如果该函数没有'return'语句,则会在函数结尾处隐含'return this'。所以你说的还有更多呢? @slebetman – kevguy

0

例如,我明确地将Foo.prototype.constructor设置为 其他的obj2,但obj2仍然有属性栏。 [..]

您的情况constructor只是Foo的原型属性。它是而不是构造函数对于obj2,你可以称之为它。 构造函数对于obj2Foo。通过将名为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);