目标:最终目标是拥有一种访问有序列表中对象数据的方法/技术,以及调用有序列表中的排序或映射等方法。如果我可以为每个键值分配索引号,那么这应该是可能的。如果我们可以为对象的每个键值分配一个索引,那么其余的应该通过创建map版本并将它们排序或继承Array对象来实现。
var foo = {
bar : 'value',
foobar : 'value2'
};
//the magic here
foo.bar // 'value'
foo[0] // 'value' (This is the ideal solution it does not have to be this way)
问题:有没有办法为javascript对象键分配索引编号?
思考:我知道javascript对象是哈希表,因此它们有一个分配给它们的密钥,但它们是完全随机的,并且可能会随着更改哈希表的大小而改变。所以那不行。
我们可以遍历对象并拥有一个单独的数组,该数组只包含键值,然后通过该键值得到值。
我真的不确定这里有什么好的解决方案我只是抛弃我的想法,想法?
答案 0 :(得分:0)
嗯,一种方式就是这样:
var foo = {
bar : 'value',
foobar : 'value2'
}
var i = 0;
for (el in foo) {
foo[i] = foo[el];
i++;
}
答案 1 :(得分:0)
JavaScript不支持指针,所以要做到这一点,我担心你必须复制对象的内容。
var foo = {
bar : 'value'
foobar : 'value2'
};
foo[0] = foo.bar;
foo[1] = foo.foobar;
这会使一个具有重复内容的对象,因为执行上述代码后的属性将是:
bar
foobar
0
1
你可以做的是使用for ... in
statement迭代你的对象,允许你使用整数作为数组索引来遍历它,以迭代你的对象。
var obj = {a:1, b:2, c:3};
for (var prop in obj) {
console.log("obj." + prop + " = " + obj[prop]);
}
所以你可以这样做:
var i = 0;
for (var prop in foo) {
foo[i] = foo[prop];
i++;
}
请注意,这不会在特定属性与其数组索引之间提供强绑定。为了实现这种一致性,您可以为同时更新两者的变量创建一个setter属性。
function setProperty(propertyName, index, value) {
foo.propertyName = value;
foo[index] = value;
}
我不确定这是否会在性能方面表现良好,因为您的对象仍然会被复制,但是现在我可以想到解决这个问题。
答案 2 :(得分:0)
JavaScript对象不是哈希表,而现代引擎哈希表仅在其实现中使用,如果您从中删除属性。否则,它们是高度优化的运行时生成的类的实例。其中没有一个对手头的问题非常重要。 : - )
假设您希望0
属性与其中一个命名属性之间存在持续链接,那么在ES5及更早版本中无法执行此操作。相反,您需要getter / setter方法来进行索引访问:
Object.defineProperty(foo, "item", {
value: function(index, value) {
var key = Object.keys(this).sort(orderingFunction)[index];
if (arguments.length < 2) {
// Getter
return this[key];
}
// Setter
this[key] = value;
return this;
}
});
...其中orderingFunction
是定义键顺序概念的函数。 (在ES5及以下,属性没有订单。虽然在ES2015及以上属性确实有订单,但它是A)没用,B)不保证是Object.keys
返回的订单。)
用法:
foo.item(0); // "value"
foo.item(0, "new value");
或者如果您愿意,可以为getter和setter使用单独的函数。
请注意,这是相当昂贵的,所有这些都是排序。
是在ES2015及以上版本中的一种方法:一个Proxy
对象,可以在这里做两件事:
实现可用于数字访问的默认属性访问功能
允许您维护密钥数组,而无需不断对其进行重新排序
// REQUIRES ES2015+ SUPPORT IN YOUR BROWSER
let foo = {
question: "Life, the Universe, and Everything!",
answer: 42
};
let rexNumber = /^\d+$/;
let fooProxy = indexedProxy(foo);
console.log(fooProxy[0]); // 42
fooProxy.answer = 67;
console.log(fooProxy[0]); // 67
fooProxy.bar = "foo";
console.log(fooProxy[1]); // "foo"
function indexedProxy(obj) {
// An array of the current keys
let keys = getKeys(foo);
// Return the proxy
return new Proxy(obj, {
// Called when any property is gotten from the target
get(target, property) {
if (rexNumber.test(property)) {
// Indexed access
let key = keys[property];
return key === undefined ? undefined : target[key];
}
// Normal access
return target[property];
},
// Called when any property is set on the target
set(target, property, value) {
if (rexNumber.test(property)) {
// Indexed access
let key = keys[property];
if (key === undefined) {
throw new Error(`No property for index #{property}`);
}
target[key] = value;
} else {
// Normal access, do we know the key?
let newProp = !keys.includes(property);
target[property] = value;
if (newProp) {
// Rebuild our array
keys = getKeys(target);
}
}
}
});
}
function getKeys(obj) {
// Let's go for alphabetical
return Object.keys(obj).sort((a, b) => a.localeCompare(b));
}
&#13;
代理也不便宜,但希望能比你不断生成和排序的数组表现得更好。
显然上面的只是一个例子,而不是高度优化的通用工具。它没有使用数组索引的正确定义(隐藏在this answer中的细节),它使用更简单的&#34;它是全部数字?&#34;定义。它只处理对象拥有,可枚举属性;如果您想处理继承的属性或标记为不可枚举的属性,那么可能只需要调整上面的内容。
答案 3 :(得分:0)
也许这有帮助。
(我没有看到其他答案,也没有阅读评论;当我开始编写此代码时,这篇文章很空白)
<input type="button" value="GO" onclick="doStuff()">
<div id="log"></div>
<script>
function doStuff() {
var foo = {};
// INSERT items
log('Inserting items');
var index1 = pushItem(foo, 'bar', 'value');
var index2 = pushItem(foo, 'foobar', 'value2');
log('getting items');
// get items
var item2 = getItem(foo, 1);
// map
log('map');
mapItems(foo, function(value, index, key) {
log('map. value: ' + value + ' - index: ' + index + ' - key: ' + key);
});
// display a log on screen. Feel free to use console.log instead
function log(message) {
document.getElementById('log').innerHTML += message + '<br/>';
}
}
////////////////////////////////////////////////////////////////
// global variable, contains the keys in an array, example ['bar', 'foobar']
var key_indexes = [];
// pushes an item to the object, returns the index
function pushItem(object, key, value) {
key_indexes.push(key);
object[key] = value;
return (key_indexes.length - 1);
}
// get an item
function getItem(object, index) {
var key = key_indexes[index];
return object[key];
}
// map
function mapItems(object, callback) {
for(var index in key_indexes) {
var key = key_indexes[index];
callback(object[key], index, key);
}
}
</script>