2014-08-27 51 views
-1

我想创建一个使用javascript原型继承的网格,但有一个问题,我不明白。在代码的某些部分,“新”关键字似乎不起作用。在Javascript Instanciation意外的结果

这很难解释,所以代码如下,我把意见放在要点上。

<head> 
    <!-- this is the "parent class" --> 
    <script type='text/javascript'> 
     // constructor 
     function Container(CSSClassName) { 
      this.CSSClassName = CSSClassName; 
      this.build = ContainerBuild; 

      this.components = new Object(); 

      this.addComponent = ContainerAddComponent; 
      this.getComponent = ContainerGetComponent; 
     } 

     /* 
     * methods 
     */ 

     function ContainerAddComponent(id, component) { 
      this.components[id] = component; 
     } 

     function ContainerGetComponent(id) { 
      return this.components[id]; 
     } 

     function ContainerBuild() { 
      this.element = document.createElement('div'); 
      this.element.className = this.CSSClassName; 

      for (var i in this.components) { 
       this.element.appendChild(this.getComponent(i).build()); 
      } 

      return this.element; 
     } 
    </script> 

    <!-- Below I'm using prototype inheritance --> 
    <script type='text/javascript'> 
     Grid.prototype = new Container('grd'); 
     function Grid() { 
      this.addComponent('body', new GridPart()); 
      this.addComponent('foot', new GridPart()); 
     } 

     GridPart.prototype = new Container('grd-part'); 
     function GridPart() { 
      this.addComponent('comp', new Container('comp')); // this new keywork seems not to work. 

      /* ***** I tried this code, but the result was the same. 
      var comp = new Container('comp'); 
      this.addComponent('comp', Object.create(comp)); // same unexpected result. 
      */ 
     } 

     window.onload = function() { 
      var grd = new Grid(); 
      document.getElementById('grd').appendChild(grd.build()); 

      grd.getComponent('body').element.style.background = 'red'; // ok! 
      grd.getComponent('body').getComponent('comp').element.style.background = 'gold'; // unexpected behavior 

      // Testing the objects. 
      console.log(grd.getComponent('body') === grd.getComponent('foot')); // false, ok! 
      console.log(grd.getComponent('body').getComponent('comp') === grd.getComponent('foot').getComponent('comp')); // true?? should be false! 
     } 
    </script> 

    <style type='text/css'> 
     .grd { border: 1px solid black } 
     .grd-part { 
      height: 25px; 
      padding: 12px; 
      border-bottom: 1px solid black; 
     } 
     .grd-part:last-child { border:none } 
     .grd-part .comp { 
      background: black; 
      height: 25px; 
     } 
    </style> 
</head> 
<body> 
    <div id='grd'></div> 
</body> 

如果您将此代码复制并过滤到html文档中,您将会看到问题。黄色矩形应该在红色矩形内!

任何人都知道会发生什么?

回答

1

纵观您的代码,我怀疑问题是GridGridPart的每个实例共享相同的components对象。您可以通过查看原型链或检查grd.getComponent('body').components === grd.getComponent('foot').components的结果来验证此情况。

不要做类似

Grid.prototype = new Container('grd'); 

它增加了例如特定性质的原型,因此所有实例共享相同的实例特定的属性(如components)。相反,使用Object.create建立继承:

Grid.prototype = Object.create(
    Container.prototype, 
    {constructor: {value: Grid, configurable: true, writable: true}} 
); 

,并调用父类的构造函数的孩子构造函数中:

function Grid() { 
    Container.call(this, 'grd'); 
    this.addComponent('body', new GridPart()); 
    this.addComponent('foot', new GridPart()); 
} 

属性是特定于实例应在构造函数中设置,属性应共享在原型上设置。所以在你的情况下,你应该做Container.prototype. ContainerAddComponent = ContainerAddComponent;

又见Benefits of using `Object.create` for inheritance


如果你已经能够使用ES6,使用新的class语法:

class Grid extends Container { 
    constructor() { 
     super('grd'); 
     this.addComponent('body', new GridPart()); 
     this.addComponent('foot', new GridPart()); 
    } 
} 
+0

谢谢!现在我知道如何使用Object.create进行继承了!我已经尝试过但没有成功。谢谢你的回答,它解决了我的问题。我也会看到关于ES6的。我不知道它已经可用了!谢谢:) – jairhumberto 2014-08-27 15:21:34

+1

我认为任何浏览器都不支持类语法,但有些转换工具会将其转换为有效的ES5代码。例如http://www.phpied.com/writing-es6-today-with-jstransform/ – 2014-08-27 15:22:37

1

的问题不在于new关键字不工作了,而是它位于以下行: GridPart.prototype = new Container('grd-part');

它做什么是cau全部GridPart对象具有相同的this.components对象。

所以,当你调用this.addComponentGridPart构造函数里面,你在指数'comp'用新Container对象

我已经找到一种方法来实现你正在寻找here 和综合继承覆盖相同this.components对象这个解决方案进入你的代码

这里是工作codepen