Automatically created variables from ids in JS? [d

2020-01-24 12:52发布

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.

标签: javascript
6条回答
虎瘦雄心在
2楼-- · 2020-01-24 13:08

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.

查看更多
我命由我不由天
3楼-- · 2020-01-24 13:13

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.

查看更多
做自己的国王
4楼-- · 2020-01-24 13:16

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).

查看更多
家丑人穷心不美
5楼-- · 2020-01-24 13:16

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.

查看更多
我想做一个坏孩纸
6楼-- · 2020-01-24 13:20

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.

  1. 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.
  2. 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.
  3. 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.
查看更多
我只想做你的唯一
7楼-- · 2020-01-24 13:21

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.

查看更多
登录 后发表回答