Javascript Instaunction中出现意外结果

Unexpected Result in Javascript Instanciation

本文关键字:意外 结果 Instaunction Javascript      更新时间:2023-09-26

我正试图使用javascript原型继承创建一个网格,但有一个问题我无法理解。在代码的某些地方,"new"关键字似乎不起作用。

这很难解释,所以代码在下面,我在要点中添加了注释。

<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文档中,您将看到问题。黄色矩形应该在红色矩形的内部!

有人知道会发生什么吗?

仔细查看您的代码,我怀疑问题在于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;

另请参阅使用`Object.create`进行继承的好处


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

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

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

它的作用是使所有GridPart对象都具有相同的this.components对象。

因此,当您在GridPart构造函数内调用this.addComponent时,您可以用新的Container对象覆盖索引'comp'处的相同this.components对象

我找到了一种方法来实现你在这里寻找的遗产并将此解决方案集成到您的代码中。

这是一个工作代码笔