我正在尝试“扩展”(不确定这种扩展的正确用语是什么)覆盖某些属性的DOMElement (基本元素)。为此,我动态创建一个函数,其原型是我想要扩展的DOMElement,然后用该函数实例化一个对象(扩展元素)。
为扩展元素赋值时,预期结果是在扩展元素中创建具有给定名称的属性,保持基本元素不变,即使它具有属性那个名字。使用普通对象作为基本元素可以完美地工作,但是当使用DOMElement作为基本元素时,如果存在同名属性,则会修改基本元素(在Chrome和Firefox上。即使尝试获取属性的值,IE9也会抛出“无效的调用对象”。
var base = $("<input type='text' />")[0];
//Plain object example: var base = {value:null}
base.value = "original";
var MyClass = function(){ };
MyClass.prototype = base;
var obj = new MyClass();
obj.value = "modified";
obj.value //"modified" (OK)
base.value //"modified" (WRONG!) - "original" if plain object is used (OK)
我打算做的是创建一个带有覆盖“value”属性的输入元素的扩展实例。这将允许将此对象传递给验证器插件,该插件将使用重写的值来运行其所有验证规则,并且在任何错误的情况下原始对象将保持完整,并且扩展的对象将由验证器完成所有修改。
由于IE中可能无法解决的异常,我们不打算进一步应用这种方法,但我仍然对这种奇怪的行为感兴趣。
我认为这个行为来自事实,而不是DOMElement属性和函数不是纯粹的Javascript,而是浏览器实现的Interface的说明。这样会影响原型“继承”在这种情况下的工作方式,使得值的本机setter实现代替在扩展对象上创建属性。 (这可以通过IE中抛出的异常来支持,声明我正在尝试从非本机元素访问本机函数/属性。)
答案 0 :(得分:1)
这似乎已经成功了:
var base = $("<input type='text' />")[0];
base.value = "original";
function MyClass() {
Object.defineProperty(this, "value", {
value: null,
configurable: true,
enumerable: true,
writable: true
});
}
MyClass.prototype = base;
var obj = new MyClass();
obj.value = "modified";
console.log(obj.value); //"modified" (OK)
console.log(base.value); //"original" (OK)
问题是您的obj
实例从未拥有自己的value
:它总是委托给原型的setter,即HTMLInputElement.prototype.value
。因此obj
的所有实例都会共享同一个value
属性。
换句话说,说obj.value = "modified"
与说Object.getPrototypeOf(obj).value = "modified"
,当然还有Object.getPrototypeOf(obj) === base
相同。
我的第一次尝试是给MyClass
自己的每个实例value
属性,如下所示:
function MyClass() {
this.value = null;
}
但实际上这并不是我们想要的,因为this.value
只引用了原型的value
:我们没有创建新的属性;我们正在设置现有的。 Object.defineProperty
使我们想要创建一个新的运行时非常明确,所以这就是诀窍。