将element.id设置为副作用是一种糟糕的做法
Is setting element.id as a side effect bad practice?
我正在插件/库中编写一个小的缓存函数。它获取一个HTMLElement
并返回一个Decorator。
return function _cache(elem) {
if (elem.id === "") {
elem.id = PLUGIN_NAME + "_" + uid++;
}
if (cache[elem.id] === void 0) {
cache[elem.id] = _factory(elem);
}
return cache[elem.id];
}
在这里,我通过HTMLElement
的id
将一些昂贵的操作存储在高速缓存中。这是一个O(1)
查找,但它使用了设置elem.id
的"坏做法",并产生了副作用。
另一种选择是在缓存上查找O(N)
return function _cache(elem) {
for (var i = 0, ii = cache.length; i++) {
var o = cache[i];
if (o.elem == elem) return o.data;
}
var ret = _factory(elem);
cache.push({ elem: elem, data: ret });
return ret;
}
但这意味着我缓存的昂贵方法对HTMLElement
没有任何副作用。
问题:
这种"副作用"是无辜的吗?值得对我的装饰器进行优化吗?
真实代码:
Gist的插件模板,我在那里使用这个片段
编辑:
我显然太累了,忘记了data-foo
的存在。以下是应该如何实现
var attr = "data-" + PLUGIN_NAME + "-cache";
return function _cache(elem) {
var val = elem.getAttribute(attr);
if (val === null || val === "") {
val = PLUGIN_NAME + "_" + uid++;
elem.setAttribute(attr, val);
}
if (cache[val] === undefined) {
cache[val] = _factory(elem);
}
return cache[val];
}
不要使用id
,而是使用data-x
——这就是它的创建目的。
id
有一个特定的含义,看到它自动生成是令人困惑的(即使有正确的文档记录,这几乎从来都不是。)你也有被覆盖的风险。
这种"副作用"是无辜的吗
不,很明显。它会与页面上的其他脚本很好地交互吗?不知道。。。这取决于它的用途,以及您希望它与其他类型的脚本相结合。你永远无法制作一个在与其他插件和脚本交互时永远不会失败的"插件",但通过将副作用降至最低,你至少可以尝试将其降至最低。
注意,id
不是唯一标识符。尽管在一个特定的时间,文档中应该只有一个具有给定ID的元素,但(a)可以使用相同的ID创建多个元素,并按顺序插入到文档中(也许一个元素用相同的ID替换另一个元素),以及(b)人们仍然使用重复的ID,即使这是错误的。这两种情况都会导致缓存收集旧的、不再使用的元素,并不适当地返回它们。
不幸的是,没有JavaScript函数来获取任意对象的标量/哈希唯一标识符;获得对象身份的唯一方法是CCD_ 13——与其他对象进行比较。
另一种常见的方法是向节点添加一个任意的新属性(IE术语中的"expando"),并带有一个随机的、真正唯一的ID。标准并不能保证expando能够工作,但它从第一天起就在所有浏览器中都能工作,并且很常用。
例如,jQuery就是这样唯一地识别元素的,如果你正在为jQuery编写插件,你可以尝试利用这一点——jQuery.expando
保存用于此目的的任意expando属性的名称。。。或者,在文档化的特征集中,data()
可以用于将您自己的元数据添加到元素中,包括您自己的另一个唯一ID。
Expandos确实有一些令人不快的副作用,包括意外地将它们作为IE<9(不能区分属性和属性),但如果您无论如何都在使用jQuery,您可能不会有任何损失。
对我的decorator进行优化值得吗?
取决于你期望在一页上有多少。将每个项目与其他项目进行比较是O(n²)运算;如果n较低,则可以忍受(考虑到副作用,可能更可取),但随着n的增长,很快变得无法控制。
- 是否可以在网页上用另一种字体设置jqmath-display的样式
- 有没有一种快捷方式可以让我用javascript或jQuery设置对象的字段
- 用Javascript在forEach中设置开关是不是一种糟糕的做法
- 在 reactjs 中设置组件 DidMount 上的间隔是一种正确的方法
- 当区域设置设置为另一种语言时,如何从 momentjs 对象获取英语值
- 是否有一种本机方法可以将字符串从任何区域设置转换为数字
- 是否有一种非闪存方法来设置/获取 WebKit 中的剪贴板数据
- 有没有一种方法可以使用不同的环境配置文件来为基于Ionic Framework的Cordova应用程序进行开发和生产设置
- 有没有一种更快的方法可以在下拉列表中设置选定的值
- 有没有一种方法可以将javascript中的字符串解析为与区域设置相关的数字
- 有没有一种方法可以用程序设置断点(例如,当调用命名函数时)
- 在JavaScript/jQuery中将DOM元素设置为全局变量是不是一种糟糕的编程实践
- Net-有没有一种方法可以从数据中设置属性
- 有没有一种方法可以检测当前的输入语言设置
- 有没有一种更简洁的方法来设置一个条件语句,以便为变量的任意值集执行
- Javascript或jQuery:有没有一种方法可以设置document.referrer,而不必在每次重新加载页面时
- angularjs中有没有一种方法可以动态设置ngModel
- 在Node.js Express/Connect中,有没有一种方法可以将会话设置为无穷大
- 有没有一种方法可以动态设置Highchart选项
- 有没有一种设置方式"!“重要”;用于event.stop()