Can't use "download" as a function name in javascript
I've had a problem with this little snippet:
<script>
function download() {
alert('Hi');
}
</script>
<a href="#" onClick="javascript:download();">Test</a>
Once I click on the link in Chrome 14.0, I get a
Uncaught TypeError: string is not a function
in Firefox and IE it works just fine. I solved the problem by renaming the function but I'm still curious what's with the "download" thing in Chrome. It's not a reserved keyword as far as I know so what might it be?
<a>
elements have a download
attribute in HTML5 as explained here, with a default value of ""
(an empty string).
This means that download === this.download
in the onclick
handler (this
is the element in onevent
attributes), and therefore the download
attribute of the element is superior to the download
property of window
.
This fiddle lists all string attributes that are present by default. You can see download
is an attribute just like innerHTML
, which also fails with the exact same reason when used as a function (i.e. trying to refer to window.innerHTML
, but instead executing elem.innerHTML()
).
As said in the comments, using window
makes for no confusion as to what property/attribute variables will evaluate to.
This scope behaviour does actually not seem to due to the this
value but rather a specific "scope chain" that is being constructed.
As per the HTML5 specification:
Lexical Environment Scope
Let
Scope
be the result ofNewObjectEnvironment(the element's Document, the global environment)
.If the element has a form owner, let
Scope
be the result ofNewObjectEnvironment(the element's form owner, Scope)
.Let
Scope
be the result ofNewObjectEnvironment(the element's object, Scope)
.
I.e. what is happening is the scope chain is window
-> document
-> element
(increasing superiority). This means that download
evaluates to element.download
and not window.download
. What also can be concluded from this is that getElementById
will bubble up to document.getElementById
(given elem.getElementById
does not exist).
I set up a systematic example so that you can see how variables bubble up the scope chain:
window.a = 1;
document.a = 2;
elem.a = 3;
window.b = 4;
document.b = 5;
window.c = 6;
Then, <a ... onclick="console.log(a, b, c)">
logs 3
, 5
, 6
when clicked.