我正在尝试使用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文档中,您将看到问题所在。黄色矩形应该在红色矩形内!
任何人都知道会发生什么?
答案 0 :(得分:1)
浏览代码时,我怀疑问题是Grid
和GridPart
的每个实例共享相同的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());
}
}
答案 1 :(得分:1)