简体   繁体   English

Javascript实例化的意外结果

[英]Unexpected Result in Javascript Instanciation

I'm trying to create a grid using javascript prototype inheritance, however there is a problem I could not understand. 我正在尝试使用javascript原型继承来创建网格,但是存在我无法理解的问题。 In some point of the code the "new" keyword seems not work. 在代码的某些方面,“ new”关键字似乎无效。

It's hard to explain, so the code are below and I put comments in the main points. 很难解释,因此代码在下面,我在要点中添加了注释。

<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>

If you copy and past this code into a html document you will see the problem. 如果您将此代码复制并粘贴到html文档中,将会看到问题。 The yellow rectangle should be inside of the red rectangle! 黄色矩形应该在红色矩形的内部!

Anyone knows what happens? 有人知道会发生什么吗?

Glancing over your code, I suspect the problem is that every instance of Grid and GridPart share the same components object. 浏览您的代码,我怀疑问题是GridGridPart每个实例共享相同的components对象。 You could verify this by having a look at the prototype chain or check the result of grd.getComponent('body').components === grd.getComponent('foot').components . 您可以通过查看原型链来验证这一点,或者检查grd.getComponent('body').components === grd.getComponent('foot').components

Don't do something like 不要做类似的事情

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

it adds instance specific properties to the prototype, so all instances share the same instance specific properties (like components ). 它将特定实例的属性添加到原型中,因此所有实例共享相同的特定于实例的属性(如components )。 Instead, use Object.create to establish inheritance: 而是使用Object.create建立继承:

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

and call the parent constructor inside the the child constructor: 并在子构造函数中调用父构造函数:

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

Properties that are instance specific should be set in the constructor, properties that should be shared are set on the prototype. 实例特定的属性应在构造函数中设置,应共享的属性应在原型上设置。 So in your case you should do Container.prototype. ContainerAddComponent = ContainerAddComponent; 因此,在您的情况下,您应该执行Container.prototype. ContainerAddComponent = ContainerAddComponent; Container.prototype. ContainerAddComponent = ContainerAddComponent; .

See also Benefits of using `Object.create` for inheritance 另请参见使用Object.create进行继承的好处


If you are already able to use ES6, use the new class syntax: 如果您已经可以使用ES6,请使用新的class语法:

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

The problem is not that the new keyword is not working anymore but rather it lies in the following line: GridPart.prototype = new Container('grd-part'); 问题不在于new关键字不再起作用,而是在于以下行: GridPart.prototype = new Container('grd-part');

What it does is cause all GridPart objects to have the same this.components object. 它的作用是使所有GridPart对象具有相同的this.components对象。

So when you call this.addComponent inside the GridPart constructor function you override the same this.components object at index 'comp' with a new Container object 因此,当您在GridPart构造函数中调用this.addComponent ,将在索引'comp'处的相同this.components对象替换为新的Container对象

I've found a way to achieve the inheritance you are looking for here and integrated this solution into your code. 我已经找到一种方法来实现您在此处寻找的继承并将此解决方案集成到您的代码中。

here is a working codepen 这是一个有效的codepen

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM