Why does this property assignment overwrite the prior property in JavaScript? - javascript

var foo = new Object();
var bar = new Object();
var map = new Object();
map[foo] = "foo";
map[bar] = "bar";
alert(map[foo]); //This alerts bar, but what happens to foo?
This is one of those questions to help with your understanding of how keys are assigned in JS. Of course, I immediately tried the following:
for(var prop in map){
console.log(prop + ' ' + map[prop]);
} //[object Object] bar undefined
And then simply:
map //This returns Object {[object Object]: "bar"}
What?
UPDATE:
Thanks for the answers but what happened to foo? Is there some kind of delete mechanism happening I never heard of?

Object bracket notation coerces the value its given to a string. Since your giving it an object, it calls the object's toString method and saves the key as [object Object].
Foo is overridden by bar because you are saving to the same key, [object Object].
Ie. your object looks like this:
{
"[object Object]": "bar"
}

When you use your objects foo and bar as property names, .toString() is implicitly run on them. So you end up with:
map['[object Object]'] = "foo";
map['[object Object]'] = "bar";
alert(map['[object Object]']);

Related

Javascript object property accessed via brackets assigned another property's value?

I know what the following code DOES, I'm just unable to wrap my head around the WHY.
var myObject = new Object();
var foo = new Object();
var bar = new Object();
myObject[foo] = 'foo';
myObject[bar] = 'bar';
console.log(myObject[foo]); // returns bar
console.log(myObject); // returns [object Object]: "bar"
console.log(myObject[blah]); // returns "blah not defined" error.
By this measure, how is myObject[blah] undefined yet myObject[foo] and myObject[bar] are defined - and not only defined, but set to the same value?
According to http://www.w3schools.com/js/js_objects.asp an object's properties can be accessed via object.property or object[property] however if I add in myObject.foo = "foobar"; before the console logs, myObject[foo] does not get set to "foobar" but myObject.foo does.
If I console.log myObject.Object or myObject.object or myObject[object] or myObject[Object] - it all comes back as undefined.
Both foo and bar have values of Object {}. So they aren't being set.
The problem is with types here.
foo is an object, you can't access a property of an object with another object as a key.
Although foo will be converted to a string and no error will occur, be aware that what will finally be evaluated is this:
myObject[foo] = 'foo';
myObject[bar] = 'bar';
Translated to
myObject["[object Object]"] = 'foo';
myObject["[object Object]"] = 'bar';
By this measure, how is myObject[blah] undefined yet myObject[foo] and
myObject[bar] are defined - and not only defined, but set to the same
value?
This message error does not tell you that the key does not exist, as it would not be an error. What it tells you instead is that blah is a variable you are trying to use whereas you never defined it before, thus throwing an undefined reference error.
Also, unrelated but {} syntax is always preferred to new Object()
You're referencing the variable blah which is not defined.
foo and bar are defined but it's very strange to use them as keys in another object. JavaScript doesn't support HashMaps by default, instead it will perform a to-string cast, this produces "[object Object]".
So myObject[foo] and myObject[bar] are both just myObject["[object Object]"]
Did you intend myObject["foo"] and myObject["bar"]"?
The syntax is either:
obj["property"];
// or
obj.property;
// or
var prop = "property";
obj[prop];
By this measure, how is myObject[blah] undefined
myObject[blah] is undefined because your trying to add the object blah which is not existing or undefined (thats what the interpreter is complaining when you open the console)
so if you would have said
var blah= new Object();
myobject[blah] would have worked fine.
yet myObject[foo] and myObject[bar] are defined - and not only defined, but set to the same value
The reason being similar to the above one, since you have defined foo and bar by declaring them as objects
var foo = new Object();
var bar = new Object();
the reason they have the same value is because you assigned them with those values
myObject[foo] = 'foo';
myObject[bar] = 'bar';
According to http://www.w3schools.com/js/js_objects.asp (Try to use MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Objects)... however if I add in myObject.foo = "foobar"; before the console logs, myObject[foo] does not get set to "foobar" but myObject.foo does.
This part has been answered well in the other two answers, but for the sake of completion.
when you say myObject.foo , it creates a new 'property' ,if not already present, called 'foo' for 'myobject'.
The other way when you say
myobject["foo"] //-> NOTE foo is a string. A property is created.
However when you have
var foo = new object();
myobject[foo] // this is not correct since foo is an object here not a string
//or a property. inshort adding objects as property not a good idea.
If I console.log myObject.Object or myObject.object or myObject[object] or myObject[Object] - it all comes back as undefined.
myObject.Object // there is no property called 'Object', 'object' in myobject
However, if you say
myObject.object = "added object property"; //OR
myObject["object"] = "added object property";
then try the above console.log commands it should work, but note that properties are case sensitive

is function an object? Why console.log does not show inspectable Object?

var foo = function () {};
foo.a = "an attribute"; // set attribute to prove foo is an object
console.log(foo) // log shows: function () {};
I thought function foo is an object, but why console.log in Chrome shows "function () {}" rather than an inspectable Object? Is there anyway to show inspectable Object when logging a function?
When you call console.log(foo), the console builds a non normalized display (it's not part of EcmaScript). In most cases (but not for basic objects) it calls the toString function of the argument (but does more work, like adding quotes to string, setting a color, offering object browsing, etc.).
The toString function of a function simply prints the code.
If you want to see all properties, you might do
console.dir(foo);
or (at least on Chrome)
console.log("%O", foo);
You'd see the same phenomenon with other objects having a dedicated toString function.
For example :
var a = new Number(3);
a.b = 4;
console.log(a); // logs just 3
console.dir(a); // lets you see b
Use console.dir() to see the a
>>>>console.log(foo);
function()
>>>>console.dir(foo);
a "an attribute"
prototype Object { }
dystroy is right. function is an object whose toString prints the code.
console.log(foo.a);
would do the trick

Why declare a variable as a new Object?

As a beginner, working with existing code, I've come across the following:
var foo = {};
which I believe is equivalent to:
var foo = new Object();
I was under the impression that any variable was automatically an Object, so what would be the purpose of specifically coding that, rather than just declaring an empty variable:
var foo;
I was under the impression that any variable was automatically an Object
That is a mistaken impression. If you declare a variable and do not assign it a value, it is initialised to undefined (as mention in the spec and described in detail), which is not an object (it's a primitive value):
var foo;
console.log(foo); // undefined
If you were to attempt to set a property of an undefined variable you would receive a TypeError:
var foo;
foo.example = "hello"; // TypeError: Cannot set property 'example' of undefined
However, if you assign an empty object to that variable, the above code will succeed:
var foo = {}; // Now refers to an empty object (equivalent to `new Object()`)
foo.example = "hello";
console.log(foo); // '{example:"hello"}'
I believe your understanding probably stems from the common misunderstanding that "everything in JavaScript is an object". This is not true. Many things in JavaScript are objects, but primitive values are not. For example:
var a = "hello"; // String primitive, not an object
var b = new String("hello"); // String instance, object
var c = 10; // Number primitive, not an object
var d = true; // Boolean primitive, not an object
var e; // Undefined value, not an object
var f = null; // Null value, not an object
James's answer is correct. In case he's throwing too much info too quickly (refer back to it later, if so), here's a quick summary.
You are correct in this: var foo = {} and var foo = new Object() are not only equivalent, the results are identical. Only use object literals. (ignore new Object(), new Array(), etc).
var foo; does nothing other than declare a variable. It is 'undefined' by default.
var foo = new Object() also gives the new object a prototype property which can be used to manipulate object inheritance and call standard object functions defined by javascript
see here for details on how you can manipulate the object.protype:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/prototype

What does the object[foo] term mean?

I'm confused what the object[foo] term is referring to. Any hints? I know that bar['unique_prop'] and bar.unique_prop refers to 2
var foo = {unique_prop: 1};
var bar = {unique_prop: 2};
var object = {};
object[foo] = 'value';
alert(object[bar]);
code on jsfiddle
This:
var foo = 'abc';
object[foo]
is equivalent to:
object.abc
However this:
var foo = {unique_prop: 1};
object[foo] = 'value';
Doesn't have much sense (object property names cannot be object literals). JS engine will use foo.toString() (returning e.g. "[object Object]"), so in fact you are doing this:
var foo = {unique_prop: 1};
object["[object Object]"] = 'value';
which is clearly a bug or a misunderstanding. This behaviour is explained in Member Operators on MDN:
Property names must be strings. This means that non-string objects cannot be used as keys in the object. Any non-string object, including a number, is typecasted into a string via the toString method.
You can however use:
object[foo.unique_prop] = 'value';
which is equivalent to:
object[1] = 'value';
It is the same as object.whatever_x_is where x is foo.toString() which will be the same as bar.toString() since (unless overridden) calling toString on a generic object will generate a generic "is an object" string such as "[object Object]"
object[foo] = 'value';
attempts to use an object as a member name, this causes a .toString() call so;
'value' is assigned to object["[object Object]"], when you attempt to read alert(object[bar]); the same toString() occurs as bar is also an object, so you reference object["[object Object]"] once again and get back 'value'.

Question about Javascript properties and instances

I can't figure out myself why foo.bar in the example is undefined, could you explain?
var foo = "foo";
foo.bar = "baz";
console.log(foo.bar); // undefined
Q2: How do I add references to properties and methods to the String instance foo?
Help is appreciated, thanks.
-- EDIT --
Note: the question is about a generic String instance, not the String global object. So using "classic" prototyping as someone suggested is not an option, because this way every String instance would have a property called bar, while I want to augment only certain instances.
This is a duplicate of Why can't I add properties to a string object in javascript?.
Basically, you're creating a string, and this is a primitive type in javascript.
You cannot add properties to primitive types in javascript.
By using a real String object for foo:
var foo = new String('foo');
foo.bar = 'baz';
console.log(foo.bar); // 'baz'
foo.bar = "baz"; is the same as undefined = "baz";
You can add functions to string by using it's prototype;
String.prototype.bar = function() {
return "baz";
};
foo.bar() ; //# => baz
When you specified var foo = "foo"; you are asking foo to be interpreted as a string. String can only have a literal as a value. It cannot have any other sub-properties. ( just extend this logic to any other oo programming language you know and it will become clearer). Instead you could do something like this.
var fooObject = new Object()
fooObject.foo = "foo"
fooObject.bar = "baz"
You're talking about "prototyping", which is the ability to add custom properties to objects in javascript.
This is an excellent and concise tutorial on prototyping:
http://www.javascriptkit.com/javatutors/proto.shtml
To extend the String class, modify its prototype:
String.prototype.bar = "baz";
var foo = "foo";
console.log(foo); // "foo"
console.log(foo.bar); // "baz"
In your question, you were modifying an instance of the String class instead of the String class itself.

Categories