Ordered Map Implementation in JavaScript - javascript

My Task
In my JavaScript code i'm often using objects to "map" keys to values so i can later access them directly through a certain value. For example:
var helloMap = {};
helloMap.de = "Hallo";
helloMap["en"] = "Hello";
helloMap.es = "Hola";
So i build up the map object step by step in my source code using the two available notations object style and array style.
Later i can then access the values i added through helloMap["de"] for example. So thats all fine if i don't have to care about the order in which the attributes has been set on the object.
If i want to iterate the objects properties now as far as i know there is no way to ensure that i'll iterate them in the order they have been added (insertion order).
Note: I can't use some wrapper object and simply hold a array in there and then use its methods to add the values so something like this:
var HelloMap = function(){
this.myMap = [];
this.addProperty = function(key, value){
this.myMap.push({key: key, value: value});
}
}
or something similar won't work for me. So the solution needs to be absolutely transparent to the programmer using the object.
That said the object i needed would be an empty object which maintains the order of the properties that were added to it. Something like this would do:
var helloMap = {};
helloMap = getOrderAwareObject(helloMap);
so that every further assignment of the form helloMap.xy = "foo" and helloMap["yz"] = "bar" would be tracked in the object "in order",
Possible Solutions
Since i did not find any solution in underscore or jQuery giving me such a special object i came across the possibility of defining getters and setters for properties in JavaScript objects with Object.defineProperty since i can rely on ECMAScript 5 standard i can use it.
The Problem with this one is, that you have to know all the possible properties that can be set on the object, before they are actually set. Since if you define it you got to name it.
What i am searching for is something like a Default Getter and Default Setter which applies on the object if no getter and setter has been defined for the property. So i could then hide the sorted map behind the object inteface.
Is there already a solution for this in any framework you know?
Is there a mechanism like "default getter/setter" ?

You'll need a wrapper of some kind using an array internally, I'm afraid. ECMAScript 5 (which is the standard on which current browser JavaScript implementations are based) simply doesn't allow for ordered object properties.
However, ECMAScript 6 will have a Map implementation that has ordered properties. See also http://www.nczonline.net/blog/2012/10/09/ecmascript-6-collections-part-2-maps/.
There may also be other options in ECMAScript 6. See the following question:
How can I define a default getter and setter using ECMAScript 5?

Adding a link to a custom javascript library which provides Sorted maps and other implementation, for future reference in this thread . Check out https://github.com/monmohan/dsjslib
-msingh

I don't know of a general solution but non-general solutions are very simple to construct.
Typically, you maintain an Array of objects, with several methods defined as properties of the Array. At least, that's my approach.
Here's an example, taken (in a modified form) from a larger application :
var srcs = [];
srcs.find = function(dist) {
var i;
for(i=0; i<this.length; i++) {
if(dist <= this[i].dist) { return this[i]; }
}
return null;
};
srcs.add = function(dist, src) {
this.push({ dist:dist, src:src });
}
srcs.remove = function(dist) {
var i;
for(i=0; i<this.length; i++) {
if(this[i].dist === dist) {
srcs.splice(i,1);
return true;
}
}
return false;
};
srcs.add(-1, 'item_0.gif' );
srcs.add(1.7, 'item_1.gif');
srcs.add(5, 'item_2.gif');
srcs.add(15, 'item_3.gif');
srcs.add(90, 'item_4.gif');
Unfortunately, you lose the simplicity of a plain js object lookup, but that's the price you pay for having an ordered entity.
If you absolutely must have order and dot.notation, then maintain a plain js Object for lookup and an Array for order. With care, the two can be maintained with total integrity.

See my answer to this question. I implemented an basic ordered hashtable (ES 5+ only, didn't bother to polyfill)

var put = function(k,v){
if(map[k]){
console.log("Key "+ k+" is already present");
}else
{
var newMap = {};
map[k] = v;
Object.keys(map).sort().forEach(function(key){
newMap[key] = map[key];
});
map = newMap;
//delete newMap; in case object memory need to release
return map;
}
}
Put method will always take a key-value pair, internally creates another map with sorted keys from the actual map, update the value and return the updated map with sorted keys.No external library need to includ.

Related

how to remove middle field in an object to access array inside it? [duplicate]

I am using Map
because I want to store an object as a key.
My question is - can I access a map the same way I would access a plain object?
For example:
let m = new Map();
let obj = {foo:'bar'};
m[obj] = 'baz';
console.log(m[obj]);
is this supposed to work correctly as is, or do I need to use the get/set methods of a Map?
The reason I ask is because if I need to use get/set it forces to me to carefully refactor a lot of code.
Here is a real life example of code that may need to be refactored:
// before (broker.wsLock was plain object)
function addWsLockKey(broker, ws, key) {
let v;
if (!( v = broker.wsLock[ws])) {
v = broker.wsLock[ws] = [];
}
if (v.indexOf(key) < 0) {
v.push(key);
}
}
// after (broker.wsLock is a Map instance)
function addWsLockKey(broker, ws, key) {
let v;
if (!( v = broker.wsLock.get(ws))) {
v = [];
broker.wsLock.set(ws, v);
}
if (v.indexOf(key) < 0) {
v.push(key);
}
}
is there some way to set v on the same line as the set() call?
If you want access to the actual values of the Map object, then you have to use .get() and .set() or various iterators.
var m = new Map();
m.set("test", "foo");
console.log(m.get("test")); // "foo"
Regular property access on a Map such as:
m["test"] = "foo"
just sets a regular property on the object - it does not affect the actual map data structure.
I imagine it was done this way so that you can access the Map object properties separately from the members of the Map data structure and the two shall not be confused with one another.
In addition, regular properties will only accept a string as the property name so you can't use a regular property to index an object. But, map objects have that capability when using .set() and .get().
You asked for a "definitive" answer to this. In the ES6 specification, you can look at what .set() does and see that it operates on the [[MapData]] internal slot which is certainly different than the properties of an object. And, likewise, there is no where in that spec where it says that using normal property access would access the internal object [[MapData]]. So, you'll have to just see that normal property access is describe for an Object. A Map is an Object and there's nothing in the Map specification that says that normal property access should act any different than it does for any other object. In fact, it has to act the same for all the methods on the Map object or they wouldn't work if you happened to put an item in the Map with the same key as a method name. So, you're proof consists of this:
A simple test will show you that property access does not put anything in the Map itself, only a regular property.
The spec describes a Map as an object.
The spec describes how .get() and .set() operate on the internal slot [[MapData]].
There's nothing in the spec that says property access on a Map object should work any different than it always does.
If property access did access the MapData, then you would not be able to access methods if you happened to put a key in the Map that conflicted with a method name - that would be a mess if that was the case.

how many nested object should i define in javascript?

I am new in javascript.
Here I am wondering about how many nested or inner object could i
define in javascript
how to find first 2 nested object's key in js.
i also search it on google but i didn't get any solution.
here is example what i want!
var obj = {
a:{
b:{
c:{
//so on
}
}
}
}
thanks in advance.
Here I am wondering about how many nested or inner object could i define in javascript
There is no specified limit.
In the case of an object initializer such as the one you've shown, eventually you'll run into some sort of limitation of a particular JavaScript engine running the code, e.g., around its parsing / processing of the initializer, but nothing defined in the specification.
If you build objects dynamically on your own, for instance like this:
// Don't run this code!
var obj = {};
while (true) {
obj.child = {};
obj = obj.child;
}
...there's no reason to believe you'll run into anything other than a memory limit related to the number of objects you're creating (not their nesting).
how to find how many objects keys are defined in js
In one particular object, you can get an array of its own (not inherited) properties via Object.getOwnPropertyNames and Object.getOwnPropertySymbols, then take the length of the array. To find out how many properties the object has and how many the objects its properties refer to have, you'd use a recursive search — but beware of cyclic structures.
For instance:
const obj = {
a: {
b: {
c: {
}
}
}
};
function countProps(target, recursive = false) {
const ownProperties = [
...Object.getOwnPropertyNames(target),
...Object.getOwnPropertySymbols(target)
];
let count = ownProperties.length;
if (recursive) {
for (const key of ownProperties) {
const value = target[key];
if (value && typeof value === "object") {
count += countProps(value, true);
}
}
}
return count;
}
console.log(countProps(obj, true));
answer for first question.
There is not any restriction for nested object. you can define nested object as per you want until your memory limit exceed.
answer for second question.
here is a code to find keys from nested objects but it is work for only 2nd nested object.
for (var key in ob) {
if (!ob.hasOwnProperty(key))
continue;
var obj = ob[key];
help += "</br>"
for (var prop in obj) {
// skip loop if the property is from prototype
if(!obj.hasOwnProperty(prop)) continue;
help += " ---) \""+key+" "+prop+"\"</br>"
}
}
tell me if you got what you want.
Here I am wondering about how many nested or inner object could i define in javascript?
In the specification of JS it is not defined.
You can define nested or inner object how many you want.
But: do not forget: every object in your code need place in PC memory. And if you have to many objects you browser will not work correctly.
How to find how many objects keys are defined in JS?
With following metods:
Object.getOwnPropertyNames
Returns an array containing the names of all of the given object's own enumerable and non-enumerable properties.
Object.getOwnPropertySymbols
Returns an array of all symbol properties found directly upon a given object.
you will find the length of how many objects keys are defined in your object.

Most peformant set structure in JS

I want to have a list of strings that is unique and so everytime I get a new string that I should push onto the list I need to check if the list contains the item before pushing it on the list. This seems unperformant.
However, if I use a hash structure and store the items as keys, is there some way to make this more performant than a simple array?
I guess I am simply wondering what the most performant set data structure exists in JavaScript.
Yes, using a Set will be much faster than checking for an existing value (O(1) for set vs. O(n) for an array).
var s = Set();
s.add(1); // s is (1)
s.add(2);
s.add(3);
s.add(1)
s.add(1)
// s is now (1, 2, 3)
In modern browsers (Chrome 38+, IE11+) the Set type is defined, it is documented here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
Otherwise, in JavaScript, Object values (a fundamental type in ECMAScript) are internally implemented as hashtables - so the fastest conceptual "HashSet" structure would exist as a generalisation of of a hashtable with a disregarded value-type.
Here's how I'd do it (if Set was unavailable):
function StringSet() {
this.values = {};
this.add = function(value) {
value = value.toUpperCase(); // use UpperCase for string normalization because of how casing rules work in different languages, especially Turkish
this.values[ value ] = true; // use bool values as stubs
};
this.contains = function(value) {
value = value.toUpperCase();
return value in this.values; // JavaScript has a fast `in` operator which runs in `O(1)` time
}
}
var foo = new StringSet();
foo.add("bar");
assert( foo.contains("bar") );

Javascript How to overload a method and handle keys

I'm trying to implement a dictionary much like Python. So, I would like to have a keys() method that returns keys added to the subclass Dict, but not properties such as the Object's method "keys"
EDIT AGAIN
Basically, I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}. It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects. So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
ie don't return this.prototype.propertyName when own is passedHere's what I have so far:
function Dict(){
this.prototype = {};
var _keys = this.prototype.keys;
this.keys = function(own){
if(typeof own === 'undefined') { return _keys(); }
var ownKeys = [];
for(var key in _keys()){
if(this.hasOwnProperty(key)) {
ownKeys.push(key);
}
}
return ownKeys;
}
}
Will this work as follows? Is there a better or already existent way to do it?
save the overloaded keys() method to a private var
return everything as usual, unless own is something that resolves to true.
if own == true, get the usual keys and filter out those
belonging to the superclass.
On the subject, I'm likely most concerned about saving back the prototype method as a way to get all of the keys and filter out proto keys.
Also, I've read overloading isn't built into Javascript. But, much of what I've found deals with standalone functions such as this Q&A on best practices. I don't need a built in way, but I'll take advantage of whatever's available (Hence, using Object as a Dict).
Any feedback is appreciated!
EDIT
In Python, we get this:
In[2]: d = {}
In[3]: 'has_key' in d.keys()
Out[3]: False
In[7]: 'has_key' in d.__class__.__dict__.keys()
Out[7]: True
In[8]: d.has_key('has_key')
Out[8]: False
In[9]: d['newKey'] = 5
In[10]: d.newKey # ERROR
Python has a dict attribute contained in its class where the functions are accessed via a dot (see In[8]...). So, those standard {} or dict() functions and operators are hidden (not private) while keys/data are added to the user's dict are accessed via []. d['newKey'] = 5 adds a new key or overwrites the old and sets the data to 5.
I don't need all of that to work, though it would be great. keys() returning Python-like keys would be fine for now.
There seem to be multiple issues here.
You seem to want to pass variable arguments to a function:
I'm making a class to pass settings to a function like function(arg1, arg2, myObj) where my object is {map: texMap, alphaMap: aTexMap}.
JS function arguments are very flexible.
You can either set up names for every one of them:
function foo(arg1, arg2, map, alphaMap)
and pass values directly. This style is preferred for functions that work on a fixed set of arguments.
Or you can set up an "options" object that collects keys and values:
function foo(options)
and pass {arg1: val1, arg2: val2, map: valMap, alphaMap: valAlphaMap}. This style often occurs on constructor functions that initialize objects with a certain set configuration options.
Or you can set up an empty function signature
function foo()
and work with the arguments collection inside the function. This is found in functions that work with a variable number of uniform arguments (imagine add(1, 2, 3, 4, 6)) or strictly positional arguments instead of named ones.
In any case, passing arguments to a function is optional in JavaScript, even when there is an argument list in the function signature. You are free to pass none, less or more arguments. Of course all these approaches can be combined if it suits you.
It's for Three.js, and I have to wait on images to download before I can create settings on 3D objects.
This is a problem caused by the asynchronous nature of the web. The solution is to use event handlers. These are either callbacks or - as an abstraction over callbacks - promises.
So, interface like one would expect with d in var d = { a: aData b: bData }, but hide the methods etc that are not added by the user.
This can be solved by not adding methods etc to data objects, or at least not directly. Add them to the prototype if your data objects must have behavior.
The direct equivalent to a Python Dict is a plain object in JavaScript.
var dict = {};
The direct equivalent of Python's keys() method is the Object.keys() static method in JavaScript.
var keys = Object.keys(dict);
To iterate the keys you can either use an imperative approach:
var i, key;
for (i = 0; i < keys.length; i++) {
key = keys[i];
doSomething(key, dict[key]);
}
or a functional one
keys.forEach(function (key) {
doSomething(key, dict[key]);
});
The direct equivalent of Python's in is .hasOwnProperty() in JavaScript:
if ( dict.hasOwnProperty('foo') ) ...
or, if it is a pure data object with no prototype chain, you can use in as well.
if ('foo' in dict)
Using in in for loops is not recommendable because it iterates the prototype properties as well. The way to guard against this is by using Object.keys() instead or by combining it with .hasOwnProperty(), as you did.
var key;
for (key in dict) {
if ( dict.hasOwnProperty(key) ) ...
}
Your question indicates that you are missing basic puzzle pieces about JS and try to substitute them with more familiar Python constructs. I would recommend not doing that.
I also suspect that you try to shoehorn Python's class-based inhertiance pattern into JS' prototype-based inheritance pattern. I strongly recommend that you don't do that, either.

How to hydrate a WinJS.Class

I am serializing and storing an object that was created from a WinJS.Class like this:
var myClass = WinJS.Class.define(...);
var myObject = new myClass();
var serialized = JSON.stringify(myObject);
//store the object
And later I'm pulling the object out of storage and I want to deserialize it and cast it as a myClass. Is that possible with WinJS out of the box or do I need to create a constructor for my class that is capable of taking an object that can turn it into a new object?
I haven't broken into TypeScript yet, and I think that would help out in this situation, but until then I'm wondering how to do it with plain JavaScript/WinJS.
There are a few ways to handle this, and none are particularly special to WinJS. Simply put: JSON serialization only serializes and deserializes the obje values, not its methods, prototype, or other type information.
Option 1: Copy values to new instance of your class
This is usually best accomplished by having your constructor take the deserialized object as a parameter and copying the data to the new instance.
There are a variety of variations of this. Using the object constructor is generally the best for performance, as this typically enables the JS engine to apply the greater number of optimizations to the object.
WinJS.UI.setOptions can be helpful here, or you can just copy the data using a simple loop like this:
var keys = Object.keys(source);
for (var i = 0, len = keys.length; i < len; i++) {
var key = keys[i];
destination[key] = source[key];
}
Option 2: Setting __proto__
Warning: This can have significantly adverse performance effects, so it's not appropriate in some situations. But occasionally it can be handy.
Object.setPrototypeOf(myObject, myClass.prototype);
Note that setPrototypeOf is relatively new. It's there on Win8.1 for web apps (which I'm guessing this is about) and in IE 11, but not available in Safari, for example. On older browsers/ Safari, assigning to proto is the equivalent (but if available, setPrototypeOf is better).
This will attach methods from myClass to the object, but in addition to the negative performance effects, also does not run your constructor on the object - so it still may not be in exactly the same state as the object you originally serialized.
Other helpful thing: JSON "revivers"
JSON.parse takes an optional second parameter, called a "reviver". This lets you provide a function that gets the opportunity to transform each node of the JSON being deserialized. This can be useful for rehydrating serialized dates into JavaScript Date objects, for example. It also gets the opportunity to transform the top-most object, which could be useful in some cases to turn the deserialized object into the "class" you want.
Javascript is a dynamic language so I think you dont need to cast the deserialized object, just treat it as myClass type and that's it. Hope it helps you.
You should consider using the 'Options' constructor pattern, where the option value is the deserialized object:
// MovieModel Constructor
// ----------------------
function MovieModel(options) {
this._titleValue = options.title || "Sample Title";
}
Where the movie methods closure is something like this:
// MovieModel Methods
// ------------------
var movieModelMethods = {
title: {
get: function () {
return this._titleValue;
},
set: function (val) {
this._titleValue = val;
this.dispatchEvent("title");
}
}
};
Since WinJS class define can only specify one constructor function (as far as I understand it), you may use the static members to define a factory function that will take the serialized data as a parameter. This factory methdod will actually create a new instance and will set the values one by one and return the new object.
It as some advantages like the fact that you can actually manage the data structure changes over the time you enhance the app...
The drawback is that you cannot write new MySuperClass() all the time...
...
// let's suppose we already called JSON.parse(data);
create: function(serializedData) {
var newObj = new MySuperClass();
newObj.name = serializedData.name || "";
newObj.color = serializedData.color || "";
return newObj;
}
Then you will call somewhere else in the app :
var myInstance = MySuperClass.create(serializedDataFromfile);
You should just be able to call JSON.parse after pulling it out of local storage:
var myObject2;
myObject2 = JSON.parse(localStorage["mySeriazliedObject"];

Categories