有效记忆对象参数
Efficient memoization of object arguments
>摘要:有没有比JSON.stringify
更快的方法来散列对象?
细节:我有一个Ruby和JavaScript库(NeatJSON(,它提供了JavaScript值的漂亮打印。我最近修复了一个问题,即深度嵌套对象导致 O(n!( 性能(n 是嵌套级别(,使用基于被序列化的对象和缩进量的记忆。
在 Ruby 中,修复非常简单,因为您可以通过唯一对象集的数组来索引哈希:
build = ->(object,indent) do
memoizer[[object,indent]] ||= <all the rest of the code>
end
但是,在 JavaScript 中,我不能通过另一个对象(以独特的方式(索引一个对象。根据我在网上找到的几篇文章的引导,我决定笼统地解决这个问题,使用函数的完整参数集JSON.stringify
来创建用于记忆的唯一键:
function memoize(f){
var memo = {};
var slice = Array.prototype.slice;
return function(){
var args = slice.call(arguments);
var mkey = JSON.stringify(args);
if (!(mkey in memo)) memo[mkey] = f.apply(this,args);
return memo[mkey];
}
}
function rawBuild(o,indent){ .. }
var build = memoize(rawBuild);
这有效,但是 (a( 它比我想要的要慢一点,并且 (b( 对我将要智能序列化的每个对象和值执行(幼稚的(序列化似乎效率低下(且不优雅(。序列化具有许多值的大型对象的行为将存储整个对象中每个唯一值(而不仅仅是叶值(的字符串和格式结果。
有没有一个现代的JavaScript技巧可以让我唯一地识别一个值?例如,访问内部 ID 的某种方法,或者将复杂对象与唯一整数相关联,需要 O(1( 时间才能找到值的标识符?
如果你想通过身份(而不是内容(来记忆你的对象,那么你需要使用一个专门为此目的而设计的WeakMap
。但是,它们不适用于原始值,因此您需要为此类参数提供不同的解决方案。
使用@Bergi的WeakMap
建议,我发现了Map
,它允许使用任何值类型作为键(不仅仅是对象(。因为我需要一个复合键(唯一地记住传入的值和缩进字符串的组合(,所以我创建了一个分层记忆结构:
function memoizedBuild(){
var memo = new Map;
return function(value,indent){
var byIndent=memo.get(value);
if (!byIndent) memo.set(value,byIndent={});
if (!byIndent[indent]) byIndent[indent] = rawBuild(value,indent);
return byIndent[indent];
}
}
事实证明,这比我在序列化大型 270kB JSON 对象时使用的记忆代码快约 4×。
请注意,在上面的代码中,我能够使用 !byIndent[indent]
只是因为我知道rawBuild
永远不会返回 falsey 值(null
、undefined
、false
、NaN
、0
、""
(。更安全的代码行如下所示:
if (!(indent in byIndent)) byIndent[indent] = rawBuild(value,indent);
如果您只需要记住对象,那么为您的对象分配一些唯一 ID 是有意义的。
var gID = 0;
function createNode() {
var obj = ...
obj.id = (++gID).toString();
}
并将这些obj.id
用作memo
集合中的键。
这将是最快,最不贪婪的解决方案。
更新:
如果希望该 id 属性不与现有属性冲突然后,您可以使用标准 ES5.1 Object.createProperty(((具有一些唯一名称(或使用 ES6 符号来创建不可枚举的属性:
var gID = 0;
var gUidSym = Symbol("uid");
function getUidOf(obj) {
return obj[gUidSym]
|| (obj[gUidSym] = (++gID).toString());
}
- 我们可以用参数对象集合而不是原始数据来调用JavaScript collection.reduce()方法吗
- 如何将参数对象传输到函数
- 为什么参数对象没有在控制台中显示它的方法
- JavaScript参数对象不起作用
- 如何在 JavaScript 中取消移位或添加到参数对象的开头
- 使用参数对象而不是参数
- JavaScript 参数对象 MDN 指南
- 如何获取参数对象的子集?(关于具有可变大小的参数)
- 如何更好地检查 javascript 中的参数对象
- 如何使用 ajax 调用带有参数(对象)的服务器端方法,其中 url 具有查询参数
- 如何在 ie8 中检测参数对象
- 手动将 AngularJS $http参数对象转换为 URL 参数
- JavaScript 参数对象引用未知
- Javascript - 对 2 参数对象的数组进行排序
- 为什么下划线说 _.initial 对参数对象特别有用
- 未命名的传递参数不包含在“参数”对象中
- JavaScript:获取回调的参数对象
- Javascript参数对象
- 围绕JavaScript参数对象使用的Sonar违规
- each()在IE8上不起作用,并给了我一个“;期望应用数组或参数对象”;.如何解决