因此,父类Select
将this.elem
声明为DOM元素<select>
和this.value
,它们链接到选定选项的值
class Select {
constructor(classList, isTwoLevel, index){
this.elem = document.createElement("select")
this.value = this.elem.children[this.elem.selectedIndex].value;// error here!
}
}
子类MySelect
添加选项,为其分配值,并将其附加到this.elem
。
class MySelect extends Select {
constructor(){
super();
let opt1 = document.createElement("option");
opt1.value = "foo";
this.elem.appendChild(opt1);
let opt2 = document.createElement("option");
opt2.value = "bar";
this.elem.appendChild(opt2);
}
}
按预期,在创建MySelect类的新示例时,会发生错误:
let testSelect = new MySelect(); // Uncaught TypeError: Cannot read property 'value' of undefined
document.body.appendChild(testSelect.elem);
我不想将this.value的声明移到子类中,因为它应该是所有子类的通用属性,我该怎么办?
答案 0 :(得分:4)
您可以将value
变成吸气剂:
class Select {
constructor(classList, isTwoLevel, index){
this.elem = document.createElement("select")
}
get value() {
return this.elem.children[this.elem.selectedIndex].value;
}
}
class MySelect extends Select {
constructor(){
super();
let opt1 = document.createElement("option");
opt1.value = "foo";
this.elem.appendChild(opt1);
let opt2 = document.createElement("option");
opt2.value = "bar";
this.elem.appendChild(opt2);
}
}
const testSelect = new MySelect();
document.body.appendChild(testSelect.elem);
console.log(testSelect.value);
您也可以在首次访问实例时直接在实例上分配属性,以提高性能,从而使getter仅运行一次:
class Select {
constructor(classList, isTwoLevel, index){
this.elem = document.createElement("select")
}
get value() {
console.log('getter running');
const theValue = this.elem.value;
Object.defineProperty(this, 'value', { value: theValue });
return theValue;
}
}
class MySelect extends Select {
constructor(){
super();
let opt1 = document.createElement("option");
opt1.value = "foo";
this.elem.appendChild(opt1);
let opt2 = document.createElement("option");
opt2.value = "bar";
this.elem.appendChild(opt2);
}
}
const testSelect = new MySelect();
document.body.appendChild(testSelect.elem);
console.log(testSelect.value);
console.log(testSelect.value);
您还可以简化
this.elem.children[this.elem.selectedIndex].value;
到
this.elem.value;
如果需要。这也回避了{-1的selectedIndex
抛出错误(value
是空字符串)的问题:
class Select {
constructor(classList, isTwoLevel, index){
this.elem = document.createElement("select")
}
get value() {
console.log('getter running');
const theValue = this.elem.value;
Object.defineProperty(this, 'value', { value: theValue });
return theValue;
}
}
class MySelect extends Select {
constructor(){
super();
let opt1 = document.createElement("option");
opt1.value = "foo";
this.elem.appendChild(opt1);
let opt2 = document.createElement("option");
opt2.value = "bar";
this.elem.appendChild(opt2);
}
}
const testSelect = new MySelect();
document.body.appendChild(testSelect.elem);
console.log(testSelect.value);
console.log(testSelect.value);
答案 1 :(得分:2)
这些不是声明,它们只是赋值。
如果您想在父级使用value
,但是在子类完成初始化之前没有要分配的值,则可以:
在父级别将其分配给null
,然后再为其分配另一个值,或者
将选择的选项传递到父构造函数中,或
将value
作为访问者属性(获取器)设为CertainPerformance pointed out。
答案 2 :(得分:0)
这是对先前答案的稍微修改的方法。如果将cfg
对象传递给类,则可以选择要绑定的元素的哪些属性。此代码段还添加了一个事件处理程序,以演示value属性的绑定。
属性的绑定已移至其自己的方法。
对代码的改进可能包括检查以确保元素上的属性首先存在。
class Select {
constructor(cfg){
this.elem = document.createElement("select")
this.bindProps(cfg.bindProps)
}
bindProps(props){
if( !props ) return;
props.forEach((prop) => {
Object.defineProperty(this, 'value', {
get: () => this.elem[prop],
set: (val) => this.elem[prop] = val
})
})
}
}
class MySelect extends Select {
constructor(cfg){
super(cfg);
let children = [
{ label: 'Foo', value: 'foo' },
{ label: 'Bar', value: 'bar' }
]
children.forEach(({label, value}) => {
let opt = document.createElement("option");
opt.label = label;
opt.value = value;
this.elem.appendChild(opt);
})
}
}
const testSelect = new MySelect({bindProps: ['value']});
document.body.appendChild(testSelect.elem);
testSelect.elem.addEventListener('change', (evt) => {
console.log('testSelect.elem.value', testSelect.elem.value);
console.log('testSelect.value', testSelect.value);
})