4

我正在尽我所能理解javascript。这是 Chrome 控制台中的一个简单实验,让我非常困惑:

var foo=function(){this.p=1;}
foo.prototype.p=2;
var bar=new foo();
//foo{p:1,p:2} <- this is the output of Chrome console, from the last command above

Chrome 的输出让我感到困惑。看起来 bar 是一个有 2 个参数的对象,p:1 和 p:2。这是否意味着 bar 有 2 个 p???这背后的原因是什么?

4

5 回答 5

2

bar 对象只有一个 p 值为 1

可以在只读对象中查看早期值为 2 的 p ,您可以使用getPrototypeOf访问该对象:

Object.getPrototypeOf(bar).p

您会看到两者,因为开发人员工具栏旨在打印指定对象的 XML 表示形式,该表示形式应直观地显示所有属性,无论是否可直接访问。

于 2013-09-15T10:30:17.710 回答
2

是的。有点。

bar两者都有:

  • 自己p财产。

    bar.hasOwnProperty('p'); // true
    bar.p;                   // 1
    
  • p仍然保留prototype通过继承的属性上的属性。

    Object.getPrototypeOf(bar).p; // 2
    

但是,一次只能直接访问其中bar的一个,优先于自己的财产。

bar.p;        // 1
delete bar.p;
bar.p;        // 2

而且,Chrome 展示了这两者,因为它正在遍历原型链并寻找任何可枚举的属性。

于 2013-09-15T10:32:03.123 回答
2

Chrome DevTools 控制台的内联(非扩展)对象表示目前不显示自己的属性和继承的原型属性之间的任何差异。

现在让我们把正在发生的事情分解成更小的步骤。

new foo()创建一个内部proto属性指向的新对象foo.prototype。这意味着该对象可以访问foo.prototype. 它被称为原型链

现在,当您在对象中设置同名的属性时,它会以相同的名称“遮蔽”原型的属性,从而通过常规属性访问使后者无法访问(请参阅@loxxy 的答案,Object.getPrototypeOf(obj)用于访问遮蔽的原型属性)。

向对象或其原​​型添加函数后,控制台允许您显示扩展对象表示,这确实不同于原型属性的自身属性。在下一个示例中,我q向原型添加了一个方法来允许这种行为。从原型继承的属性显示在对象的proto内部属性中:

在此处输入图像描述


如果您只想在构造函数的原型中拥有实例对象的数量,您可以使用:

var foo = function() {
    Object.getPrototypeOf(this).p++;
}
foo.prototype.p = 0;

console.log(new foo()); //{p: 1}
console.log(new foo()); //{p: 2}

或者没有 ES5 依赖:

var foo = function() {
    foo.prototype.p++;
}
foo.prototype.p = 0;

console.log(new foo()); //{p: 1}
console.log(new foo()); //{p: 2}
于 2013-09-15T10:33:31.023 回答
1

var foo=function(){this.p=1;}是构造函数并在之后执行var bar=new foo();。所以在开始时 p=2 然后 p 变为 1。所以:

var foo=function(){
   // here this.p is equal to 2
   this.p=1;
   // here this.p is equal to 1
}
foo.prototype.p=2;
var bar=new foo();

编辑:

JSON.stringify(bar);
于 2013-09-15T10:23:33.570 回答
1

当您访问一个属性时,javascript 引擎将在对象实例上查找它,然后在其所有原型链上查找。
因此,p 作为原型属性的含义是为 p 提供一个默认值,无论您是否在类的任何实例上定义它。一个示例可能是车辆的车轮数,例如,默认为 4。
如果稍后您写入此属性:

 function Vehicle() {};
 Vehicle.protoype.wheelCount = 4;
 var myBike = new Vehicle();
 myBike.wheelCount = 2 ;           // this is a bike.

您不会更改原型上设置的值,而是会在实例上创建一个具有新值的新属性,例如:

 var myCar = new Vehicle();
 myCar.wheelCount // === 4

现在您提到的场景 - 设置默认值,并在构造函数中设置实例值 - 没有多大意义,因为您必须使用 Object.getPrototypeOf 才能达到默认值。这只是一种没有用的可能性,就像所有语言都有很多一样。

于 2013-09-15T10:39:26.280 回答