如何获取当前正在执行的 JavaScript 代码的文件路径

87
我想做类似于C语言的 #include "filename.c" 或者 PHP 中的 include(dirname(__FILE__)."filename.php") 的功能,但是想在 JavaScript 中实现。如果我能获取到 JavaScript 文件加载时的 URL(例如 script 标签中的 src 属性所提供的 URL),那么我就可以实现这个功能。是否有办法让 JavaScript 获取它呢?
另外,有没有一种好的方法可以动态从同一域加载 JavaScript(无需明确知道该域)?例如,假设我们有两个相同的服务器(QA 和生产环境),但它们显然具有不同的 URL 域。是否有一种方式可以像这样使用 include("myLib.js");,其中 myLib.js 将从加载它的文件所在的域中加载?
如果我的表达有点令人困惑,非常抱歉。
12个回答

93

在脚本内部:

var scripts = document.getElementsByTagName("script"),
    src = scripts[scripts.length-1].src;

这个方法有效是因为浏览器按顺序加载和执行脚本,所以当您的脚本正在执行时,包含它的文档一定会把它作为页面中最后一个脚本元素。当然,这段代码必须是脚本的“全局”部分,因此请将src保存在可以稍后使用的地方。通过将其包装在以下代码块中避免泄漏全局变量:

(function() { ... })();

5
只要脚本中的代码是“内联”运行的(即在全局上下文或“立即运行匿名方法”中,正如您建议的那样,而不是在“稍后调用”的函数或设置超时中),这就是一个很好的建议。您可以通过这种方式在每个JavaScript文件/路径中创建一个变量。但要小心,“泄漏全局变量”无法通过我所说的即时运行匿名方法 (function(){...})();来解决 - 您上面的示例仍将创建一个名为src的全局变量,因为它没有var说明符。 - Graza
5
第一行末尾有一个逗号,用于'src' 的变量说明符。 - InfinitiesLoop
1
@InifinitesLoop:在类似问题的另一个答案中,他们建议返回scripts [scripts.length-1] .getAttribute('src',-1)脚本的位置,请参见此处以获取更多信息:https://dev59.com/3XNA5IYBdhLWcg3wYMt-#984656 - Marco Demaio
2
@buley 请看下面我最近的回答。使用 stackinfo 模块(github)从堆栈跟踪中获取文件名可能会对你有所帮助。 - B T
3
如果您的<script>标签不是最后一个,由于各种原因,例如如果您通过JS在<head>开头动态注入该标签,则此方法将无法正常工作。 请参见此评论 - ComFreek
显示剩余7条评论

68

除Internet Explorer(任何版本)外的所有浏览器都具有document.currentScript,它始终有效(无论如何包含文件(异步、书签等))。

如果您想知道当前JS文件的完整URL:

var script = document.currentScript;
var fullUrl = script.src;

Tadaa.


这太棒了,正是我所希望找到的! - Markus
谢谢,我终于找到了解决方案! - Alcalyn
1
我认为了解这一点很重要——如果对象在文件脚本之外初始化,则该路径是不同的——因此,如果有人想要脚本的路径,它必须在该文件脚本的根目录中调用。 - Bruno

27

我刚刚用一个小技巧做到了这个:

window.getRunningScript = () => {
    return () => {      
        return new Error().stack.match(/([^ \n])*([a-z]*:\/\/\/?)*?[a-z0-9\/\\]*\.js/ig)[0]
    }
}
console.log('%c Currently running script:', 'color: blue', getRunningScript()())

screenshot

适用于:Chrome、Firefox、Edge、Opera

享受吧!


1
太好了!我遇到了一个问题,因为我的JavaScript文件是通过Chrome扩展程序插入的,而不是通过常规方式插入的。查看document.currentScript.src并查看之前添加的<script>为空。这个方法完全奏效了。 - evan
另外,我以前从未在console.log中看到过那种颜色技巧。非常酷。 - evan

18

如果您的文档中有内联脚本,则此处接受的答案将无法正常工作。为避免这种情况,您可以使用以下内容仅针对包含 [src] 属性的 <script> 标签进行操作。

/**
 * Current Script Path
 *
 * Get the dir path to the currently executing script file
 * which is always the last one in the scripts array with
 * an [src] attr
 */
var currentScriptPath = function () {

    var scripts = document.querySelectorAll( 'script[src]' );
    var currentScript = scripts[ scripts.length - 1 ].src;
    var currentScriptChunks = currentScript.split( '/' );
    var currentScriptFile = currentScriptChunks[ currentScriptChunks.length - 1 ];

    return currentScript.replace( currentScriptFile, '' );
}

这有效地捕获了最后一个外部.js文件,解决了我在内联JS模板中遇到的一些问题。


非常好用!!!谢谢!!!我尝试了很多解决方案,但都没有取得积极的结果。 - MarianoVolker

9

在这里进一步完善答案后,我得到了以下内容:

getCurrentScript.js

var getCurrentScript = function() {
  if (document.currentScript) {
    return document.currentScript.src;
  } else {
    var scripts = document.getElementsByTagName('script');
    return scripts[scripts.length - 1].src;
  }
}

// module.exports = getCurrentScript;
console.log({log: getCurrentScript()})

getCurrentScriptPath.js

var getCurrentScript = require('./getCurrentScript');

var getCurrentScriptPath = function () {
  var script = getCurrentScript();
  var path = script.substring(0, script.lastIndexOf('/'));
  return path;
};

module.exports = getCurrentScriptPath;

顺便提一下:我正在使用CommonJS模块格式,并且使用webpack打包。


5
我最近发现了一种更加简洁的方法,可以在任何时候执行,而不必强制在脚本加载时同步执行。使用stackinfo获取当前位置的堆栈跟踪,并从堆栈顶部获取info.file名称。请参考stackinfo
info = stackinfo()
console.log('This is the url of the script '+info[0].file)

3

在这里进一步完善答案:

小技巧

getCurrentScript和getCurrentScriptPath

我得出了以下结论:

//Thanks to https://dev59.com/THE95IYBdhLWcg3wkeuq#27369985
var getCurrentScript = function() {

  if (document.currentScript && (document.currentScript.src !== ''))
    return document.currentScript.src;
  var scripts = document.getElementsByTagName('script'),
    str = scripts[scripts.length - 1].src;
  if (str !== '')
    return str ;
  //Thanks to https://dev59.com/THE95IYBdhLWcg3wkeuq#42594856
  return new Error().stack.match(/(https?:[^:]*)/)[0];

};

//Thanks to https://dev59.com/THE95IYBdhLWcg3wkeuq#27369985
var getCurrentScriptPath = function() {
  var script = getCurrentScript(),
    path = script.substring(0, script.lastIndexOf('/'));
  return path;
};

console.log({path: getCurrentScriptPath()})


3

我编写了一个简单的函数,可以通过使用try/catch方法获取当前JavaScript文件的绝对路径。

// Get script file location
// doesn't work for older browsers

var getScriptLocation = function() {
    var fileName    = "fileName";
    var stack       = "stack";
    var stackTrace  = "stacktrace";
    var loc     = null;

    var matcher = function(stack, matchedLoc) { return loc = matchedLoc; };

    try { 

        // Invalid code
        0();

    }  catch (ex) {

        if(fileName in ex) { // Firefox
            loc = ex[fileName];
        } else if(stackTrace in ex) { // Opera
            ex[stackTrace].replace(/called from line \d+, column \d+ in (.*):/gm, matcher);
        } else if(stack in ex) { // WebKit, Blink and IE10
            ex[stack].replace(/at.*?\(?(\S+):\d+:\d+\)?$/g, matcher);
        }

        return loc;
    }

};

你可以在这里查看。

为什么要点踩?考虑添加一条评论吧。无论如何。 - Afonso Matos
5
根据规则,您应该在答案中解释解决方案,而不仅仅是提供链接。如果链接失效,那么您的答案将毫无意义。请注意,此翻译保留原意并尽可能使其更通俗易懂。 - Nicholas Westley
太棒了,感谢分享。此外,您可以检查document.currentScript以防万一它被定义了。 - alecov
2
你应该将那个小的解决方案从Github复制到这里(你可以留下最新版本的链接),这样当你删除或替换Github项目时,它不会变得过时。 - GazB
对我来说,它获取的是第一个脚本,而不是它被调用的位置。 - Flummox - don't be evil SE

1
我可能误解了你的问题,但是看起来只要生产和开发服务器使用相同的路径结构,你应该可以使用相对路径。
<script language="javascript" src="js/myLib.js" />

2
问题在于这个 JavaScript 库是用来在不同的域上加载的。 - B T
这是一个位于一个域上的单个js库文件,需要在多个域上引用吗?还是这是一个位于多个域上的js文件,需要相对于其源拉取其他js文件?您能提供一下您想要实现的示例吗? - johnmdonahue
实际上是两者都有。JS文件将驻留在多个域中(QA与生产环境),并且还将从多个域中包含(任何需要使用库的Web应用程序)。 - B T
这可能是你想要避免的,但你可以将脚本路径硬编码为变量,并拥有开发和生产版本的库,它们之间唯一的区别就是该行代码。或者更简单地,将某些东西作为get参数传递给单个脚本,指定其位置:?devel=true - johnmdonahue
这就是我试图避免的。我也试图避免使用GET参数,但那是一个完全有效的解决方案。只是为此在我们所有的Java Struts中瞎折腾有点懒 : ) - B T

1
无论是脚本、html 文件(例如框架),css 文件,图像等等,如果您没有指定服务器/域名,则 html 文档的路径将是默认值,因此您可以这样做,例如: <script type=text/javascript src='/dir/jsfile.js'></script> 或者 <script type=text/javascript src='../../scripts/jsfile.js'></script> 如果您不提供服务器/域名,则路径将相对于页面或主文档路径的脚本路径。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接