I have the following code snippet below:
var obj = new Object();
var foo = new Object();
var bar = new Object();
obj[foo] = 'hello';
obj[bar] = 'hi'
console.log (obj[foo])
It prints "hi". Why is this?
Objects in JS can have string keys only. When you do obj[foo] actualy you do obj[foo.toString()].
Your code will be
obj["[object Object]"] = 'hello';
obj["[object Object]"] = 'hi'
console.log (obj["[object Object]"])
Objects need a string as reference. Any variable used as key is casted to string with the prototype toString and here you get for this '[object Object]', which is used as key.
var obj = new Object(),
foo = new Object(),
bar = new Object();
obj[foo] = 'hello';
obj[bar] = 'hi'
console.log (obj[foo]);
console.log('' + foo); // force object to use toString() method
console.log (obj['[object Object]']);
you are assigning the object obj with keys which are objects (foo & bar).
When keys given to object are objects themselves then the following is assigned as the key value
[object Object]
this simply means that your 1st assignment
obj[foo] = 'hello'
created key [object Object] and made its value "hello";
then your second assignment did the same, but since the key [object Object] is already present, the previous value got overridden with "hi".
Now when you try to access the property of obj with foo or bar or any other object, you are actually doing
obj["[object Object]"]
You're defining foo as an object, and bar as an object. When you assign them to the original object (obj), you're basically saying this:
obj["Object"] = 'hello';
obj["Object"] = 'hi';
console.log(obj["Object"]); //Will be the last object.
Keys need to be string types. If they're not a string, they will be converted to a string. In the cast of Object() to a string, they'll be turned into [object Object]. Check out this answer for an alternatitve way to override toString()'s functionality to return the object's name, or a unique identifer for the key you're trying to create.
To see this in action, let's do this:
var obj = new Object();
var foo = new Object();
var bar = new Object();
obj[foo] = 'hello';
console.log(obj);
/* Shows:
{
"[object Object]": "hello"
}
*/
obj[bar] = 'hi';
console.log(obj);
/* Shows:
{
"[object Object]": "hi"
}
*/
console.log(obj[foo]); //Will show hi
console.log(obj['[object Object]']); //Essentially the same thing
I have not used the new object constructor on javascript yet, since it is not my preferred language, but the mistake is most likely obvious, you have not assigned anything on your "foo" and "bar" variables, so regardless, their values will be the same, which is the initial value upon declaration of the object without any assignment. What's happening is you are assigning second value on top of your first, which applies to the "obj" array's element.
You are using objects as property-names in your object obj. Property names are strings, therefore your objects are stringified to [object Object]. As both objects are stringified to the same name, bar replaces foo.
The result looks like this:
{
"[object Object]": "hi"
}
Related
var foo = {unique_prop: 1}, bar = {unique_prop: 2}, object = {};
object[foo] = 'anu';
console.log(object[bar]);
The above code outputs "anu".
toString method typecast the non-string object into string object.
In the above code object[bar] outputs the value as 'anu'.
Document says 'since both foo and bar are converted to the same string'
I can't able to understand the java script toString method on this code.
can anybody please explain how it works?
When you use foo's value as a property name, it calls toString on the foo like object[foo.toString()] = 'anu', which if not overridden, will return the same value for every object, which is '[object Object]'
So actually you have a property which name is '[object Object]'.
Below console.logs will assure that you have a property with name '[object Object]'.
var foo = {unique_prop: 1};
var object = {};
object[foo] = 'anu';
console.log(`foo.toString() - ${foo.toString()}`);
console.log(`object.toString() - ${object.toString()}`);
console.log(`object.toString() === foo.toString() ? - ${object.toString() === foo.toString()}`);
for(var prop in object) {
console.log(prop);
}
I've been trying to get a hold of ES2015 map concept and one thing I don't understand is the following:
var mapRawObj = new Map();
var rawObj = {j:"I like penguin"};
mapRawObj.set(rawObj,true);
console.log(mapRawObj.get(rawObj)); //this outputs true
mapRawObj.set({j:"I like polar bear"},true);
console.log(mapRawObj.get({j:"I like polar bear"})); //this outputs undefined
The first one works, the second one doesn't, and I don't understand why?
I thought when you register object as key, it's the object itself, not the object's name. That's why in the below example when you re-assign the key object, it fails as key?
var obj = { a:"hello ", b:"world "};
var mapObj = new Map();
mapObj.set(obj,true);
obj = {d:34}; //obj is re-assigned
console.log(mapObj.get(obj)); // outputs undefined
Objects with the same data are not equal in Javascript, ie
{ hello: 'world'} === { hello: 'world'} // false
The first example uses the same object as the key for set and get, so the key is identical:
var obj = { hello: 'world'};
obj === obj // true
But the second example creates a new object for the get(), which is not identical to the key used to set the value in the map. Since it's not identical, the map doesn't have anything set against this new key and returns undefined.
Even though the new key has exactly the same data as the original key, the objects aren't referring to the same data internally.
More on object equality
I came across this code snippet on Mozilla Developer Network (MDN) and I am racking my brain in trying to figure out why the result would indeed be 'value'
var foo = {unique_prop: 1}, bar = {unique_prop: 2}, object = {};
object[foo] = 'value';
console.log(object[bar]);
I would be grateful if someone would be so kind as to enlighten me!
object[foo] = 'value';
You can only have strings as identifiers and hence when the above runs, JavaScript internally calls ToString method, which represents "[object Object]". That's how objects are represented.
Now when you do object[bar], bar.toString() is also "[object Object]", and since 'value' is stored with "[object Object]" as key, it gets returned.
If you have a quick look in your console, you will see this is because foo is being coerced into a string (since all keys in Javascript are strings**), which defaults to [object object]. The string [object object] is the same for every object, so foo appears to be bar, but in essence it is not. Check out the below output:
var foo = {unique_prop: 1}, bar = {unique_prop: 2}, object = {};
object[foo] = 'value';
var output = document.getElementById('p')
for(thing in object){
output.textContent += thing + " = " + object[thing];
}
<p id='p'></p>
** I think that ES6 has a way of setting a computed key using {[func]: value} syntax, but I have not looked into this very deeply yet, so excuse me for the possible incorrectness.
You can see what's going on here with 3 mini experiments:
What is the result of toString() called on each of the objects you create?
foo.toString(), bar.toString() and object.toString() will output:
[object Object]
What is the result of object[{}]?
it is also "value", because the key that the runtime used to store your value is literally [object Object]
Let's change the behaviour of toString and see what happens.
Object.prototype.toString = function(){
return this.unique_prop;
};
// Re run the code
object[foo] = "value";
console.log(object[bar]); // Returns undefined
// Value was stored under the key "1"
console.log(object[1]); // Returns "value"
Because the key in this object is a string representation of the foo and bar objects, like
Object {[object Object]: "value"}.
As explained above, setting the object property results with an object stringifys the key
> console.log(foo.toString())
[Log] [object Object]
so object[foo] is equivalent to
object["[object Object]"] = 'value';
However if you actually wanted them to be different you could do something like this:
> console.log(JSON.stringify(foo))
[Log] {"unique_prop":1}
> object[JSON.stringify(foo)] = 'donkey'
> console.log(object)
[Log] {[object Object]: "value", {"unique_prop":1}: "donkey"}
> console.log(object[JSON.stringify(bar)])
[Log] undefined
Can you please explain the following piece of code, ? it is working in my browser console. So how does this work ? The new keyword doesnt create a new instance at all or how is it ?
var myObject = new Object(); // Produces an Object() object.
myObject['0'] = 'f';
myObject['1'] = 'o';
myObject['2'] = 'o';
console.log(myObject); // Logs Object { 0="f", 1="o", 2="o"}
var myString = new String('foo'); // Produces a String() object.
console.log(myString); // Logs foo { 0="f", 1="o", 2="o"
Please explain.
if its a new instance how does it carry the value of myObject onto myString variable
It doesn't. You are initialising your String object with a string literal:
new String('foo');
That foo is an entirely different foo to the characters you assign to the three properties of the object. For comparison, replace the second foo with bar.
It's completely normal behavior:
new String creates an Object, if you will type "var myString = new String('moo')", you will get another object with different values.
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/#section_7
Could anyone explain to me why the code sample below reports true? I would have assumed that like in C# the instance of Test1 != instance of Test2.
Update: So I think I will go with some unique identifier stored in the base of both Test1 and Test2.
function Test1() { };
function Test2() { };
var test1 = new Test1();
var test2 = new Test2();
var dict = new Array();
dict[test1] = true;
alert(dict[test2]);
Your object (JavaScript's hashtable) is not using the instance of test1 or test2, but the string representation, as a key. Since both test1 and test2 have the same string representation: "[object Object]", the true value is associated with that key.
Try doing something like below instead:
function Test1(id) { this.id=id };
function Test2(id) { this.id=id };
var test1 = new Test1('1');
var test2 = new Test2('2');
var dict = {};
dict[test1.id] = true;
console.log(dict[test1.id]);
Keys in 'hashtables' (objects, basically) are always strings. So anything you add will be converted to a string.
new Test1();
returns a instance of Test1. Converted as a string, this is:
"[object Object]"
The same goes for Test2. So in fact, when storing true under the key of new Test1() as a string, you are working with the exact same record as the one by obtaining with the key new Test2() as a string. In other words,
(new Test1()).toString() == (new Test2()).toString();
The actual object is therefore simply:
{
"[object Object]": true
}
A solution is overwriting .toString() like this:
Test1.prototype.toString = function() { return "Test1" };
Test2.prototype.toString = function() { return "Test2" };
Then dict[test1] will be stored as dict['Test1'] and dict[test2] as dict['Test2'], which allows you to differ between them. Still, manually setting dict['Test1'] would overwrite things. As far as I know, there is no way to assign an object as a key.
Javascript objects aren't exactly hashtables; they're actually objects with string keys.
When you use an object as a key, the object is converted to a string by calling toString().
toString() will return the same string for all custom classes (unless you create your own toString), so they end up using the same key.
First: Use arrays only for numerical keys. For anything else use objects.
Property names can only be strings. Anything else is converted to its string representation. In case of objects, this is [object Object] or whatever toString() returns.
Which means, that if you want to make both objects distinguishable, you have to override this method and let it return something which is unique to each instance.
This question might help you: Hash/associative array using several objects as key