This question already has answers here:
Using the variable "name" doesn't work with a JS object
(4 answers)
Closed 7 years ago.
Lets say we have this code segment :
var name = ["Apples","Oranges","Strawberries"];
console.log(name.length);
This code produces this weird result of 27 !! The issue seems to be with using the variable name as 'name' which seems like a reserved keyword.
But can anyone explain why this weird behavior ?
It refers to window.name, which is the name of the window.
You can use the window's name to target hyperlinks, but it's not typically useful.
More info on window.name: https://developer.mozilla.org/en-US/docs/Web/API/Window.name
Just testing in chrome:
You can't stop var name from being window.name, which is a string. No matter what you set the value to, it will be cast as a string so that it is a valid window name. So, name.length is the amount of characters in the string. It's best to avoid variable or be very careful about them!
As I can see from some of the other comments, this is an odd concept if you're new to it. The concern is over what window.name refers to. window.name is the name of the window. Any use of it is naming the window.
Defending that Chrome's behavior is logical:
If this var document = 'foo' did what it looks like it would do, you would have overwritten window.document - the document object - with a string. That would be quite the problem. name is a property of window just like document and has a use that shouldn't be (and can't be in Chrome) replaced.
In the global scope, when you do var name = ["Apples","Oranges","Strawberries"];, it's the same as window.name = ["Apples","Oranges","Strawberries"];.
window.name must be a string, so it assign ["Apples","Oranges","Strawberries"].toString() to it which is "Apples,Oranges,Strawberries".
What is the scope of variables in JavaScript? is a good start. Basically, when you're declaring name outside of a function, you're actually hiding the window.name value, which is a very, very bad idea (be very careful about any global variables you declare - they are actually values of the window object - including hiding existing values.
As others have said, the fact that Google Chrome forces the type to string is probably a Chrome quirk (although somewhat understandable), but the underlying cause is that you're simply doing something "dangerous" you didn't realize you're doing :)
the window object has a property "name";
if you define 'name' in a closure function you may get 3
you defined var name in the global object, so you just initialized a string obj;
(function(){
var name = ["Apples","Oranges","Strawberries"];
consol.log(name.length);
})()
var name = ["Apples","Oranges","Strawberries"];
the global window.name is a build in string object(reserved), so name.toString() is called when you excuete the line above;
As pointed out by others, in the when you are using the variable named name in the global scope it is treated as window.name.
From experimentation under Google Chrome, window.name gets the value as a string, like so: "Apples,Oranges,Strawberries", This behaviour is because Google Chrome is forcing window.name to be string. This explains why name.length will report 27 as that is the length of the string given.
This behaviour is not present in IE, Opera or Firefox which assing the array ["Apples","Oranges","Strawberries"] and report 3 on `name.length as expected, therefore I guess this is a quirk of Google Chrome.
Related
I'm trying to work out what is considered valid for the property name of a javascript object. For example
var b = {}
b['-^colour'] = "blue"; // Works fine in Firefox, Chrome, Safari
b['colour'] = "green"; // Ditto
alert(b['-^colour']); // Ditto
alert(b.colour); // Ditto
for(prop in b) alert(prop); // Ditto
//alert(b.-^colour); // Fails (expected)
This post details valid javascript variable names, and '-^colour' is clearly not valid (as a variable name). Does the same apply to object property names? Looking at the above I'm trying to work out if
b['-^colour'] is invalid, but works in all browsers by quirk, and I shouldn't trust it to work going forward
b['-^colour'] is completely valid, but it's just of a form that can only be accessed in this manner - (it's supported so Objects can be used as maps perhaps?)
Something else
As an aside, a global variable in javascript might be declared at the top level as
var abc = 0;
but could also be created (as I understand it) with
window['abc'] = 0;
the following works in all the above browsers
window['#£$%'] = "bling!";
alert(window['#£$%']);
Is this valid? It seems to contradict the variable naming rules - or am I not declaring a variable there? What's the difference between a variable and an object property name?
Yes, objects can be used as maps, and any string can be a property name. As you've discovered, some properties can only be accessed using the bracket syntax.
window['abc']
is accessing a property. It is not a variable, even though it refers to the same value (at the global level) as:
abc
Object property naming rules and variable naming rules are separate. The standard only "reserves" a handful of property names (such as prototype and constructor, IIRC), but other than those, any string goes.
Except when the execution environment (i.e. the browser) decides to add more magic properties, of course. (I hear setting __proto__ breaks some things in quite weird ways)
Every time you create a global variable you create in fact a new member of a global object (which is window in browser environment, global in Node.js, etc.). This is why window.x is exactly the same like (global) var x, this.x or just x.
Understanding JavaScript object like a map is quite right, because: a) you can add a new element dynamically - at any moment; b) the element can have any name - also including special characters, c) you can try to access a non-existing element of an object/map and it is not an error, d) you can remove an element from an object.
If you like to access object members with standard dot notation (eg. a.x) you are not allowed to use any special characters different than _ or $; also the name cannot start from a number. For all other cases you are forced to use square brackets and quotation marks to access object elements.
Someone I know is just learning programming and stumbled upon this and left me baffled:
Please open a console (Chrome/Firefox) and type: var name = ['what', 'the', '...?'];
I would expect name to be an array of strings, but:
typeof name displays string instead of Array
listing the name variable prints a string instead of an array
name.length is 13 instead of 3
writing name = name.split(',') returns an array ["what", "the", "...?"] as expected, but name is still a string, not an array
name is the only variable name that seems to behave this way, or at least I couldn't find another one.
Is this just a console quirk, a JavaScript engine bug, or what?
NOTE: the above happens on Chrome and Firefox. IE Edge surprisingly works as expected (typeof name is Array and all that). Not tested on other browsers.
window.name is a global which is a string in the DOM.
Notice you can get around it by declaring the variable in a function scope:
(function() {
var name = ['foo', 'bar'];
console.log(typeof name);
})();
As for why IE/Edge is different - its their interpretation of the spec and likely has been that way for years. Changing it now would be a breaking change.
This question already has answers here:
Do DOM tree elements with IDs become global properties?
(5 answers)
Closed 9 years ago.
If I write html like this:
<div id="foo">Foo<div>
window.foo returns a dom-element and window.document.getElementById("foo") === window.foo returns true.
Why is that? And why does everyone use getElementById?
And on a sidenote: Why was overriding window.foo forbidden in IE7/8? And what happens if I set window.foo = "bar"?
I am not sure about the historical perspective, but HTML 5 specifies that elements are candidates to be directly exposed as properties on the window object if they have an id attribute:
The Window interface supports named properties. The supported property
names at any moment consist of the following, in tree order, ignoring
later duplicates:
[...]
the value of the id content attribute of any HTML element in the active document with a non-empty id content attribute.
The problem with this definition is that it only guarantees that if there is a <div id="foo">Foo<div> then window.foo will be defined. It does not guarantee what exactly its value will be (read the spec for the rules on how that is determined; for example, it might return a collection).
So it turns out the answer to "why use getElementById ever?" is simple: because you can depend on it to return what you expect without needing to take into account the whole document.
In general placing something inside the window object will make it global. For example:
var A = function() {
window.test = "bla";
console.log(test);
}
var B = function() {
console.log(test);
}
A();
B();
However that's not a good practice. You should not rely on any global object, because you may want to move your code to a browser that doesn't have window. Or to nodejs for example.
I find window.foo a little bit wrong, because you may have code that creates a global variable called foo. So, using getElementById ensures you that you always get DOM element.
Window.foo is working fine in your scenario, but what if the Id is something like this "foo-test" instead of "foo", you can see it will not work. it is because Javascript variables are not allowed for dashes in it....
Whereas it will work fine in case of document.getElementById
I tested the following code in IE6, IE7 and IE8 with the same result:
<a name="cd"/>a</a>
<script>
try {
cd = new Date;
} catch(e) {
alert(e);
}
</script>
In all cases an error is thrown. However using
var cd = new Date;
seems to solve the problem.
Does anyone know why that is ?
Here is an example: http://jsbin.com/ahuhu4/2
When you don't use the var specifier to declare your variable, the variable cd is added as a property to the window object, e.g. window.cd. You already have an object element that is a child of window that is <a name="cd">a</a> which is already typed. You can't specify new Date as a type for this object as it already exists. When you use the var keyword, you are rescoping the variable to a local scope and removing its direct attachment to the window object. This removes the error and allows IE to proceed. Other browser engines handle this differently.
IE does you the great favor of creating properties of window for each page element with an "id" value. It's just a thing. (note: this statement is not really true.)
edit — yes, the element doesn't have "id". OK, well good news - IE also treats references by name as if they were by "id". Recall that document.getElementById("cd") on that page would return a reference to the <a>, just as it would if it had an "id" element.
edit again I think it's not quite correct to say that IE creates actualy window properties, at least by my reading of what the IE8 debugger is telling me. It's more like the interpreter treats an implicit reference to a global variable ("cd" in this case) as a request for it to go look for something in the global page context by that name. To IE, that process includes checking the DOM for elements with that "id" or "name" value. By using the var keyword, you're explicitly telling the interpreter that you're declaring a symbol in the applicable scope (global, here), so that "lookup" process is skipped.
//
Firefox does not automatically define global variables for elements with ids or names.
IE including #9, Opera 10, Safari 5 and Chrome 6 all do maintain a global
rollcall of named or id'd elements in the document.
It seems like it could crowd up the global namespace...
function a1(id){
try{
window[id].style.color= 'red';
}
catch(er){
return er.message+'\n'+'window.'+id+' = '+window[id];
}
return 'window.'+id+'='+window[id];
}
function a2(id){
window[id]= 'red';
return 'window.'+id+'='+window[id]
}
/*
firefox returns window[idstring] is undefined.
The others all find it, just like the old IE document.all object.
query the id as a global identifier:
alert(a1('idstring'))
colors the element red and returns[object HTMLButtonElement]
(returns [object Object] in older ie browsers)
assign the global a new value: alert(a2('idstring')) returns 'red'
Try the element again alert(a1('idstring'))
throws an error - Cannot convert 'window[id].style' to object
or Cannot set property 'color' of undefined or
Result of expression 'window[id].style' [undefined] is not an object ot
Object expected
*/
I'm trying to work out what is considered valid for the property name of a javascript object. For example
var b = {}
b['-^colour'] = "blue"; // Works fine in Firefox, Chrome, Safari
b['colour'] = "green"; // Ditto
alert(b['-^colour']); // Ditto
alert(b.colour); // Ditto
for(prop in b) alert(prop); // Ditto
//alert(b.-^colour); // Fails (expected)
This post details valid javascript variable names, and '-^colour' is clearly not valid (as a variable name). Does the same apply to object property names? Looking at the above I'm trying to work out if
b['-^colour'] is invalid, but works in all browsers by quirk, and I shouldn't trust it to work going forward
b['-^colour'] is completely valid, but it's just of a form that can only be accessed in this manner - (it's supported so Objects can be used as maps perhaps?)
Something else
As an aside, a global variable in javascript might be declared at the top level as
var abc = 0;
but could also be created (as I understand it) with
window['abc'] = 0;
the following works in all the above browsers
window['#£$%'] = "bling!";
alert(window['#£$%']);
Is this valid? It seems to contradict the variable naming rules - or am I not declaring a variable there? What's the difference between a variable and an object property name?
Yes, objects can be used as maps, and any string can be a property name. As you've discovered, some properties can only be accessed using the bracket syntax.
window['abc']
is accessing a property. It is not a variable, even though it refers to the same value (at the global level) as:
abc
Object property naming rules and variable naming rules are separate. The standard only "reserves" a handful of property names (such as prototype and constructor, IIRC), but other than those, any string goes.
Except when the execution environment (i.e. the browser) decides to add more magic properties, of course. (I hear setting __proto__ breaks some things in quite weird ways)
Every time you create a global variable you create in fact a new member of a global object (which is window in browser environment, global in Node.js, etc.). This is why window.x is exactly the same like (global) var x, this.x or just x.
Understanding JavaScript object like a map is quite right, because: a) you can add a new element dynamically - at any moment; b) the element can have any name - also including special characters, c) you can try to access a non-existing element of an object/map and it is not an error, d) you can remove an element from an object.
If you like to access object members with standard dot notation (eg. a.x) you are not allowed to use any special characters different than _ or $; also the name cannot start from a number. For all other cases you are forced to use square brackets and quotation marks to access object elements.