Skip to content

Instantly share code, notes, and snippets.

@XoseLluis
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save XoseLluis/4cb8315f5df6b3ba4baa to your computer and use it in GitHub Desktop.
Save XoseLluis/4cb8315f5df6b3ba4baa to your computer and use it in GitHub Desktop.
JavaScript Object/Dictionary that keeps track of insertion order, allowing iteration in such order
// deploytonenyures.blogspot.com
//At the time of this writing (2014/07/22) this code only works in Firefox
//notice that at the time of this writing, Direct Proxies and Array.prototype.findIndex are only supported by Firefox
function OrderPreservingObject(initObj){
var obj = {
orderedKeys: [],
forEach: function(actionFunc){
//where actionFunc receives as parameters: item, key, tiedDic
//I've chose this item-key order over key-item based on Array.protoype.forEach, that is passing: the element value, the element index, the array being traversed
for(var i=0; i<this.orderedKeys.length; i++){
var key = this.orderedKeys[i];
actionFunc(this[key], key, this);
}
}
// __iterator__: function* (){
// for (var i=0; i<this.orderedKeys.length; i++){
// yield this.orderedKeys[i];
// }
// }
};
//to prevent orderedKeys from showing up when iterating with "for in" we should declare it as non enumerable,
//but anyway, we should not use "for in" for iterating this object
//ideally we would have managed to trap the "for in" and we would exclude it directly there
var proxy = Proxy(obj, {
//receiver is the proxy itself
set: function(target,name,val,receiver){
//console.log("set invoked");
target[name] = val;
if (target.orderedKeys.findIndex(function(it){
return it == name;
}) == -1){
target.orderedKeys.push(name);
}
return true;
},
deleteProperty: function(target,name){
//console.log("delete invoked");
delete target[name];
var index = target.orderedKeys.findIndex(function(it){
return it == name;
});
if (index != -1){
target.orderedKeys.splice(index, 1);
}
return true;
},
//not completely sure how it works... so let's stick to keys
// enumerate: function* (target){
// console.log("enumerate invoked");
// for (var i=0; i<target.orderedKeys.length; i++){
// yield target.orderedKeys[i];
// }
// },
keys: function(target){
//console.log("keys invoked");
return target.orderedKeys;
}
});
//now that the proxy is set up, we can add the items in the initObj and they'll be added in order
if (initObj){
for (var key in initObj){
proxy[key] = initObj[key];
}
}
return proxy;
}
//let's test it:
var dic1 = new OrderPreservingObject({
name: "Xuan",
city: "Berlin",
age: 45
});
console.info("dic1.keys: " + Object.keys(dic1).join(", "));
delete dic1.city;
console.info("dic1.keys: " + Object.keys(dic1).join(", "));
dic1.job = "journalist";
console.info("dic1.keys: " + Object.keys(dic1).join(", "));
console.log("--------------");
for (var i=0; i<Object.keys(dic1).length; i++){
var key = Object.keys(dic1)[i];
console.info(key + " - " + dic1[key]);
}
console.log("--------------");
for (var i = 0; i< dic1.orderedKeys.length; i++){
var key = dic1.orderedKeys[i];
console.info(key + " - " + dic1[key]);
}
console.log("--------------");
dic1.forEach(function(item, key){
console.info(key + " - " + item);
});
console.log("--------------");
//the __iterator__ fails to compile
// for (var key of dic1){
// console.info(key + " - " + dic1[key]);
// }
console.log("--------------");
//I can't make the enumerate trap work
// for (var key in dic1){
// console.info(key + " - " + dic1[key]);
// }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment