Javascript change variable based on variable reference - javascript

In a program i am writing i need an object variable that looks like this:
var map {
cube: {__pt3arraylocation__:[0,0,0], poly: new Object()},
other: {__pt3arraylocation__:[1,0,0], poly: new Object()}
};
However, i want to be able to type map.cube and have it return the pt3arraylocation as a default unless i specify what i want by typing map.cube.poly
for example: map.cube would return [0,0,0] and map.cube.poly would return the object poly in the object cube
thanks in advance

i want to be able to type map.cube and have it return the pt3arraylocation as a default unless i specify what i want by typing map.cube.poly
for example: map.cube would return [0,0,0] and map.cube.poly would return the object poly in the object cube
You can't do that in JavaScript.
However, as an alternative, it's worth noting that you can add arbitrary properties to arrays if you want to. So for instance:
var map {
cube: [0,0,0],
other: [1,0,0]
};
map.cube.poly = {}; // {} is the same as `new Object()` but not subject to people...
map.other.poly = {}; // ...overriding the `Object` symbol
Then map.cube gives you the array, and map.cube.poly gives you the object you've stored on that array.
How is this possible? Because in JavaScript, arrays aren't really arrays. They're just objects that have an automatic length property, treat a class of property names (all numeric ones) in a special way, and have Array.prototype backing them up. And of course, you can add properties to any object.
There's no literal syntax for doing this, which is why I had to do it with assignments after the object initializer above. But it's perfectly valid. I use it for cross-indexing arrays all the time.
Do be sure, if you do this, that you're not using for..in incorrectly; more.

The best way to do this I would say is like this:
var map {
cube: [0,0,0],
other: [1,0,0]
};
map.cube.poly = new Object();
map.other.poly = new Object();

That is not possible to achive. Maybe you can play around with toString()
var map = {
cube: {
__pt3arraylocation__:[0,0,0],
poly: new Object(),
toString : function() {
return this.__pt3arraylocation__.toString()
}
},
other: {__pt3arraylocation__:[1,0,0], poly: new Object()}
};
map.cube == '0,0,0'
map.cube.split(',') == map.cube.__pt3arraylocation__

There is no way to do that exactly as you want - if you request an object (which map.cube is), you get an object. However, there are a few ways to do something similar.
when used as a parameter to functions or operations that require string, like alert(map.cube) or "sometext" + map.cube, the object is converted to string by calling the toString function. You can therefore define, for example:
map.cube.toString = function() { return this.__pt3arraylocation__.toString(); };
a similar thing happens when there if the object is used in context when a number is needed. In this case, it is converted with valueOf(). So you can use, for example
map.cube.valueOf = function() { return this.__pt3arraylocation__.length; };
or you can obtain the default value via a function call, if you define your object as a function instead
var map = {
cube: function() {
return map.cube.__pt3arraylocation__;
}
}
map.cube.__pt3arraylocation__ = [0,0,0];
map.cube.poly = new Object();
alert(map.cube.__pt3arraylocation__); // 0,0,0
alert(map.cube.poly); // [object Object]
alert(map.cube()); // same as map.cube.__pt3arraylocation__
As you can see, in JavaScript, functions are objects like any other, so you can not only call them, but also set fields and methods to them.

T.J. Crowder is right. Based on his answer I'd like to remark that you can also assign map.cube like this
var map = {
cube: function(){
var val = [0,0,0];
val.poly = {};
return val; }()
};
Or for more values:
function polyval(val){
val.poly = {};
return val;
}
var map = {
cube: polyval([0,0,0]),
other: polyval([1,0,0]),
more: polyval([1,1,0])
/* ... etc */
};

Related

Store an object with an array inside?

Is there a way to store an object with an array[id] = "certain value", so that every single user has a list of favorite things ?
What I'm trying to achieve is having a data object with undefined values at first, and filling them in, so for example Jack and Sam could have an assigned favorite movie saved.
I tried something like this with no success:
Data.js:
module.exports = function() {
return {
favMovie: ""
}
};
App.js:
var person [] = data();
//1st person
person[811767132257839].favMovie = "Matrix";
//2nd person
person[107230716367889].favMovie = "Kill Bill";
//3rd person
person[973676332752239].favMovie = "Avatar";
...
console.log( "Favorite movie: " + person[id].favMovie );
It doesn't sound like you want any arrays at all, just objects.
// Create an object that we'll keep person objects in
var personData = {};
// Add a person object to it for person ID #123
personData[123] = {};
// Set person #123's favorite movie:
personData[123].favMovie = "Avatar";
// Add a different person; this time, we'll add the movie at
// the same time
personData[234] = {
favMovie: "Matrix"
};
When using objects as maps like that, sometimes people create the objects using Object.create(null) to avoid them having any inherited properties (like toString and valueOf and constructor):
person[123] = Object.create(null);
person[123].favMovie = "Avatar";
In ES2015 (aka "ES6"), you might want to use a Map rather than an object for the map of people:
var personData = new Map();
...and then use set and get for the individual person objects.
If the individual person objects get complicated, you might use a constructor function and associated prototype for them, using either ES5 syntax:
function Person() {
// ...
}
Person.prototype.doSomething = function() {
// ...
};
...or ES2015 syntax:
class Person {
constructor() {
// ...
}
doSomething() {
// ...
}
}
Then creating them:
personData[123] = new Person();
// or if using Map
personData.set(123, new Person());
Side note: Even when we write them as numbers, the keys (property names) in objects are always strings (unless you use ES2015 Symbols, which you probably wouldn't here). In contrast, keys in an ES2015 Map can be anything. Key equality in Map instances is determined using the special "same value zero" algorithm (which is basically === except that NaN is equal to itself [whereas it isn't in ===]).

Prototype lost on slice on array-like construct

I have created an array like prototype:
function METracker() {}
METracker.prototype = Object.create(Array.prototype);
METracker.prototype.myMethod = function(aStd) {
return true;
};
now i create an instance:
var aInst = new METracker('a', 'b', 'c');
Now I want to clone it so I do:
var cloneInst = aInst.slice();
however cloneInst no longer has the method .myMethod is there a way to keep the prototype on the clone?
Thanks
If you're going to create your own array-alike, the trick is to extend an array instance, not the array prototype:
function MyAry() {
var self = [];
[].push.apply(self, arguments);
// some dark magic
var wrap = 'concat,fill,filter,map,slice';
wrap.split(',').forEach(function(m) {
var p = self[m];
self[m] = function() {
return MyAry.apply(null, p.apply(self, arguments));
}
});
// add your stuff here
self.myMethod = function() {
document.write('values=' + this.join() + '<br>');
};
return self;
}
a = new MyAry(11,44,33,22);
a.push(55);
a[10] = 99;
a.myMethod()
b = a.sort().slice(0, 4).reverse();
b.myMethod();
Basically, you create a new array (a normal array, not your object), wrap some Array methods so that they return your object instead of generic arrays, and add your custom methods to that instance. All other array methods and the index operation keep working on your object, because it's just an array.
I have created an array like prototype:
No, you haven't.
function METracker() {}
METracker.prototype = Object.create(Array.prototype);
METracker.prototype.myMethod = function(aStd) {
return true;
};
The METracker constructor does nothing at all, it will just return a new Object with Array.prototype on its [[Prototype]] chain.
var aInst = new METracker('a', 'b', 'c');
Just returns an instance of METracker, it has no data since the constructor doesn't do anything with the arguments passed. Assigning Array.prototype to the inheritance chain doesn't mean the Array constructor is invoked.
var cloneInst = aInst.slice();
Note that callling slice() on aInst just returns a new, empty array. aInst doesn't have a length property, so the algorithm for slice has nothing to iterate over. And even if aInst had properties, slice will only iterate over the numeric ones that exist with integer values from 0 to aInst.length - 1.
If you want to create a constructor that creates Array–like objects, consider something like:
function ArrayLike() {
// Emulate Array constructor
this.length = arguments.length;
Array.prototype.forEach.call(arguments, function(arg, i) {
this[i] = arg;
}, this);
}
ArrayLike.prototype = Object.create(Array.prototype);
var a = new ArrayLike(1,2,3);
document.write(a.length);
document.write('<br>' + a.join());
The above is just play code, there is a lot more to do. Fixing the length issue isn't easy, I'm not sure it can be done. Maybe there needs to be a private "fixLength" method, but methods like splice need to adjust the length and fix indexes as they go, so you'll have to write a constructor that emulates the Array constructor and many methods to do re–indexing and adjust length appropriately (push, pop, shift, unshift, etc.).

Generic 2D hash in JavaScript?

In other languages it is possible to create a generic 2D hash. I know creating 2d hashes is possible in javascript as well as explained here, but I can't seem to find a generic way to achieve this.
As an example of what I am looking for. In Ruby you can do this:
2dhash = Hash.new{|h, k| h[k] = Hash.new }
puts 2dhash["test"]["yes"]
#=> nil
2dhash[1][2] = "hello"
puts 2dhash[1][2]
#=> "hello"
Notice that I have not initialized the second level of hash, it happens automatically.
Is it possible to somehow achieve the same in javascript? Specifically, a way to make a 2d hash without initializing the first level of hash (or hard-coding it to be even more specific). The 2dhash will be used dynamically, so I have no clue what the first level will be.
Looks like a nice data structure excercise, let me try :D
function Hash() {
this.hash = {};
}
Hash.prototype.set = function(val) {
var paths = Array.prototype.slice.call(arguments, 1) // all levels
var path = paths.shift() // first level
var hashed = this.hash[path]
if (paths.length) {
// still have deeper levels
if (!(hashed instanceof Hash)) {
hashed = this.hash[path] = new Hash()
}
Hash.prototype.set.apply(hashed, [val].concat(paths))
} else {
// last level
this.hash[path] = val
}
}
Hash.prototype.get = function() {
var paths = Array.prototype.slice.call(arguments, 0) // all levels
var path = paths.shift() // first level
var hashed = this.hash[path]
if (paths.length) {
// still have deeper levels
return Hash.prototype.get.apply(hashed, paths)
} else {
// last level
return hashed
}
}
Now, let's see if it works:
var trytry = new Hash()
trytry.set('the value to store', 'key1', 'key2')
trytry.get('key1') // Hash{key2: 'the value to store'}
trytry.get('key1', 'key2') // 'the value to store'
Hooray it works!
It also works for even deeper levels:
trytry.set('the value to store', 'key1', 'key2','key3', 'key4')
trytry.get('key1', 'key2','key3') // Hash{key4: 'the value to store'}
However, a disadvantage of this approach is that you have to use instance methods get and set, rather than native object literal getter/setter.
It's still incomplete. For production environment, we need to do more, e.g. methods and properties like contains, size, etc.
If you initialize the first level of the hash with objects, then you can reference the second level without typeErrors, even if the data was not defined before.
Example:
var _2dhash = {a: {}, b: {}, c:{}}
//Note you cannot start variable names with numbers in js
_2dhash['a']['missingElement'];
// > undefined
It works because you're accessing undefined properties of defined objects. If you try to access through a missing top-level object, ie.
_2dhash['d']['whatever'];
You will get a TypeError, because _2dhash.d was not defined, and the second lookup fails, trying to read the 'whatever' property of undefined.

__hash__ for javascript?

Is there a way to give objects in js custom hashes, just as overriding
__hash__()
in python let's someone define how a given object is hashed into a dictionary.
My underlying question is: what hash function is used to put js objects into associative arrays, and can I over-ride it?
You mean using objects as keys, how do you make sure you access that key again?
The magic method is toString(). Turns out all objects in JS use string keys, and the toString() method is called if it's not a string.
http://jsfiddle.net/udsdT/1/
var objA = {
data: 'yay',
toString: function() {
return 'value_as_key';
}
};
var objB = {
data: 'some other totally data thing',
toString: function() {
return 'value_as_key';
}
}
var foo = {};
foo[objA] = 'abc';
foo[objB] = 'def';
foo['value_as_key'] = 'qwe';
foo.value_as_key = 'omg';
foo[objA]; // 'omg'
foo[objB]; // 'omg'
foo['value_as_key']; // 'omg'
foo.value_as_key; // 'omg'
​​​​​​Usually though, you really don't want to use whole objects as keys. Especially if you dont create your own toString() method, since the default toString() method on basic objects isn't exactly very awesome...
({a:123}).toString() // [object Object]
({b:456}).toString() // [object Object]
var foo = {};
foo[{a:123}] = 'wtf';
foo[{asdf:9876}]; // 'wtf'
foo['[object Object]']; // 'wtf
In JS, you can't control the hashing, but you don't have to.
Two things are the same if they're equal. The hash is not part of the definition, it's just an implementation detail. Under the covers, two different objects may have the same hash, but they're still different, and the implementation has to deal with that magically (e.g., by using a chaining hash table).
Also, the keys of an object are always strings—the interpreter will stringify the values inside the hash constructor, inside the [], or after the ., rather than storing the actual values, which means that this rarely comes up in the first place.
To give some examples:
function X() {}
x = new X()
y = new Y()
h = {x: 2, y: 3} // h has 2 members, named "x" and "y"
a = (x, y)
b = (x, y)
h[a] = 4
h[b] = 5 // h has 3 members, named "x", "y", and "[object Object]"
Put in Python terms, it's as if dict called __repr__ on keys instead of __hash__ (although this isn't quite 100% accurate), which means you can provide a custom toString method to control equal-ness of different instances of your class.

What is this javascript code doing?

this.String = {
Get : function (val) {
return function() {
return val;
}
}
};
What is the ':' doing?
this.String = {} specifies an object. Get is a property of that object. In javascript, object properties and their values are separated by a colon ':'.
So, per the example, you would call the function like this
this.String.Get('some string');
More examples:
var foo = {
bar : 'foobar',
other : {
a : 'wowza'
}
}
alert(foo.bar); //alerts 'foobar'
alert(foo.other.a) //alerts 'wowza'
Others have already explained what this code does. It creates an object (called this.String) that contains a single function (called Get). I'd like to explain when you could use this function.
This function can be useful in cases where you need a higher order function (that is a function that expects another function as its argument).
Say you have a function that does something to each element of an Array, lets call it map. You could use this function like so:
function inc (x)
{
return x + 1;
}
var arr = [1, 2, 3];
var newArr = arr.map(inc);
What the map function will do, is create a new array containing the values [2, 3, 4]. It will do this by calling the function inc with each element of the array.
Now, if you use this method a lot, you might continuously be calling map with all sorts of arguments:
arr.map(inc); // to increase each element
arr.map(even); // to create a list of booleans (even or odd)
arr.map(toString); // to create a list of strings
If for some reason you'd want to replace the entire array with the same string (but keeping the array of the same size), you could call it like so:
arr.map(this.String.Get("my String"));
This will create a new array of the same size as arr, but just containing the string "my String" over and over again.
Note that in some languages, this function is predefined and called const or constant (since it will always return the same value, each time you call it, no matter what its arguments are).
Now, if you think that this example isn't very useful, I would agree with you. But there are cases, when programming with higher order functions, when this technique is used.
For example, it can be useful if you have a tree you want to 'clear' of its values but keep the structure of the tree. You could do tree.map(this.String.Get("default value")) and get a whole new tree is created that has the exact same shape as the original, but none of its values.
It assigns an object that has a property "Get" to this.String. "Get" is assigned an anonymous function, which will return a function that just returns the argument that was given to the first returning function. Sounds strange, but here is how it can be used:
var ten = this.String["Get"](10)();
ten will then contain a 10. Instead, you could have written the equivalent
var ten = this.String.Get(10)();
// saving the returned function can have more use:
var generatingFunction = this.String.Get("something");
alert(generatingFunction()); // displays "something"
That is, : just assigns some value to a property.
This answer may be a bit superflous since Tom's is a good answer but just to boil it down and be complete:-
this.String = {};
Adds an object to the current object with the property name of String.
var fn = function(val) {
return function() { return(val); }
}
Returns a function from a closure which in turn returns the parameter used in creating the closure. Hence:-
var fnInner = fn("Hello World!");
alert(fnInner()); // Displays Hello World!
In combination then:-
this.String = { Get: function(val) {
return function() { return(val); }
}
Adds an object to the current object with the property name of String that has a method called Get that returns a function from a closure which in turn returns the parameter used in creating the closure.
var fnInner = this.String.Get("Yasso!");
alert(fnInner()); //displays Yasso!

Categories

Resources