Last active
August 29, 2015 14:04
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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