我正在阅读有关在javascript中扩展本机对象的一些讨论。在当前浏览器中扩展本机对象似乎比以前少得多。当然,我们可以通过以下方法更好地控制对象的扩展:
Object.defineProperty(<some parameters...>)
然而,存在的一个巨大风险是不同代码/库之间的冲突,导致意外行为。
命名冲突(和全局崩溃)的风险可以通过命名自己的函数来减少。所以我想如果扩展原生对象,为什么我们不这样做呢?当然执行上下文是一个问题,但我们可以使用bind()来解决这个问题,使我们的扩展功能中可以使用该对象的本机函数。所以我创建了以下内容来扩展Element对象:
// Define the extend function
Object.defineProperty(Element.prototype, 'extend', { value: function(namespace, object) {
var cache = {};
// Create the namespace and make sure on invocation the Element is bound
Object.defineProperty(Element.prototype, namespace, { value: function() {
var objectCheck = typeof cache[Element.prototype.constructor.name] !== 'undefined';
if(objectCheck && typeof cache[Element.prototype.constructor.name][namespace] !== 'undefined'){
console.log('cache used');
return cache[Element.prototype.constructor.name][namespace];
} else {
var extended = Element.prototype[namespace].extended;
for (var e in extended) {
extended[e] = extended[e].bind(this);
}
if(!objectCheck)
cache[Element.prototype.constructor.name] = {};
cache[Element.prototype.constructor.name][namespace] = extended;
}
return extended;
}});
this[namespace].extended = object;
return this;
}});
// Extend the Element prototype with an attr function in
// the namespace 'namespace' or ofcourse whatever function
Element.prototype.extend('namespace',{
attr: function(name, value) {
if(arguments.length === 1) {
return this.getAttribute(name);
} else {
this.setAttribute(name, value);
return this;
}
}
});
当在实际元素上查看它时看起来很好,命名空间就在那里,在里面我们发现我们的&#39; attr&#39;功能。我们可以像这样调用它:
document.querySelector('.a-css-class').namespace().attr('class')
// returns 'a-css-class'
可以进一步重构代码以动态扩展各种对象。但是,我很好奇,这对性能意味着什么,这个实验有意义吗?主要问题是,这比直接延伸更好吗?
编辑(基于Bergi关于表现的评论):
可以在外部函数中缓存创建的函数。让我们看看我是否可以提出一个实现。
编辑2:
添加了一个简单的缓存函数,以确保在每次调用时都不会创建所有命名空间方法。
编辑3:
更新的代码。为了使扩展本机对象更安全,生成了以下代码。它可能会阻止命名冲突。谢谢@Bergi:
/**
* Extend a (NATIVE) object with a namespace. See below for an example
*/
Object.defineProperty(Object.prototype, 'extend', { value: function(namespace, object) {
function Wrapper(that) {
this.that = that;
}
Wrapper.prototype = object;
Object.defineProperty(Object.prototype, namespace, { value: function() {
return new Wrapper(this);
}});
}});
// This example uses the Element object, but it could be any object
Element.prototype.extend('namespace',{
attr: function(name, value) {
if(arguments.length === 1) {
return this.that.getAttribute(name);
} else {
this.that.setAttribute(name, value);
return this;
}
}
});
答案 0 :(得分:0)
然而,我很好奇,这对性能意味着什么
您当前的代码意味着无论何时调用namespace()
,您都会创建一个新对象和许多绑定函数,这将大大影响大型命名空间的性能。
我建议让你的namespace
方法返回一个带有element: this
属性的包装器对象,该属性继承了可以在其上调用的所有方法。您使用this.element.getAttribute
代替this.getAttribute
:
Element.prototype.extend = function(namespace, object) {
function Wrapper(el) {
this.element = el;
}
Wrapper.prototype = object;
Element.prototype[namespace] = function() {
return new Wrapper(this);
};
};
主要问题,这比直接延伸更好吗?
不多。您仍然在extend
上定义namespace
和Element.prototype
属性,对于这两个属性,所有反对扩展DOM的参数仍然有效。您可能会降低与更常见名称(attr
)发生冲突的风险,但它并不比仅定义namespace_attr
方法更好。