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
Related
So I was playing around the other day just to see exactly how mass assignment works in JavaScript.
First I tried this example in the console:
a = b = {};
a.foo = 'bar';
console.log(b.foo);
The result was "bar" being displayed in an alert. That is fair enough, a and b are really just aliases to the same object. Then I thought, how could I make this example simpler.
a = b = 'foo';
a = 'bar';
console.log(b);
That is pretty much the same thing, isn't it? Well this time, it returns foo not bar as I would expect from the behaviour of the first example.
Why does this happen?
N.B. This example could be simplified even more with the following code:
a = {};
b = a;
a.foo = 'bar';
console.log(b.foo);
a = 'foo';
b = a;
a = 'bar';
console.log(b);
(I suspect that JavaScript treats primitives such as strings and integers differently to hashes. Hashes return a pointer while "core" primitives return a copy of themselves)
In the first example, you are setting a property of an existing object. In the second example, you are assigning a brand new object.
a = b = {};
a and b are now pointers to the same object. So when you do:
a.foo = 'bar';
It sets b.foo as well since a and b point to the same object.
However!
If you do this instead:
a = 'bar';
you are saying that a points to a different object now. This has no effect on what a pointed to before.
In JavaScript, assigning a variable and assigning a property are 2 different operations. It's best to think of variables as pointers to objects, and when you assign directly to a variable, you are not modifying any objects, merely repointing your variable to a different object.
But assigning a property, like a.foo, will modify the object that a points to. This, of course, also modifies all other references that point to this object simply because they all point to the same object.
Your question has already been satisfyingly answered by Squeegy - it has nothing to do with objects vs. primitives, but with reassignment of variables vs. setting properties in the same referenced object.
There seems to be a lot of confusion about JavaScript types in the answers and comments, so here's a small introduction to JavaScript's type system:
In JavaScript, there are two fundamentally different kinds of values: primitives and objects (and there is no thing like a 'hash').
Strings, numbers and booleans as well as null and undefined are primitives, objects are everything which can have properties. Even arrays and functions are regular objects and therefore can hold arbitrary properties. They just differ in the internal [[Class]] property (functions additionally have a property called [[Call]] and [[Construct]], but hey, that's details).
The reason that primitive values may behave like objects is because of autoboxing, but the primitives themselves can't hold any properties.
Here is an example:
var a = 'quux';
a.foo = 'bar';
document.writeln(a.foo);
This will output undefined: a holds a primitive value, which gets promoted to an object when assigning the property foo. But this new object is immediately discarded, so the value of foo is lost.
Think of it like this:
var a = 'quux';
new String(a).foo = 'bar'; // we never save this new object anywhere!
document.writeln(new String(a).foo); // a completly new object gets created
You're more or less correct except that what you're referring to as a "hash" is actually just shorthand syntax for an Object.
In the first example, a and b both refer to the same object. In the second example, you change a to refer to something else.
here is my version of the answer:
obj = {a:"hello",b:"goodbye"}
x = obj
x.a = "bonjour"
// now obj.a is equal to "bonjour"
// because x has the same reference in memory as obj
// but if I write:
x = {}
x.a = obj.a
x.b = obj.b
x.a = "bonjour"
// now x = {a:"bonjour", b:"goodbye"} and obj = {a:"hello", b:"goodbye"}
// because x points to another place in the memory
You are setting a to point to a new string object, while b keeps pointing to the old string object.
In the first case you change some property of the object contained in the variable, in the second case you assign a new value to the variable. That are fundamentally different things. The variables a and b are not somehow magically linked by the first assignment, they just contain the same object. That's also the case in the second example, until you assign a new value to the b variable.
The difference is between simple types and objects.
Anything that's an object (like an array or a function) is passed by reference.
Anything that's a simple type (like a string or a number) is copied.
I always have a copyArray function handy so I can be sure I'm not creating a bunch of aliases to the same array.
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]']);
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
The below code is taken from http://bonsaiden.github.com/JavaScript-Garden/
function Foo() {
this.value = 42;
}
Foo.prototype = {
method: function() {}
};
function Bar() {}
// Set Bar's prototype to a new instance of Foo
Bar.prototype = new Foo();
Bar.prototype.foo = 'Hello World';
// Make sure to list Bar as the actual constructor
Bar.prototype.constructor = Bar;
I have come across this explanation multiple times
"When accessing the property of an object, first it checks if the object its self has that property and if not than it goes to the prototype of that object to look for the property and so on."
But I am struggling to understand ho this actually works because of the behavior of the following code
var test1 = new Bar();
var test2 = new Bar();
test1.value = 24;
now value is not part of the test1 object but it is a property of its prototype which is a Foo Object, and since the prototype is a Foo Object all instances of Bar will share the value property, What i expect the above code to do is to set that value property to 24 but instead it creates a new property named 'value' to the test1 object and assigns it 24 leaving the value property in the prototype to its initial value 42. well this doesn't sound like sharing. test2.value still has a value of 42. when i look at the prototype chain in the firebug console it shows me that test1 has a value property with 24 and its prototype has a value property with 42.
This is very confusing to. Has any one you figured out why it behaves this way ?
The prototype chain is only used when reading properties and only if the property is not found in the object itself - it's not used when writing property values.
As soon as you write a property into an object (test1.value = 24) any existing "shared" property in the prototype with the same name is hidden, and all subsequent reads will access the value now store in the object itself.
I think you want .hasOwnProperty()
If that is what you are looking for, someone else has eloquently summed it up here
hasOwnProperty in javascript
EDIT
Having read the other answer, then properly read the questions this time... I'd like to retract that ;-)
...
Or maybe it is what you are looking for, it you want to check whether the property had been set on the 'hash' before doing something else.
I've read this too many times and confused I think, I'll shut up now
Just append the following lines at the end to check what's going on.
var test1 = new Bar();
test1.value = 30;
console.log(test1.hasOwnProperty("value"));
console.log(test1.value);
delete test1.value;
console.log(test1.hasOwnProperty("value"));
console.log(test1.value);
Output:
true
30
false
42
Terms:
hasOwnProperty only returns true is key is the local property of the object.
delete is used to delete local property it does not touch inherited properties.
Explanantion
If we assign a value then it creates it's own local property and overrides the prototypal property. And thus, as local properties has higher preference than prototypal properties, they are read first.
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'.