有人问我在ES5和ES6中实现商店这个问题。
我一直在努力解决这个问题,但我不知道如何存储节点
实现商店类:
使用set(Node,value),get(Node)和has(Node)方法实现商店类,这些方法存储具有相应值的给定节点。
这是我能写的(伪代码)
function Store () {
this.store = [];
}
Store.prototype.set = function(node, v) {
// Problem here would be how do I store the node?
}
Store.prototype.get = function(node) {
if(this.has(node)) {
return this.store.find(each => {
// Check to see if it's the same node and return.
})
}
}
Store.prototype.has = function(node) {
return this.store.indexOf(node) > -1;
}
注意:我们可以在商店中存储HTML DOM。所以关键是“DOM”元素而不是字符串。
有人可以用一个例子来启发我吗?我想这会像ES6中的Map一样工作。如果我要在ES5中实现这一点,我如何首先存储DOM节点?
在ES5时代,创建一个键数组并使用线性搜索定位它们是很常见的。这不是最有效的解决方案,但很简单。
function Store() {
this.keys = [];
this.values = [];
}
Store.prototype.set = function(key, val) {
var i = this.keys.indexOf(key);
if(i < 0) {
i = this.keys.push(key) - 1;
}
this.values[i] = val;
};
Store.prototype.get = function(key) {
return this.values[this.keys.indexOf(key)];
};
Store.prototype.has = function(key) {
return this.keys.indexOf(key) >= 0;
};
//
a = document.querySelector("#a")
b = document.querySelector("#b")
c = document.querySelector("#c")
s = new Store()
s.set(a, '1')
s.set(b, '2')
console.log(s.has(a), s.get(a))
console.log(s.has(b), s.get(b))
console.log(s.has(c), s.get(c))
<div id="a"></div>
<div id="b"></div>
<div id="c"></div>
此解决方案存在两个问题:第一,慢速线性搜索,第二,更重要的是,由于Store保留对关键对象的引用,因此一旦销毁就无法进行垃圾回收。
更有效的选择是将密钥注入值本身,但实现起来要复杂得多。
对于ES6部分,有一个专用的内置对象,称为WeakMap
。
如果节点是可变的,我们可以尝试创建并为每个节点分配其唯一ID:
function NodeStore() {
this.nodesValueMap = {};
this.lastId = 0;
}
NodeStore.prototype.set = function(node, value) {
// text nodes do not have dataset (DOMStringMap), create simple object
node.dataset = node.dataset || {};
node.dataset.uniqueId = node.dataset.uniqueId || ++this.lastId;
this.nodesValueMap[node.dataset.uniqueId] = value;
}
NodeStore.prototype.get = function(node) {
return node.dataset.uniqueId && this.nodesValueMap[node.dataset.uniqueId];
}
NodeStore.prototype.has = function(node) {
return !!(node.dataset.uniqueId && this.nodesValueMap[node.dataset.uniqueId]);
}
var textNode = document.querySelector("#a").childNodes[0];
var b = document.querySelector("#b");
var c = document.querySelector("#c");
var store = new NodeStore();
store.set(textNode, '1');
store.set(b, '2');
console.log(store.has(textNode), store.get(textNode));
console.log(store.has(b), store.get(b));
console.log(store.has(c), store.get(c));
<div id="a">asdf</div>
<div id="b"></div>
<div id="c"></div>
所有方法现在都将以O(1)的复杂性运行。
没有必要使用dataset
,我们可以在节点本身上编写唯一的ID。
另一件事是,如果同一页面上存在多个存储,我们可能会发生ID冲突,其中每个存储可能会在同一节点上改变相同的属性。为了解决这个问题,我们可以为store salt的当前实例添加一些唯一的,例如可以通过构造函数传递,然后用于前缀或后缀uniqueId
。
function Store () {
this.store = {};
}
Store.prototype.set = function(node, v) {
this.store[node] = v;
}
Store.prototype.get = function(node) {
return this.store[node];
}
Store.prototype.has = function(node) {
return this.store[node] !== undefined
}
将它像对象一样存储在对象中我认为可能适用于你的情况。
首先是this.store
this.store = {}
然后,在set功能中你可以做到
this.store[node] = value;
在你得到的,
return this.store[node]
我认为这非常简单直接
更新:如果你想获取DOM有关键:对DOM进行字符串化并将其作为键和存储值。