在JavaScript中实现节点存储功能

问题描述 投票:2回答:3

有人问我在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节点?

javascript dom
3个回答
4
投票

在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


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冲突,其中每个存储可能会在同一节点上改变相同的属性。为了解决这个问题,我们可以为store salt的当前实例添加一些唯一的,例如可以通过构造函数传递,然后用于前缀或后缀uniqueId


-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
投票

将它像对象一样存储在对象中我认为可能适用于你的情况。

首先是this.store

this.store = {}

然后,在set功能中你可以做到

this.store[node] = value;

在你得到的,

return this.store[node]

我认为这非常简单直接

更新:如果你想获取DOM有关键:对DOM进行字符串化并将其作为键和存储值。

© www.soinside.com 2019 - 2024. All rights reserved.