Skip to content

Instantly share code, notes, and snippets.

@dherman
Created June 9, 2012 02:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dherman/2899176 to your computer and use it in GitHub Desktop.
Save dherman/2899176 to your computer and use it in GitHub Desktop.
Map vs object for dictionary
// A Dict class that works in ES6 using Map. Basically it's identical to Map, but
// only expected to be used on string keys.
function Dict() {
this.elts = new Map();
}
// (string) -> any
Dict.prototype.get = function get(key) {
return this.elts.get(key);
};
// (string, any) -> void
Dict.prototype.set = function set(key, val) {
return this.elts.set(key, val);
};
// (string) -> boolean
Dict.prototype.has = function has(key) {
return this.elts.has(key);
};
// (string) -> void
Dict.prototype.remove = function remove(key) {
this.elts.delete(key);
};
// A Dict class that works in ES5, or in engines that support __proto__ so that
// a polyfilled Object.create can create prototype-less objects. This hasn't been
// tested or optimized at all. I'll accept any optimizations so long as it's
// never sensitive to prototype pollution (e.g. in Object.prototype).
function Dict() {
this.dunderProto = Object.create(null);
this.elts = Object.create(null);
}
// (string) -> any
Dict.prototype.get = function get(key) {
return (key === '__proto__') ? this.dunderProto.value : this.elts[key];
};
// (string, any) -> void
Dict.prototype.set = function set(key, val) {
if (key === '__proto__') {
this.dunderProto.value = val;
} else {
this.elts[key] = val;
}
};
// (string) -> boolean
Dict.prototype.has = function has(key) {
return (key === '__proto__') ? 'value' in this.dunderProto : key in this.elts;
};
// (string) -> void
Dict.prototype.remove = function remove(key) {
if (key === '__proto__') {
delete this.dunderProto.value;
} else {
delete this.elts[key];
}
};
// Alternative implementation that protects against magic __proto__ by prefixing
// all keys with "%". Again, works in ES5 or in engines that support __proto__ so
// that a polyfilled Object.create can create prototype-less objects.
function Dict() {
this.elts = Object.create(null);
}
// (string) -> any
Dict.prototype.get = function get(key) {
return this.elts["%" + key];
};
// (string, any) -> void
Dict.prototype.set = function set(key, val) {
this.elts["%" + key] = val;
};
// (string) -> boolean
Dict.prototype.has = function has(key) {
return ("%" + key) in this.elts;
};
// (string) -> void
Dict.prototype.remove = function remove(key) {
delete this.elts["%" + key];
};
@Yaffle
Copy link

Yaffle commented Jun 9, 2012

what about magic "__count__", __defineGetter__, .... ?

@dherman
Copy link
Author

dherman commented Jun 9, 2012

Pretty sure those have been gone for a while, no?

Dave

@Yaffle
Copy link

Yaffle commented Jun 9, 2012

@dherman, http://kangax.github.com/es5-compat-table/non-standard/
although, may be some properties (defineGetter) could be removed

delete x.__defineGetter__

@dherman
Copy link
Author

dherman commented Jun 9, 2012

Yeah, defineGetter isn't a problem because it's inherited from Object.prototype. I'm not worried about count or parent because I'm more interested in the future. (Of course, if someone wants to make this compatible back to FF 3.6 they can put in additional special cases for count and parent as well.)

Dave

@Yaffle
Copy link

Yaffle commented Jun 9, 2012

@dherman, oh.. sorry, you are right, defineGetter is inherited from Object.prototype
but
have you any information, that in the future no other "magic" properties will be added?

@dherman
Copy link
Author

dherman commented Jun 9, 2012

Yes, because they were one of the worst mistakes ever made in JS. I can't guarantee that no one will do it again, but I can tell you that as long as Brendan and I have anything to do with it, we won't let it happen.

Dave

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment