I have the following code:
function show(){
var a=document.getElementById('somediv').style.display;
a="block";
}
The above code does not work, it works if we use
{
var a=document.getElementById('somediv');
a.style.display="block";
}
What is wrong with the above code?
To understand this, you will need to understand a bit about javascript assignments.
There are two types of assignment in javascript when you use the = operator: assignment by value and assignment by reference. While some languages give you a choice of which type of assignment you use at any given time, javascript does not give you a choice. It has a strict set of rules for when it uses each.
An "assignment by value" means that a specific value like the number 3 or the string "none" is assigned into another variable.
An "assignment by reference" means that a pointer to the other variable is placed into your new variable and any edit of the contents of that object will be reflected in both places.
For simple types like strings and numbers and booleans, javascript ALWAYS uses assignment by value. For types like arrays and objects, javascript always does an assignment by reference. That means when you do:
var a=document.getElementById('somediv').style.display;
since the value in the display property is a string, javascript will use assignment by value and the value of the string in the display property is copied to the a variable. Once this copy has been made, the a variable has no connection whatsoever with the display property. You can change the display property and a completely independently as they each have their own copy of the string.
So, when you then do:
a="block";
you are just assigning a new string to the a variable as it has nothing to do with the previous display property.
On the other hand, when you did this:
var a=document.getElementById('somediv');
you were assigning an object to a. And, javascript always assigns objects by reference. That means that a has a pointer to the somediv object. There is no copy, they both point to the exact same object. So, any change you make to either reference will actually be changing the same object. So, when you do:
a.style.display="block";
you are changing the actual DOM object.
The rule I remember is that simple types like numbers, strings and booleans are copied when assigned (assignment by value). Complex types like arrays and objects are not copied and only a pointer to the original object is put in the new variable (assigned by reference) so both point to the exact same object.
Assignment by value is pretty simple. Assignment by reference can be both powerful and occasionally confusing enough to cause bugs in software that doesn't anticipate the consequences of a true reference to the original. Because of this, if you ever want an actual copy of an object, you have to explicitly make a copy of the object because an assignment does not do that for you. On the other hand, it can be very useful to have references to complex objects that you can pass around as long as you understand how it works. There is, in javascript, no way to get a reference to a simple type like a number, string or boolean. It can be put into an object (as a property) and you can then pass a reference to the object, but you can't pass a reference to the simple type.
Here are a few examples:
// define person
var person = {height: 66, hair: "blonde"};
// assign the person object to bob
// because person is an object, the assignment is by reference
var bob = person;
// change bob's hair
bob.hair = "red";
// because assignment was by reference, person and bob are the same
// object so changing one changes the one original
alert(person.hair); // red
// define person
var person = {height: 66, hair: "blonde"};
// assign the person's height to a variable
// because height is a number, the assignment is by value (e.g. it's copied)
var myHeight = person.height;
// change both heights
myHeight = 72;
person.height = 60;
// because assignment was by value, myHeight and person.height are
// completely separate copies so changing one does not affect the other
alert(myHeight); // 72
alert(person.height); // 60
The = is an assignment operator. You are placing something inside a variable. In the first case you set a to be the value of display. Which is a string equal to block or none etc.
In the second case you set a to be the object somediv. You then set the display property on it.
The first case doesn't work because your code say: Set the display property of a string. A string has no display property so it fails. It's like saying:
'foobar'.style.display = 'none'
You have write wrong spell of function.
As per your code document.getElementById('somediv').style.display return current display status of div, So its give error for set display block.
You will directly set div display property like this
function show(){
var a=document.getElementById('somediv').style.display="block";
}
Related
What should be the right behaviuor when you have a ng-model declaration like this one?
data-ng-model="elements[0]"
The way it works, if elements is already defined in the scope as an array, it works as I'd expected assigning the first element of the array.
But if elements is not declared it assigns this value :
elements = {0:'anyvalue'}
(which makes sense if I'd had written data-ng-model="elements['0']")
In this case :
elements[0]='anyvalue';
elements['0']='anyvalue';
and I cannot read the value of the propery using "dot" notation (elements.0 or elements.'0').
So it looks correct, but a bit weird.
Is this behaviour correct, or it should instantiate an array when the scope variable is not defined?
An array is just a special type of object. If you look at an array in a debugger, all of the values are listed as properties with numeric keys, like the one you show. If you don't initialize the object as an array, it would still accesses the object in the same way, which just means you now have an object with numeric keys and none of the helpful functions from the Array prototype.
I have object literal within that i have another literal .
The parent instances are setting the values fine, but not the inner one.
I am confused with this behavior.
Why the behavior of object literal is different ?
here is the http://jsfiddle.net/Lq6frf76/
var vehicle={
tires : 0,
seats : {
total :0
}
}
var Car = Object.create(vehicle);
Car.tires=4;
Car.seats.total = 4 ;
var bike = Object.create(vehicle);
bike.tires=2;
bike.seats.total = 2 ;
console.log(Car.tires); --->> it is not overwritten not consistent
console.log(Car.seats.total); -->> it is overwritten here
console.log(bike.tires);
console.log(bike.seats.total);
This is not a duplicate question
I knew the alternatives
I knew inner literal will override I saw lot of examples
What I don't know why the same behavior is not repeated for the parent object or in other words
why car.tires value is showing correctly instead of overwritten in my example
Edit: Added some more at the end and made a correction
I feel like we need to put down an answer here. I apologize if this is bad etiquette (and if this is the wrong answer). Please let me know.
The way prototypical inheritance works in javascript:
When you read a property of an object, lets say the tires property of your Car object, first it checks if Car has that property itself. What that means is, is there a tires property directly attached to the Car object? Or in other words, is Car something like this:
{
tires: 0,
...
}
And the answer is no. You might think Object.create() does this, similar to what you might do in a constructor, i.e.
function Vehice(t) {
this.tires = t;
...
};
var Car = new Vehicle(4);
All Object.create() does is make the object you pass in the prototype of the object it returns to you.
So after Object.create(), your object looks something like this
{
__proto__: //reference to vehicle
}
So when it doesn't find tires directly attached to the object, it then looks at the prototype, in this case a reference to the vehicle object you created earlier. The prototype (vehicle) does have the tires property, so it returns that value.
Correction
So what happens when you say Car.tires = 6? When you write a value to an object property, things work differently. Javascript only looks to see if the object itself has that property to write to. If the object itself doesn't have that property, it first checks down the prototype chain to make sure the property is not an inherited readonly property. If it isn't, it creates that property on the object itself (so long as it's legal to write that property to the object). So now you have something that looks like this:
{
tires: 6,
__proto__: //reference to vehicle
}
End Correction
Now when you read the tires property on the Car object, it first sees the tires property on the Car object itself and returns that value, never needing to look at the prototype.
This is why you can set the tires property on one vehicle and not effect the value of the others.
Now for the seats.total property. When you read from the seats property, everything works as before. There is no seats property on the Car object itself, so it looks to the prototype, which does have it. Then it checks the object referred to by seats to see if it has a total property directly attached to it, and it does, so it just returns that value.
Now when you want to write to the total property, things are once again different. The statement is this: Car.seats.total = 4. What happens here is that you are setting the total property on the object referenced by the seats property.
Javascript first has to find the object referenced by seats. It does this by checking to see if it is a property of the Car object itself. It is not, so it checks the prototype, where it finds the seats property. Now it can write the total property to the seats object as we saw before, but notice that this is happening to the seats property of the prototype, which is a referene to the vehicle object defined before and shared by bike.
In other words, javascript does not see that you are writing to a property of the Car object, so it doesn't create a seats property on the Car object and assign it a new object, and then a total property on that object and assign it 4.
Now, when you try to read bike's seats property, javascript first looks to see if bike has a seats property directly attached to it. It does not, so it looks to bike's prototype, which does have it and returns the modified vehicle.seats object.
I hope this clarifies what is happening and answers your questions. Let me know if any part isn't clear, and I hope someone will correct me if I'm just plain wrong!
Addendum: I think coming from a traditional OO language the way it works for tires is what you would expect to happen: You inherit the initial value, but if you change it, you don't expect it to change for every other instance of vehicle.
The way javascript does this is very space economical. By only initially having the prototype have the property, if you have a thousand objects inheriting from vehicle and only 2 of them set the tires property, you've only used up space for three Numbers instead of a thousand.
As for the way it works with seats, I suppose they could have designed the language to detect if you were setting a property on an inherited object (seats) and then copy the entire object into the instance. My guess is that this would actually make the system less flexible and more complicated. If you wanted Car to have it's own version of seats, you could specify it like so:
var car2 = Object.create(vehicle, {
seats: {
value: {
count: vehicle.seats.total
}
}
});
or like so:
var car2 = Object.create(vehicle);
car2.seats = { count: vehicle.seats.total }; //create a new object like the one attached to vehicle
Does that last example make it clearer what's happening?
To me, in this case, an explicit constructor version of this would be more natural, but with javascript we can use constructors or `Object.create(), or various combinations of them to do what we need.
Ultimately though, Every set happens in two parts. First, find the object we are setting the property on; Last, set the property. Everything before that final . is just there to do the first step:
Car.seats.count = 10 means set the count property of the object referred to by Car.seats to 10. What object is Car.seats? We are now following the rules of reading a property, not writing one. Car doesn't have a seats property, so see if it inherits one. If it doesn't, Car.seats will return undefined, and trying to set a property on undefined will throw an error. If it does inherit it, Car.seats will return the object from somewhere down the prototype chain, in this case the object referred to by vehicle. This object has a count property so just set it to 10.
Car.tires = 4 means set the tires property of the object referred to by Car to 4. Car doesn't have a tires property, so make sure we are allowed to create one and then do so.
I hope this clarifies things. Sorry for writing so much, but doing so has really helped solidify these concepts for me. Plus I learned some ECMAScript 5 stuff that i've been blissfully ignoring :-)
this.lastLocations[0] = this.locations[0];
this.locations[0].x++;
When this code is executed it increments both locations[0].x and lastLocations[0].x. I want it to just change locations[0].x. Is this because javascript is assigning the reference rather than the value? Or is the problem somewhere else in my code?
Objects in javascript are assigned by reference so both your variables are pointing at the exact same object.
So, when you do this:
this.lastLocations[0] = this.locations[0];
Then, both this.lastLocations[0] and this.locations[0] now point to the exact same object. If you make a change to that object via either one of these variables, then that change will show via the other variable (because they both point at the exact same object).
If you want to assign a copy, then you literally have to make a copy of the object (by creating a new object and then copying over all the properties from the original to the new object) and assign that new copy.
There are numerous other posts on methods for cloning/copying an object:
What is the most efficient way to deep clone an object in JavaScript?
How do I correctly clone a JavaScript object?
is it possible in Javascript to tell an object to stop having reference behavior with another object
And, some other related questions:
Do objects pushed into an array in javascript deep or shallow copy?
Javascript by reference vs. by value
Everything in JavaScript is passed and assigned by value.
"Objects" are not values in JavaScript. The only values in JavaScript are primitives and references (pointers to objects). So array1[0] is either a primitive or pointer to an object, and array2[0] is either a primitive or pointer to an object.
When you do array1[0] = array2[0], it assigns the object pointer so that both pointers point to the same object.
Trying to capture the time between keyup and keydown as well as between keyup and the keydown of the next keystroke by writing the time and key data to a global object using keys and values and pushing this object to a global array. The reason for globals is that I don't know how to pass parameters between functions bound to the keydown, keypress and keyup events. Each event driven function has data I want to save in one object as key value pairs such as the key code and the character typed. Each object represents one keystroke but also contains or uses for calculation some information from the previous keystroke.
By the end the data in each element of the global array seems to be either undefined or the last data entered.
My question is why?
I worked around the problem by eliminating the global object(key values) and replacing it with global variables which change with each keystroke. Then I was able to create an object in a function (function scope) and push that object in the global array with each new character. It seems to work. Instinctively it feels like it should be the other way around. I just want to understand why it works this way. I am a third of the way through the book by Zakas and have a lot more to learn.
You are thinking of variables as a box that holds objects. When you do, say a = b, then whatever was in b is copied to a. That is not the way JavaScript works.
Instead, JavaScript works by having an object somewhere, and variables point to that object. Then, when you do a = b, a now points to the same object as b; when a property of b is modified, the same property of a is modified, since the object they point to is the same.
If you want a = b to make a copy, you have to do that explicitly. For example, if you have properties foo and bar, you could do that like this:
a = {
foo: b.foo,
bar: b.bar
};
This only copies down one level, though, so if b.foo is an object too, then a.foo will be referring to the same object as b.foo, and again, modifying any properties of a.foo will make the same changes appear on b.foo, and so on.
I'd really like to track variables without switching between Firebug console windows or clicking around so much, so I want to draw a runtime viewer of variable names and their corresponding values that will display on the page of the app I am building.
I'd like to two functions, show(variableName) and freeze(variableName). They will output both the variable's value and the name of the variable or object as a literal string which will serve as the text label in the viewer. freeze(variableName) is the same as show(variableName) except with a setTimeOut timer for tracking loops.
I'm sure I'm missing something basic, but I haven't found out a way to get the string that comprises the name of a value programmatically so I can use it as a label. I guess I could create the table with hardcoded labels prior to runtime and just populate it with values at runtime, but I really want to generate the table dynamically so it only has those variables I specifically want to show or freeze. Simple functions:
foo1 = "Rock";
show(foo1);
foo2 = "Paper";
show(foo2);
foo3 = "Scissors";
show(foo3);
should output this via getElementById('viewer-table'):
<table>\<tr><td>foo1</td><td>Rock</td></tr><tr><td>foo2</td><td>Paper</td></tr><tr><td>foo3</td><td>Scissors</td></tr></table>
I've tried this solution:
How to convert variable name to string in JavaScript?
and eval() but it's not working for me...I dunno, shouldn't this be easy? Getting frustrated...
Thanks,
motorhobo
I am not sure you can actually get the "name" of the variable that is being passed into a function for two reasons:
1) The variable is just an identifier. In fact, you could have multiple identifiers reference the exact same object. You are (generally) passing that reference, not any actual object.
2) The show/freeze function is going to stomp on the identifier name, either through named arguments in the function declaration or by referencing them through the arguments array.
I was trying to think if there was some clever way to use the arguments.callee or the stack property on an exception in Firefox... but I can't see anything that would expose the arguments as you desire.
What I would recommend is to simply add the name of the variable and its value to a simple object, and call one of the various jsDump methods (I prefer the one in QUnit):
function show(o) {
document.getElementById("viewer-table").innerHTML = QUnit.jsDump(o);
}
// actually use the method
show({"foo1":foo1});
There's no easy way to solve this as the called function simply doesn't know the original name of the variable. You couldn't solve this with reflection even (esp. in javascript) so you'll have to pass the name of the variable to the function too. To follow the link you posted:
function show(varObject)
{
for(name in varObject)
{
alert(name + ": " + varObject[name]);
// save both name and reference to the variable to a local "to observe array"
}
}
And call it with
var test = "xxx";
show({'test' : test});
Within the for loop you could add easy variable to a monitor array and update your gui in fixed time intervalls (you can't be notifed when a signle variable changes it's value. You need some kind of global monitor/observer which exactly you're trying to create).