是对象的Prototype属性,是一个对象吗?

时间:2015-06-08 16:49:28

标签: javascript

我已经阅读了很多关于对象原型属性的精彩文章和讨论(如this one),但这里有一个很大的问题。当我们观察“ prototype ”属性的行为时,我们意识到它实际上是另一个对象。我们可以看到它有一个像对象一样的 proto 和构造函数属性。

var myobj= function(){};
myobj.prototype.constructor== myobj  --> true

所以这些是问题:

  1. “原型”本身是一个对象吗?
  2. 原型与其相关的对象(在本例中为 myobj )之间的关系是什么?
  3. 为什么 myobj.prototype .__ proto __ 默认为“对象{} ”但其构造函数为 myobj
  4. 我们知道:“__proto__是查找链中用于解析方法等的实际对象。 prototype 是用于构建 {{的对象1}} 使用 new “创建对象时。但我们可以看到,这不仅仅是原型的作用。我认为: Prototype就像对象的所有共享方法和属性的容器对象!然后,当使用 new 创建对象的实例时,其内部[ [Prototype]]指向原型,其中类的共享行为和属性暴露给实例! 这是真的吗?
  5. 最后:看来,当我们实例化一个类时,实例的构造函数被设置为该对象原型的构造函数。这个结论能否成立?

    __proto__

2 个答案:

答案 0 :(得分:5)

  1. 是的,原型对象是一个对象。它与函数一起隐式构造。
  2. 我不会称之为“父母”。他们唯一的关系是myobj函数确实有.prototype属性,原型对象作为其值。
  3. 原型对象继承自Object.prototype。它有一个自己的.constructor属性,其myobj函数作为其值。 (It's really just a property
  4. 是的,这是事实。 .__proto__是内部[[Prototype]]字段的非标准访问器。因此,它们通常被用作同义词。
  5. 不,在构造实例时,未设置.constructor属性。所有发生的事情是新实例继承自原型对象,而原型对象具有constructor属性。请注意,示例中的myobj.prototype={};对先前构造的实例没有影响。

答案 1 :(得分:1)

我知道有一个公认的答案,但似乎对原型是什么,构造函数是什么以及它们如何相互作用存在一些混淆。

以此对象为例:

var foo = {
  bar : 'hello',
  sayBar : function(){
    alert(this.bar);
  }
};

您可以照原样使用它,就像您期望的那样。您可以重新分配foo.bar并使用sayBar方法,而不会出现任何问题:

foo.bar = 'Goodbye';
foo.sayBar(); //alerts(Goodbye);

现在说你需要拥有一堆所有需要bar属性但具有不同值的对象。这时你可以创建一个构造函数来创建唯一的实例:

var fooClass = function(newbar){
  this.bar = newbar;
};

可以像这样调用:

var myFoo = new fooClass('baz');
console.log(myFoo.bar); //logs 'baz'

这可以在幕后分解:

var fooClass = function(newbar){
  //**IF 'new' is declared ** create an instance object, for now it has no declared prototype other than Object's base prototype
  //That instance of the prototype is now scoped to 'this'

  //it sets the 'constructor' of the instance behind the scenes      
  //this.constuctor = [our constructor function]

  // now we can assign values to our instance and invoke it's methods

  this.bar = newbar;
  // our instance now has a key 'bar' that has the value of newbar


  // so our instance now looks like this:
  //
  // { 
  //  bar : [newbar]
  // }


  // return our instance object { bar : [newbar] }
};

这是原型对象发挥作用的地方。我们将foo对象用作fooClass原型:

var fooClass = function(newbar){
  this.bar = newbar;
};

fooClass.prototype = foo;

现在,正如您所期望的那样,您可以使用foo的方法:

var myFoo = new fooClass('baz');
myFoo.sayBar(); //alerts baz

现在这是构造函数正在做的事情:

var fooClass = function(newbar){
  //**IF 'new' is declared ** create an instance object, which uses foo as it's prototype
  //That instance of the prototype is now scoped to 'this'

  //it sets the 'constructor' of the instance behind the scenes      
  //this.constuctor = [our constructor function]

  // now we can assign values to our instance and invoke it's methods

  this.bar = newbar;
  // we have now overridden foo's default foo.bar with our instance bar


  // so our instance now looks like this:
  //
  // { 
  //  bar : [newbar], //overridden in constructor
  //
  //  //with access to foo's methods through the prototype chain
  //  sayBar : function(){
  //    alert(this.bar);
  //  }
  // }


  // return our instance object
};

没有什么神奇的事情发生,所有构造函数都在做的是创建并返回一个对象实例,所有.prototype =正在做的就是为该对象设置原型。

如果忘记'新'会怎样?

如果在使用构造函数时不使用new,则不会创建或返回新的对象实例。这就是为什么经常检查你的当前实例是否具有正确的构造函数:

var fooClass = function(newbar){
  if(!(this instanceof fooClass)){ //if this constructor != fooClass
    return new fooClass(newbar); //refire constructor with 'new'
  }

  //...
};