Like how you can have:
var obj = {};
obj.a = obj.b = 5;
obj.a === obj.b === 5; //just imagine that it won't evaluate to true === 5
Is there the same thing for object literals? Something along the line of:
var obj = {
a : b : 5
};
obj.a === obj.b === 5; //just imagine that it won't evaluate to true === 5
Is there the same thing for object literals?
No, there isn't. Although you can use any other expression on the right-hand side of the :, including an assignment expression, you can't use another property initialization expression. And you can't use an assignment expression instead (assigning to one of that object's properties) because the object hasn't been assigned to the target variable yet, so you have no way of referencing it.
Related
I understand that the assignment operator is right associative.
So for example x = y = z = 2 is equivalent to (x = (y = (z = 2)))
That being the case, I tried the following:
foo.x = foo = {a:1}
I expected that the object foo would be created with value {a:1} and then the property x will be created on foo which will just be a reference to the foo object.
(This is actually what happens if I was to separate the multiple assignment statement into two separate statements foo = {a:1};foo.x = foo; )
The outcome was actually:
ReferenceError: foo is not defined(…)
So then I tried the following:
var foo = {};
foo.x = foo = {a:1};
Now I don't get the exception anymore but foo.x is undefined!
Why is the assignment not working as I expected?
Disclaimer: The 'duplicate' question seems to be very different to the one that I'm asking, as the issue there is that the variables that were created in the assignment were global, as apposed to variables created with the var keyword. That's not the issue here.
There's an important difference between associativity and order of evaluation.
In JavaScript, even though the assignment operator groups right to left, the operands are evaluated left to right before the actual assignments are performed (which do occur right to left). Consider this example:
var a = {};
var b = {};
var c = a;
c.x = (function() { c = b; return 1; })();
The variable c initially references a, but the right-hand side of the assignment sets c to b. Which property gets assigned, a.x or b.x? The answer is a.x because the left-hand side is evaluated first, when c still references a.
In general, the expression x = y is evaluated as follows:
Evaluate x and remember the result.
Evaluate y and remember the result.
Assign the result from step 2 to the result of step 1 (and return the former as the result of the expression x = y).
What happens with multiple assignments, as in x = (y = z)? Recurse!
Evaluate x and remember the result.
Evaluate y = z and remember the result. To do this:
Evaluate y and remember the result.
Evaluate z and remember the result.
Assign the result from step 2.2 to the result of step 2.1 (and return the former as the result of the expression y = z).
Assign the result from step 2 to the result of step 1 (and return the former as the result of the expression x = (y = z)).
Now let's look at your example, slightly edited:
var foo = {};
var bar = foo; // save a reference to foo
foo.x = (foo = {a:1}); // add parentheses for clarity
foo.x is evaluated before foo gets assigned to {a:1}, so the x property gets added to the original {} object (which you can verify by examining bar).
Edited the answer to make it simple
First of all you have to understand the differnce between Reference- and Value- Type.
var foo = {};
foo variable holds a Reference to an object in memory, lets say A
Now, there are two arts of accessors: Variable Accessor and Property Accessor.
So foo.x = foo = {a:1} can be understood as
[foo_VARIABLE_ACCESSOR][x_PROPERTY_ACCESSOR] = [foo_VARIABLE_ACCESSOR] = {a:1}
!!! Accessor chain is evaluated first to get the last accessor, which is then evaluated associative.
A['x'] = foo = {a:1}
Property Accessor are seperated into setters and getters
var foo = { bar: {} };
foo.bar.x = foo = {a:1}
Here where have decared two nested objects foo and bar. In memory we have then two object A and B.
[foo_VAR_ACCESSOR][bar_PROP_GETTER][x_PROP_ACCESSOR] = [foo_VAR_ACCESSOR] = {a:1}
> A[bar_PROP_GETTER][x_PROP_ACCESSOR] = [foo_VAR_ACCESSOR] = {a:1}
> B[x_PROP_ACCESSOR] = [foo_VAR_ACCESSOR] = {a:1}
> B['x'] = foo = {a: 1}
Here you have little example
var A = {};
var B = {}
Object.defineProperty(A, 'bar', {
get () {
console.log('A.bar::getter')
return B;
}
})
Object.defineProperty(B, 'x', {
set () {
console.log('B.x::getter')
}
});
var foo = A;
foo.bar.x = foo = (console.log('test'), 'hello');
// > A.bar.getter
// > test
// > B.x.setter
Great question. The thing to remember here is that JavaScript uses pointers for everything. It's easy to forget this since it is impossible to access the values representing memory addresses in JavaScript (see this SO question). But realizing this is very important in order to understand many things in JavaScript.
So the statement
var foo = {};
creates an object in memory and assigns a pointer to that object to foo. Now when this statement runs:
foo.x = foo = {a: 1};
the property x is actually getting added to the original object in memory, while foo is getting assigned a pointer to a new object, {a: 1}. For example,
var foo, bar = foo = {};
foo.x = foo = {a: 1};
shows that if foo and bar are pointing to the same object initially, bar (which will still point to that original object) will look like {x: {a: 1}}, while foo is simply {a: 1}.
So why doesn't foo look like {a: 1, x: foo}?
While you are right in that assignments are right associative, you must also realize that the interpreter still reads from left to right. Let's take an in-depth example (with some bits abstracted out):
var foo = {};
Okay, create an object in memory location 47328 (or whatever), assign foo to a pointer that points to 47328.
foo.x = ....
Okay, grab the object that foo currently points to at memory location 47328, add a property x to it, and get ready to assign x to the memory location of whatever's coming next.
foo = ....
Okay, grab the pointer foo and get ready to assign it to the memory location of whatever's coming next.
{a: 1};
Okay, create a new object in memory at location 47452. Now go back up the chain: Assign foo to point to memory location 47452. Assign property x of the object at memory location 47328 to also point to what foo now points to--memory location 47452.
In short, there is no shorthand way to do
var foo = {a: 1};
foo.x = foo;
If I know the variable will be object later, I use:
var obj;
but it doesn't really matter if I initialize it as null or undefined:
var obj = null;
or
var obj = undefined;
For strings I personally use:
var str = '';
as later on I can do
str += 'some text';
and if I use null for example I get "nullsome text".
null, undefined, empty string or 0 are all falsy values so to check if they are defined. which is the correct way to initialize variables if my variable will be used as object, dom node, etc.. ?
It's initialized to undefined by default, just use that, you don't have to write it out:
var obj;
If it you want to concatenate to a string, use '', for counters use 0... Just use common sense.
In an ideal scenario, you'd just declare your variables at the top of the scope like so:
var foo, bar, obj, domNode;
All of these variables will be undefined, as in their value is undefined. If you know for a fact one of these variables will be used as a string in a loop, for example, rather thant writing foo = (foo === undefined ? '' : foo) + 'add this';, just write:
var foo = '', bar, obj, domNode;
If you're going to use the obj var as an object literal, just assign it {my: 'objec', vals: 'here'} when the time comes, or initialize it to {}, and add properties obj.as = 'you'; obj[foo] = 'go';. If you're going to assign a reference to a DOM element, keep it undefined, as any assignment will just generate pointless overhead.
Same goes for any type of reference (function objects, arrays, objects...). Just postpone the assignment, because it'll just overwrite any previous assignment.
As for numbers, undefined + 123 will get evaluate to NaN, so in that case, initializing to 0 makes sense. However, in case of loop counters:
var foo, i, obj, arr = [1,2,3];
for (i=0;i<arr.length;i++)
{
console.log(arr[i]);
}
is equivalent to:
var foo, i= 0, arr = [1,2,3];
for (;i<arr.length;i++)
{
console.log(arr[i]);
}
Only the latter almost looks wantonly complicated. Just use your common sense and you'll be all right.
Just know that variable declarations are hoisted to the top of the scope, but assignments aren't:
console.log(foo);//undefined
var foo = 123;
console.log(foo);//123
because it's translated into:
var foo;
console.log(foo);
foo = 123;
console.log(foo);
So why not write your code as it'll be interpreted by the engine?
The following code :
var obj = {uname:"OdO", age:"22"};
alert(obj.uname);
results in:
OdO
Now, using the same concept in a for..in statement :
for (x in obj) {
document.write(obj.x+"<br>");
}
I expected it to print the following:
OdO
22
but it prints :
undefined
undefined
And to achieve printing looping in the elements, it should be written as an array elements like this:
for (x in obj) {
document.write(obj[x]+"<br>");
}
Then, why the first syntax doesn't work, however it works out of the for..in statement ?
When you write obj.x, this literally looks for a property named "x" in obj — just like obj.size would look for a property named "size". x is not defined for your objects, so it comes out as nothing. The correct way of writing it — obj[x] — uses the variable x to look up a property in the object. The bracket syntax uses the value inside the brackets to look up the property, while the dot syntax turns the property name into a string. So these two are equivalent:
obj.x
obj["x"]
So when you write x after obj., it converts that x into a string — it's not a variable anymore.
The bracket syntax is used to receive a property whose name is the expression (expression can be a literal, a variable or something more complex):
var x = "a";
{a:0, b:1}[x] == 0;
The dot syntax is used to receive the property with exactly that name:
({a:0, x:1}).x == 1;
In your for-in-loop, the variable x holds the property name. You are trying to acess the property named "x", which is not defined.
Use the bracket form (obj[x]) when the property name is stored in a variable named "x" and the attribute form (obj.x) when the property name is literally "x".
For example:
var o = {foo:1};
o.foo; // => 1
var x = 'foo';
o[x]; // => 1, since x='foo' and has a property named "foo".
o.x; // => undefined, since "o" has no property named "x".
Try
for(var x in obj){
console.log(obj[x]);
}
This works for me:
var obj = {uname:"OdO", age:"22"};
for (x in obj) {
document.write(obj[x.toString()] + "<br>");
}
http://jsfiddle.net/zA8HB/
I just started to read some JavaScript project. Most of the .js file to start with have an object declared as the following:
window.Example || {
bleh: "123";
blah: "ref"
}
What does the || symbol do here?
Objects in Javascript are truthy, so that expression evaluates to either window.Example or the default object if window.Example is falsy (or undefined). Example:
var x = window.Example || {foo: 'bar'};
// x = {foo: 'bar'}, since window.Example is undefined
window.Example = {test: 1};
var y = window.Example || {foo: 'bar'};
// y = {test: 1}, since window.Example is truthy (all objects are truthy)
Read this article for a good explanation on truthy/falsy and short-circuit evaluation.
The || operator in JavaScript is like the "or" operator in other C-like languages, but it's distinctly different. It really means:
Evaluate the subexpresson to the left.
If that value, when coerced to boolean, is true, then that subexpression's value (before coercion to boolean) is the value of the || expression
Else evaluate the right-hand subexpression and yield its value as the value of the || expression.
Thus it's used idiomatically to initialize something that might already be initialized:
var something = window.something || defaultValue;
just means, "check to see if "something" is a property of the window object with a truthy value, and if it's not, then set it to defaultValue."
There's an important bit missing from that code - the variable declaration:
var something = window.Example || {
bleh: "123",
blah: "ref"
}
This roughly translates to "set something to window.Example, unless it doesn't exist, then set it to this new object".
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Javascript Shorthand - What Does the '||' Operator Mean When Used in an Assignment?
var variable = obj1 || obj2;
Does it mean this?
var variable;
if (obj1)
{
variable = obj1;
}
else if (obj2)
{
variable = obj2:
}
Is it considered bad practise?
The || operator returns its left hand side if resolves to be a true value, otherwise it returns its right hand side.
So it means the same as:
var variable;
if (obj1){
variable = obj1;
} else {
variable = obj2:
}
Note else, not, else if.
It is a common pattern and not usually considered bad practise.
The gotcha is that you need to be sure you want if (obj) and not if (typeof obj !== "undefined").
Yup, that's what it means, and it's good practice
|| is a logical OR, so if obj1 = false you get false OR obj2 so the variable equals obj2
How || expression works
The expression a || b value is determined by the last partial evaluated to determine Boolean truth.
false || 1 is evaluated as 1 is the last one evaluated.
true || 0 is evaluated as true as it is the last one evaluated.
How obj is evaluated in Boolean context
For an object in the context of Boolean value, object is evaluated to true unless null. It means even {} === true.
Combine the above two explanation, var variable = obj1 || obj2 assigns the first none null object from obj1 and obj2 to variable.