是否可以在JavaScript中更改函数运行时范围?

时间:2014-09-17 01:00:11

标签: javascript scope

我正在开发一个JavaScript库,而我需要相应地加载不同的模块,我使用回调来加载不同的脚本:

只需在页面中添加main脚本:

<script type="text/javascript" src="main.js"></script>

main.js:

(function () {
    var actionForT2 = function (fun) {
        fun && fun.apply(this);
    }
    var loadCallback = function (name, obj) {
        if (name == "t2") {
            actionForT2(obj);
        }
    }
    window.__jsload = loadCallback;
    var loadJs = function (js) {
        var head = document.head || document.getElementsByTagName('head')[0];
        var script = document.createElement("script");
        script.setAttribute("src", js);
        script.setAttribute("type", "text/javascript");
        head.appendChild(script);
    }
    loadJs("js/t2.js");
})();

t2.js:

__jsload('t2', function () {
    console.info("t2 loaded");
    console.info(loadJs);
})

现在t2.js将按预期加载。我得到了输出:

t2 loaded
ReferenceError: loadJs is not defined

也就是说,loadJs中定义的函数不会访问t2.js函数,然后我想知道是否可以更改加载函数的运行时上下文,例如,当加载函数时被称为:

fun && fun.apply(this);

是否可以在当前匿名函数的上下文中调用fun,然后loadJs可以访问所有已定义的变量,fun等函数,而无需window将它们导出到https://maps.gstatic.com/maps-api-v3/api/js/18/3/main.js


为什么我对这种解决方案感兴趣的是我发现谷歌地图使用回调,例如,当使用谷歌地图v3时,以下脚本将被加载到页面:

map

然后将加载另一个模块https://maps.gstatic.com/cat_js/maps-api-v3/api/js/18/3/{map}.js

{map}.js

当深入到代码时,我发现main.js可以访问{{1}}中定义的变量。但是我找不到魔法是如何发生的。

2 个答案:

答案 0 :(得分:2)

  

是否可以更改函数运行时范围...我想知道是否可以更改已加载函数的运行时上下文,例如,在调用加载的函数时

没有。 Javascript是词法范围的,因此范围完全取决于代码中创建函数的位置,而不是它们调用的位置或它们的调用方式

> fun && fun.apply(this);

这只会设置函数执行上下文的一个参数,即 this 参数。

关于术语 context 存在一般性的混淆。在ECMA-262(支持javascript的语言标准)中, context 仅在execution context中使用,entire environment是函数内的identifier resolution并包含其 this < / em>参数。

调用 apply 方法允许您指定函数 this 的值,就是这样,它们对其没有任何其他影响执行上下文(这就是永远不应被称为“上下文”的原因)。它们对Identifier Resolution, Execution Contexts and scope chains没有任何影响,{{3}}根据范围继续进行,无论 this 的值是什么,或者调用函数的位置。

您可能会发现以下文章:{{3}}。

答案 1 :(得分:0)

你可以把它变成全球性的。由于您已经拥有window.__jsload,因此可以将其附加在那里。

__jsload.loadJs = loadJs;

 // // access like this  :
 // console.info(__jsload.loadJS);

或者,当您从__jsload调用它时,您可以将其传递给回调。

__jsload('t2', function (loadJs) {
   console.info("t2 loaded");
   console.info(loadJs);
}