3

Is there a way to do functions and variable hoisting between source code present in different files? That is, something like

//Inside firstfile.js
foo === "bar" //should return true

and

//Inside secondfile.js
function bar() {
    this.foo = "bar";
}

I guess this is not possible, as different files as parsed and executed separately and in order by most javascript engines, but I do not know for sure.

I don't know even if this is in the spec from ECMA, as the parsing of different files is not really part of the language.

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Andrea
  • 20,253
  • 23
  • 114
  • 183
  • This doesn't seem to have anything to do with hoisting. – Tim Down Nov 10 '10 at 13:33
  • @Tim Down I think the term "hoist" refers to the fact that Javascript interprets function declarations before other code. – Pointy Nov 10 '10 at 13:45
  • Hoisting is the consequence of the fact that function declarations and `var` statements are parsed before code is executed (during the variable instantiation phase), meaning you can do things like `foo(); function foo() { alert("foo"); }`. This question is not doing anything like that. – Tim Down Nov 10 '10 at 13:48
  • @Pointy: Yes, I know, but it's irrelevant. No reference is being made to the function defined in the second file. In fact, the code for the second file as given is a function expression on its own, which is a syntax error. – Tim Down Nov 10 '10 at 13:53
  • Sorry, I was a bit rash and wrote a function expression instead of a declaration. Now I understand the misunderstandings; I have corrected it. – Andrea Nov 10 '10 at 14:13

3 Answers3

6

I originally thought this was a more interesting question than it actually appears. The answer to the question I thought this was is that each <script> element represents a separate Program, each separate Program is parsed and (crucially) executed before anything happens to the next Program, therefore the effects of hoisting can only be seen within a single Program.

For example, within a single script:

<script type="text/javasscript">
    alert(typeof foo);
    function foo() {}
</script>

... alerts "function" because the function declaration is hoisted, but splitting the two lines into separate <script> elements changes this:

<script type="text/javasscript">
    alert(typeof foo);
</script>
<script type="text/javasscript">
    function foo() {}
</script>

... alerts "undefined", because the first script is executed before the second script is even parsed.

Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • Yes, this is what I asked for; basically I just wanted a confirm. Just because I am curious: is this a particular behaviour of the browsers, or is it in the ECMA spec? – Andrea Nov 10 '10 at 13:52
  • 1
    The behaviour of Programs is well defined within the ECMAScript spec. What I've never been able to find is something to specify that each ` – Tim Down Nov 10 '10 at 13:56
  • Thank you for the reference to that question. Essentially it is what I meant to ask, but of course the poster of that question does a much much better job in doing so! – Andrea Nov 10 '10 at 14:17
1

Separately-loaded Javascript sources can all affect the global context. Thus

window.foo = "bar";

in one source file will allow another source (loaded subsequently) to check:

if (window.foo === "bar") {
  // do something
}

This has to work, or else it would not be possible to create something like all the popular Javascript frameworks.

The "this" keyword is only meaningful inside a function, and its value has nothing to do with the source file from which the function came (at least, nothing in any direct sense).

edit — I guess that the interesting thing here is the Javascript interpreter behavior that (to use the term in the question) "hoists" function declarations up before other code in a block being evaluated. That also is done on a script-by-script basis when the browser is loading them. Thus, function declarations in a script block are interpreted before other code in each block, but a single <script> tag will be completely evaluated before the next <script> tag is loaded and evaluated.

Things get more complicated if you're using something like LabJS or enhance.js to load scripts, but I don't know of any context wherein you could rely on scripts "blending together" somehow unless you explicitly combine them at the server.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Of course separately-loaded Javascript sources can all affect the global context. My problem is whether a file can alter the global space for a file which is loaded previously. – Andrea Nov 10 '10 at 13:36
  • As for the use of this, in that context it refers to the global object, so this.foo is just foo. If the two snippets were in the same file, in the order shown in my post, the comparison would return true, even though the value "bar" is assigned AFTER the comparison. My problem is whether this mechanism can work in different files. – Andrea Nov 10 '10 at 13:39
  • Also @Andrea the "this" keyword in that function (which, without a name, is not really very useful) *might* be the global context reference, or it might be something else. – Pointy Nov 10 '10 at 13:47
  • Thank you, that is what I expected. I just wanted to be sure: it would be really useful to be able to do something like this when writing a library. – Andrea Nov 10 '10 at 13:49
  • @Pointy: I believe (I may be proved wrong) that inside function declarations the keyword this always refers to the global object. – Andrea Nov 10 '10 at 13:51
  • 2
    @Andrea: Yes, I'm afraid you are wrong. Function declarations are no different to function expressions in that sense: they both create `Function` objects, and `this` is always specified by how the function is called (e.g. as a simple call, as a method, or using `call()` or `apply()`). You can assign a function created by a function declaration as an object method, just like any other function. – Tim Down Nov 10 '10 at 14:00
1

All script tags that browser encounters are parsed and executed immediately. This is because of document.write API, that might require to browser to output something to the DOM. This means that in this situation #script1's has to finish before #script2.

<script id="script1"></script>
<script id="script2"></script>

You might want to check what the behaviour when using ASYNC and DEFER attributes. They are supported in Webkit.