在JavaScript中实现节点存储功能

时间:2019-04-12 19:16:02

标签: javascript dom

有人问我关于在ES5和ES6中建立商店的问题。

我一直在尝试解决此问题,但是我在如何存储节点上陷入了困境

实施商店类别:

  

使用set(Node,value),get(Node)和   has(Node)方法,用于存储具有相应值的给定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节点?

4 个答案:

答案 0 :(得分:4)

在ES5时代,通常创建一个键数组并通过线性搜索找到它们。这不是最有效的解决方案,但很简单。

InnoDb
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))

此解决方案有两个问题:首先是缓慢的线性搜索,其次,更重要的是,由于商店保留了对关键对象的引用,因此一旦销毁它们就无法进行垃圾回收。

一种更有效的选择是将密钥本身插入值中,但是实现起来要困难得多。

对于ES6部分,有一个专用的内置对象,称为WeakMap

答案 1 :(得分:0)

如果节点是可变的,我们可以尝试为每个节点创建并为其分配唯一的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冲突,其中每个商店可能会在同一节点上更改相同的属性。为了解决这个问题,我们可以为商店 salt 的当前实例添加一些唯一的属性,例如可以通过构造函数将其传递,然后将其前缀或后缀uniqueId

答案 2 :(得分:-2)

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
}

答案 3 :(得分:-3)

将其像对象中一样存储在可能适合您的情况的对象中。

第一个this.store

this.store = {}

然后,在设置功能中可以执行

this.store[node] = value;

在您的帮助下,

return this.store[node]

我认为这非常简单直接

更新: 如果您想使用DOM,请使用key:对DOM进行字符串化处理,然后将其作为键并根据需要存储值。