This question already has answers here:
Do DOM tree elements with IDs become global properties?
(5 answers)
Closed 5 years ago.
Just today after a couple of years of javascript programming I came across something that left me startled. Browsers create objects for every element with an id. The name of the object will match the id.
So if you have:
<div id ="box"></div>
You can do:
alert(box); //[object HTMLDivElement]
Without first assigning anything to that variable. See the demo.
This for some reason seems to be in the standards even though it can break the code in some cases. There is an open bug to end this behavior but I'm more interested in getting rid of it now.
Do you guys know if there is a way to disable this (strict mode maybe)? Am I giving this too much importance? Because it certainly seems like a bad idea. (It was introduced by IE to give you a hint).
Update: It seems FF only does this in quirks mode. Other browsers like IE6+ and Chrome do it right off the bat.
ECMAScript 5 strict should help with this as you cannot use undeclared variables. I'm not sure which browsers currently support strict mode but I know Firefox 4 does.
The HTML spec you linked mentions a proposal to reduce pollution of the global scope by limiting this behavior to quirks-only.
I don't know if this feature is in the original spec but I do expect it to be removed, prohibited or otherwise nullified in subsequent versions of ECMAScript. ES6 will be based on ES5 strict.
JavaScript has many features that make it easier to use for beginners and novices, I suspect this is one such feature. If you're a professional and you want quality code use "use strict"; and always JSLint your code. If you use these guidelines this feature should never bother you.
Here is a useful video about ES5 courtesy of YUI Theater (it's already 2 years old though, but still relevant currently as there is no ES6 yet).
I don't think this is much of a big deal. It seems messy especially to those of us who think about global namespace pollution and conflicts, but in practice it doesn't really cause a problem.
If you declare your own global variable, it will just override anything the browser created for you so there's not really any conflict. The only place I could see it potentially causing a problem is if you were testing for the existence of a global declaration and an "auto" global based on an object ID got in the way of that and confused you.
In practice, I've never seen this to be a problem. But, I'd agree it seems like something they should get rid of or allow you to turn off.
Yes most browsers do this but then again like you said some don't (firefox) so don't count on it. It's also easy to overwrite these variables in js, I can imagine something like container might be overwritten right of the bat by someone using that variable without declaring it first.
There is no way to turn this of in chrome afaik but even then it might be a hassle to figure this out and fix it for all browsers.
Don't give it too much importance, but beware of it. This is one of those reasons why you would evade the global scope for variables.
For the sake of completion, these browsers definitly do it by default: Chrome, IE9 & compat, Opera
Update: Future versions of ECMAScript might include an option of some sort since yes discussion is going on, but that will not fix the 'problem' in older browsers.
I don't think there's a way to disable it, but you don't need to put much importance to it. If you are afraid of unpredictable bugs, you could avoid them by using JSHint or JSLint. They will help you avoid mistakes. For example, they will warn you if you use an undeclared variable.
The problem here is that the global scope has objects defined in it at runtime by the browser, and you would like to prevent these definitions from interfering with your code. I'm not aware of a way to turn off this behaviour, but I do have two workarounds for you:
1) As suggested in the article you linked to, you can work around this by ensuring that you define each variable before you use it. I would achieve this by running my code through JSLint, which warns about this sort of thing (in addition to a bunch of other common errors).
2) However, since it's possible to forget to run your code through JSLint, you might prefer a step in the tool chain that you can't forget. In that case, have a look at CoffeeScript - it's a langauge very similar to javascript that you compile into javascript before use, and it will insert the correct var definitions for you. In fact, I suspect that you can't write code that relies on the automatic element variable creation using CoffeeScript.
This is what I've been able to come up with to remove global variables that are automatically created for DOM objects with an ID value:
function clearElementGlobals() {
function clearItem(iden, item) {
if (iden && window[iden] && (window[iden] === item)) {
window[iden] = undefined;
}
}
var list = document.getElementsByTagName("*");
for (var i = 0, len = list.length; i < len; i++) {
var item = list[i];
clearItem(item.id, item);
clearItem(item.name, item);
}
}
This gets a list of all objects in the page. It loops through looking for ones with an id value and when there's an id value and a global variable exists for it and that global variable points to that DOM object, that global variable is set to undefined. As it turns out browsers also do this same auto-global for some types of tags with a name attribute (like form elements) so we clear those too.
Of course, this code can't know whether your own code makes a global variable with the same name as the id so it would obviously be best to either not do that in your own code or call this function before your global variables are initialized.
Unfortunately, you cannot delete global variables in javascript so setting it to undefined is about the best that can be done.
FYI, I tried doing this the other way around where you enumerate global variables looking for variables that are an instance of HTMLElement and that have a name that matches the id of the element they point to, but I couldn't find a reliable way to enumerate global variables. In Chrome, you can't enumerate them on the window object even though you can access them through the window object. So, I had to go the other way around by getting all DOM objects with an id and looking for globals that match them.
FYI, you asked about strict mode in your question. strict mode only applies to a given scope of code so there would not be any way to cause it to affect the way the global namespace was set up. To affect something like this, it would have to be something at the document level before the document was parsed like a DOCTYPE option or something like that.
Caveats with this function.
Run it before you create any of your own globals or don't create any of your own globals with the same name as the ID or name attribute that also point to that DOM object.
This is a one-time shot, not continuous. If you dynamically create new DOM objects, you would have to rerun this function to clear any new globals that might have been made from the new DOM objects.
The globals are set to undefined which is slightly different than if they were never there in the first place. I can't think of a programming case where it would really matter, but it isn't identical. Unfortunately, you can't delete global variables.
Related
This question already has answers here:
Do DOM tree elements with IDs become global properties?
(5 answers)
Closed 5 years ago.
Just today after a couple of years of javascript programming I came across something that left me startled. Browsers create objects for every element with an id. The name of the object will match the id.
So if you have:
<div id ="box"></div>
You can do:
alert(box); //[object HTMLDivElement]
Without first assigning anything to that variable. See the demo.
This for some reason seems to be in the standards even though it can break the code in some cases. There is an open bug to end this behavior but I'm more interested in getting rid of it now.
Do you guys know if there is a way to disable this (strict mode maybe)? Am I giving this too much importance? Because it certainly seems like a bad idea. (It was introduced by IE to give you a hint).
Update: It seems FF only does this in quirks mode. Other browsers like IE6+ and Chrome do it right off the bat.
ECMAScript 5 strict should help with this as you cannot use undeclared variables. I'm not sure which browsers currently support strict mode but I know Firefox 4 does.
The HTML spec you linked mentions a proposal to reduce pollution of the global scope by limiting this behavior to quirks-only.
I don't know if this feature is in the original spec but I do expect it to be removed, prohibited or otherwise nullified in subsequent versions of ECMAScript. ES6 will be based on ES5 strict.
JavaScript has many features that make it easier to use for beginners and novices, I suspect this is one such feature. If you're a professional and you want quality code use "use strict"; and always JSLint your code. If you use these guidelines this feature should never bother you.
Here is a useful video about ES5 courtesy of YUI Theater (it's already 2 years old though, but still relevant currently as there is no ES6 yet).
I don't think this is much of a big deal. It seems messy especially to those of us who think about global namespace pollution and conflicts, but in practice it doesn't really cause a problem.
If you declare your own global variable, it will just override anything the browser created for you so there's not really any conflict. The only place I could see it potentially causing a problem is if you were testing for the existence of a global declaration and an "auto" global based on an object ID got in the way of that and confused you.
In practice, I've never seen this to be a problem. But, I'd agree it seems like something they should get rid of or allow you to turn off.
Yes most browsers do this but then again like you said some don't (firefox) so don't count on it. It's also easy to overwrite these variables in js, I can imagine something like container might be overwritten right of the bat by someone using that variable without declaring it first.
There is no way to turn this of in chrome afaik but even then it might be a hassle to figure this out and fix it for all browsers.
Don't give it too much importance, but beware of it. This is one of those reasons why you would evade the global scope for variables.
For the sake of completion, these browsers definitly do it by default: Chrome, IE9 & compat, Opera
Update: Future versions of ECMAScript might include an option of some sort since yes discussion is going on, but that will not fix the 'problem' in older browsers.
I don't think there's a way to disable it, but you don't need to put much importance to it. If you are afraid of unpredictable bugs, you could avoid them by using JSHint or JSLint. They will help you avoid mistakes. For example, they will warn you if you use an undeclared variable.
The problem here is that the global scope has objects defined in it at runtime by the browser, and you would like to prevent these definitions from interfering with your code. I'm not aware of a way to turn off this behaviour, but I do have two workarounds for you:
1) As suggested in the article you linked to, you can work around this by ensuring that you define each variable before you use it. I would achieve this by running my code through JSLint, which warns about this sort of thing (in addition to a bunch of other common errors).
2) However, since it's possible to forget to run your code through JSLint, you might prefer a step in the tool chain that you can't forget. In that case, have a look at CoffeeScript - it's a langauge very similar to javascript that you compile into javascript before use, and it will insert the correct var definitions for you. In fact, I suspect that you can't write code that relies on the automatic element variable creation using CoffeeScript.
This is what I've been able to come up with to remove global variables that are automatically created for DOM objects with an ID value:
function clearElementGlobals() {
function clearItem(iden, item) {
if (iden && window[iden] && (window[iden] === item)) {
window[iden] = undefined;
}
}
var list = document.getElementsByTagName("*");
for (var i = 0, len = list.length; i < len; i++) {
var item = list[i];
clearItem(item.id, item);
clearItem(item.name, item);
}
}
This gets a list of all objects in the page. It loops through looking for ones with an id value and when there's an id value and a global variable exists for it and that global variable points to that DOM object, that global variable is set to undefined. As it turns out browsers also do this same auto-global for some types of tags with a name attribute (like form elements) so we clear those too.
Of course, this code can't know whether your own code makes a global variable with the same name as the id so it would obviously be best to either not do that in your own code or call this function before your global variables are initialized.
Unfortunately, you cannot delete global variables in javascript so setting it to undefined is about the best that can be done.
FYI, I tried doing this the other way around where you enumerate global variables looking for variables that are an instance of HTMLElement and that have a name that matches the id of the element they point to, but I couldn't find a reliable way to enumerate global variables. In Chrome, you can't enumerate them on the window object even though you can access them through the window object. So, I had to go the other way around by getting all DOM objects with an id and looking for globals that match them.
FYI, you asked about strict mode in your question. strict mode only applies to a given scope of code so there would not be any way to cause it to affect the way the global namespace was set up. To affect something like this, it would have to be something at the document level before the document was parsed like a DOCTYPE option or something like that.
Caveats with this function.
Run it before you create any of your own globals or don't create any of your own globals with the same name as the ID or name attribute that also point to that DOM object.
This is a one-time shot, not continuous. If you dynamically create new DOM objects, you would have to rerun this function to clear any new globals that might have been made from the new DOM objects.
The globals are set to undefined which is slightly different than if they were never there in the first place. I can't think of a programming case where it would really matter, but it isn't identical. Unfortunately, you can't delete global variables.
I'm working on an application framework written as an object literal and for the sake of simplicity I'd like to do two things:
Have the object available globally
Use the object name (as globally defined) for all references (vs. using this)
So, I've run some tests, done research, and am not finding any good reason NOT to take this approach. My question is - am I missing something? Perf tests actually seem to favor my method and from a logistical level I don't see any issues. Looking at other frameworks I've seen a mix, but I know that the this reference is revered by many programmers.
For reference...
A very minimal example of my approach:
var myobj = {
someVal: 'foo',
init: function(){
// Make myobj available globally
window.myobj = myobj;
// Fire off a method
myobj.doStuff();
},
doStuff: function(){
// Just print out the contents...
console.log(myobj.someVal);
}
}
myobj.init();
Note the references are all to the global, not this.
Like I said, I've seen a mix of this, I guess I just would like to know if this could cause issues in the long-run or if this a much ado about nothing.
As far as limitations go, the first thing that comes to mind is that you could only have one instance of this object. Trying to initialize a new one would wipe out the object.
Another reason for using this rather than a global variable name is that this will point to the correct object even if the name of the variable changes.
If you really want this to be a "create once" global object whose name never changes then this technique isn't technically wrong. But it won't be able to be used in any other situation. It is probably wiser to consider writing code that will be more adaptable if the requirements change (for instance if you use a library that causes a naming conflict with the chosen variable name)
Using this lets you be flexible in renaming the variable and passing it in different contexts without worrying about tracking variable names. It also will make it easy to change if naming conflicts arise.
I've been reading up on global namespace pollution when developing an extension for Firefox, and I want to avoid it as much as possible in my extension. There are several solutions, but generally, the solutions seem to center around only declaring one global variable for your extension, and putting everything in that. Thus you only add one extra variable to the global namespace, which isn't too bad.
As a brief aside, I have had a solution proposed to me that avoids putting any extra variables into the global namespace; wrap everything in a function. The problem here is that there's nothing to refer to in your XUL overlays. You have to declare elements in your overlays, and then in JS add a ton of addEventListeners to replace what would've been something like an oncommand="..." in XUL. I don't want to do this; I definitely want my XUL to include events in the XUL itself because I think it looks cleaner, so this isn't a solution for me. I therefore need at least 1 global variable for XUL oncommand="..." attributes to refer to.
So the consensus seems to be to have one (and only one) variable for your extension, and put all your code inside that. Here's the problem: generally, people recommend that that variable be named a nice long, unique name so as to have almost zero chance of colliding with other variables. So if my extension's ID is myextension#mycompany.com, I could name my variable myextensionAtMycompanyDotCom, or com.mycompany.myextension. This is good for avoiding collisions in the global namespace, but there's one problem; that variable name is long and unwieldy. My XUL is going to be littered with references to event handlers along the lines of oncommand="myextensionAtMycompanyDotCom.doSomeEvent". There's no way to avoid having to refer to the global namespace in my XUL overlays, because an overlay just gets added to the browser window's DOM; it doesn't have a namespace of its own, so we can't somehow limit our extension's variable scope only to our own overlays. So, as I see it, there are four solutions:
1. Just use the long variable name in XUL
This results in rather unwieldy, verbose XUL code like:
<statusbarpanel id="myStatusBar" onmousedown="myextensionAtMycompanyDotCom.onMyStatusBarClick();">
2. Add an element of randomness to a short variable name
We come up with a much nicer short variable name for our extension, let's say myExt, and add some random characters on to make it almost certainly unique, such as myExtAX8T9. Then in the XUL, we have:
<statusbarpanel id="myStatusBar" onmousedown="myExtAX8T9.onMyStatusBarClick();">
Clearly, this results in rather ugly and even confusing code as the random characters look odd, and make it look like some kind of temporary variable.
3. Don't declare any global variables at all
You could just wrap up everything in functions. This, of course, means that there is nothing to refer to in your XUL, and so every event must be attached to the XUL elements using addEventListener in your JavaScript code. I don't like this solution because, as mentioned above, I think it's cleaner to have the events referenced in the XUL code rather than having to search a ton of JS code to find which events are attached to which XUL elements.
4. Just use a short variable name in XUL
I could just call my extension's variable myExt, and then I get nice XUL code like:
<statusbarpanel id="myStatusBar" onmousedown="myExt.onMyStatusBarClick();">
Of course, this short name is much more likely to clash with something else in the global namespace and so isn't ideal.
So, have I missed something? Is there any alternative to the 4 solutions I proposed above? If not, what would be the best of the 4 (given that #3 is basically unacceptable to me), and why?
We use the JavaScript module pattern described in this blog post: http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth. You can export the symbols that you want to use in your XUL handlers as described.
In addition, we use a reversed host name as the module name prefix to ensure that we control the namespace:
/* Set up the global namespace. */
if (typeof(com) == "undefined") var com = {};
if (!com.salsitasoft) com.salsitasoft = {};
/* Main namespace. */
com.salsitasoft.myExtensionGlobalStuffGoesHere = (function (my) {
return my;
})(com.salsitasoft.myExtensionGlobalStuffGoesHere || {});
Update: I changed this to pass com.salsitasoft.myExtensionGlobalStuffGoesHere into the closure if it already exists so that the namespace can be spread across multiple files.
Your functions have to "live" somewhere either way, so you cannot avoid to claim some kind of namespace. I also agree to your point that defining the event in the XUL is better than attaching them. So, I propose a hybrid between 3+4:
Find a namespace that is unique for your plugin yet as catchy as possible, for example "catchyseo".
Place all the code of your plugin and all variables inside this namespace. Use the anonymous function wrapper pattern like (have a look at some jQuery plugins as code examples):
window.catchyseo = (function(){var private = x; [...] })();
In your namespace, expose some event handlers which you can reference in your XUL.
This approach gives you the best of two worlds: you can define your events in XUL and you have a closed namespace without any global namespace pollution - except your one namespace variable.
I was looking over the code for qunit.
My question is why would you want to attach the qunit object via property to window object.
Here is the link to the file. Look at line 11.
If I look at a unit test run using firebug you can see it is a property of window.
[edit]
Additional: Is there a specific reference for best practice for declaring things in specific namespaces?
All global objects (functions, variables, etc) are just children of window, it's the default context.
For example: window.jQuery or window.$
It may be easier to think of it this way...where else would you put them? When you're doing something this general, best (or at least easiest) to stick them in the default place. If you're doing something complex with lots of functions, objects, etc...best to put them in a namespace or within an object. For example all of jQuery's code is under jQuery, not littered in the root of the DOM like window.ajax, instead it's jQuery.ajax.
This is much neater, but perhaps overkill when you're dealing with a few items, but it's a good idea to make sure they are unique if this is the case...which qunit does, by prefixing their objects with qunit-
Attaching globals as properties of window is bad practice. All globals should be declared using var. Here's my reasons:
It makes static analysis of source code much harder. It is impossible to tell from looking at a script which globals will be declared and when. Undeclared globals will create ReferenceErrors if they're used. Using var means JavaScript's hoisting takes effect, and mitigates this problem.
Globals made this way are fundamentally different, and there is no easy way for your code to detect this. The biggest difference is the absence of [[DontDelete]] on globals made this way, which means you can delete your global variables. This is silly.
It will tempt you to declare your globals from outside the global scope. This is magic, and bad magic at that. Don't do it.
As far as I'm concerned, the fact that window.x = 1 creates a global variable named x is an interesting curiosity of JavaScript, but should not be used nor replied upon. There are, however, good reasons to use properties of window, since it's an object like any other (more or less). In these cases, you should use the full name, e.g. window.onload instead of just onload.
Namespaces were once a consideration for ECMAScript (the old ECMAScript 4) but were taken out. As Brendan Eich says in this message:
One of the use-cases for namespaces in
ES4 was early binding (use namespace
intrinsic), both for performance and
for programmer comprehension -- no
chance of runtime name binding
disagreeing with any earlier
binding. But early binding in any
dynamic code loading scenario like
the web requires a prioritization or
reservation mechanism to avoid early
versus late binding conflicts.
Plus, as some JS implementors have
noted with concern, multiple open
namespaces impose runtime cost unless
an implementation works
significantly harder.
For these reasons, namespaces and
early binding (like packages before
them, this past April) must go.
But I'm not sure I understand all of that. What exactly is a prioritization or reservation mechanism and why would either of those be needed? Also, must early binding and namespaces go hand-in-hand? For some reason I can't wrap my head around the issues involved. Can anyone attempt a more fleshed out explanation?
Also, why would namespaces impose runtime costs? In my mind I can't help but see little difference in concept between a namespace and a function using closures. For instance, Yahoo and Google both have YAHOO and google objects that "act like" namespaces in that they contain all of their public and private variables, functions, and objects within a single access point. So why, then, would a namespace be so significantly different in implementation? Maybe I just have a misconception as to what a namespace is exactly.
For the sake of the bounty I'd like to know two things:
Does a namespace need early binding?
How does a namespace implementation
differ from an object with
private members?
If you declare a variable within a closure after a definition of a function will call that variable, it still uses the scoped variable.
function ShowMe() {
alert(myVar); //alerts "cool"
}
var myVar = "cool";
This process would get another layer of complicated with regards to namespacing.
Beyond this there are numerous namespace methods along with expand/applyIf etc that can do a lot of the same functionality. namespace() in ExtJS, or $.extend in jQuery for example. So, it may be a nice to have, but isn't an absolute need within the constructs of the language. I think that formalizing some of the extensions for Array, and support for ISO-8601 dates in Date are far more important myself. Over having to simply check each namespace layer for definition...
window.localization = $.extend(window.localization || {}, {
...
});
window.localization.en = $.extend(window.localization.en || {}, {
...
});
OK first Some of the terminology:
Early binding -- check/validate when the line of code is parsed.
Late binding -- check/validate when the line of code is executed.
Prioritisation/reservation --I think they mean if you do early binding and check the name spaces as the code is parsed there must be a process to validate a variable name when the variable is added dynamically later on and a different set of rules for what is valid as there may be several scopes involved at this point.
I am frankly surprised that only these quite technical reasons were given. Take the common case:-
onclick=' var mymark = "donethat";'
What namespace should "mymark" belong to? There doesnt seem to be any easy answer to that question. Especially given that the code snippet:-
window.forms.myform.mybutton.onClick = ' var mymark = "donethat";'
Should put the variable in the same name space.