我有一个大型项目,我需要截取到element.src,element.href,element.style等内容的赋值。我想用 defineSetter 来做这个,但它表现得非常奇怪(使用Chrome 8.0.552.231)
一个例子:
var attribs = ["href", "src", "background", "action", "onblur", "style", "onchange", "onclick", "ondblclick", "onerror", "onfocus", "onkeydown", "onkeypress", "onkeyup", "onmousedown", "onmousemove", "onmouseover", "onmouseup", "onresize", "onselect", "onunload"];
for(a = 0; a < attribs.length; a++) {
var attrib_name = attribs[a];
var func = new Function("attrib_value", "this.setAttribute(\"" + attrib_name + "\", attrib_value.toUpperCase());");
HTMLElement.prototype.__defineSetter__(attrib_name, func);
}
此代码应该做的是在指定attribs中的公共元素属性时,它使用setAttribute()来设置该属性的大写版本。
出于一些非常奇怪的原因,setter仅适用于约1/3的任务。
例如
element.src = "test"
新的src是“TEST”,就像它应该是
然而
element.href = "test"
新的href是“test”,而不是大写
然后即使我尝试element.__lookupSetter__("href")
,它也会返回正确的大写设置器
最奇怪的是Chrome和Firefox之间正确拦截了不同的变量
帮助!
答案 0 :(得分:2)
这不是一个好主意。主机对象(例如DOM元素)不受适用于本机JavaScript对象的通常规则的约束,并且基本上可以执行它们喜欢的操作,并且所有浏览器都或多或少地利用了这一事实。浏览器没有义务为宿主对象提供原型,也没有义务允许您覆盖宿主对象属性的getter和setter,或者尊重任何覆盖默认行为的尝试。
我强烈建议放弃这种方法,而是采用不同的方法,例如为DOM元素编写包装器对象。
更新:包装器方法示例
您可以为DOM元素创建包装器对象,并通过这些包装器执行所有DOM操作。这是许多库(例如YUI)所做的事情。例如:
function ElementWrapper(el) {
this.domElement = el;
}
ElementWrapper.prototype = {
// Wrap the DOM methods you need
appendChild: function(child) {
this.domElement.appendChild(child);
},
// Add custom behaviour, such as converting certain
// property values to upper case
setProperty: function(name, value) {
if (/^(src|href|action)$/i.test(name)) {
this.domElement[name] = value.toUpperCase();
} else {
this.domElement[name] = value;
}
}
};
var wrappedEl = new WrappedElement( document.getElementById("foo") );
wrappedEl.setProperty("href", "http://www.google.com/");
答案 1 :(得分:2)
如果你等待WebIDL完全定义DOM的ECMAScript绑定,那么回应Tim Down并加上我自己的两分钱,你将会以更加跨浏览器,符合标准的方式获得更好的运气。在那一点覆盖应该给你精确,明确的行为。但是现在你会变得奇怪。