如何从脚本内部获取脚本文件名?

63

我很确定答案是否定的,但还是想问一下。

如果我的网站引用了一个名为"whatever.js"的脚本,是否可以在该脚本内部获取"whatever.js"的文件名?例如:

var scriptName = ???

if (typeof jQuery !== "function") {
    throw new Error(
        "jQuery's script needs to be loaded before " + 
        scriptName + ". Check the <script> tag order.");
}

也许对于依赖项检查来说比它的价值更麻烦,但是管他呢。


既然你将要在文件的某个地方输入那行代码,为什么不直接输入你要添加它的文件名呢? - MarkusQ
是的,这个方法可以工作,除非文件名被更改。我可能只是太过于追求完美了。 - core
嘿,如果有人想提交“少抱怨一点”的答案并且得到了几个赞,我会接受那个作为答案。 :D - core
3
另一个好处是,如果你想获取正在运行的脚本的完整URL路径,这将会很有帮助。并非所有的.js文件都来自于使用它们的HTML页面所在的同一域名。 - Ed Brannin
显示剩余2条评论
13个回答

40
var scripts = document.getElementsByTagName('script');
var lastScript = scripts[scripts.length-1];
var scriptName = lastScript.src;
alert("loading: " + scriptName);

在以下浏览器版本中测试通过:FF 3.0.8、Chrome 1.0.154.53、IE6


另请参阅:如何引用加载当前正在执行的脚本的script标签?


7
边界情况:如果当前脚本被添加到<head><body>加载后,且<body>中存在任何脚本,则此方法将返回<body>中的最后一个脚本,而不是当前正在运行的位于<head>中的脚本。 - Nate
11
我曾遇到过一种情况,这个算法不是很可靠。其他被设置为异步的脚本标签可以在你的脚本请求和运行之间运行。这些脚本可以向DOM添加其他脚本,这些脚本会出现在你的脚本后面。当你的脚本运行时,页面上的最后一个脚本不再是你的脚本,而是返回了错误的“src”。 - Karl
5
这个回答已经严重过时了。脚本可以被延迟加载、异步加载、作为模块加载、或者在Web Worker中执行。这个回答在这些方面都不再适用。 - gman
1
我觉得应该在这里提到document.currentScript,但就像@gman所说的,这个答案总体上已经过时了,而且算法也没有涵盖许多边缘情况。 - Tomáš Hübelbauer

27

我知道这已经过时了,但是因为所有以上的解决方案都不适用于异步脚本,所以我已经开发出了一个更好的解决方案。通过一些调整,以下脚本几乎可以涵盖所有用例。这是对我有用的东西:

function getScriptName() {
    var error = new Error()
      , source
      , lastStackFrameRegex = new RegExp(/.+\/(.*?):\d+(:\d+)*$/)
      , currentStackFrameRegex = new RegExp(/getScriptName \(.+\/(.*):\d+:\d+\)/);

    if((source = lastStackFrameRegex.exec(error.stack.trim())) && source[1] != "")
        return source[1];
    else if((source = currentStackFrameRegex.exec(error.stack.trim())))
        return source[1];
    else if(error.fileName != undefined)
        return error.fileName;
}

不确定在Internet Explorer上是否支持,但在我测试的其他浏览器上都可以正常使用。


谢谢!这正是我一直在寻找的!有趣的是,有时候在Python或Java代码中出现了相同的错误堆栈处理方式。 - scythargon
4
谢谢!这是一个很好的方法,因为它也适用于Web Workers。然而,在代码压缩后它会失败,因为该函数不再被称为getScriptName。解决方法是将currentStackFrameRegex表达式替换为:new RegExp(arguments.callee.name + ' \(.+\/(.*):\d+:\d+\)')。 - MaMazav
1
非常好的解决方案,可惜在IE10以下版本无法使用 :( - psychowood
@PsychoWood 我会看一下,如果我找到解决方案,我会更新答案。 - jduncanator
1
@MaMazav 如果函数被定义为函数表达式,arguments.callee.name 将无法工作。我认为最好的解决方案是用 scriptName 替换 arguments.callee.name,其中 scriptNamevar scriptName = arguments.callee.name || 'getScriptName';。当然,如果函数表达式被分配给普通变量,则缩小会更改变量名,因此必须将函数分配给对象键才能使其正常工作。 - Michael
显示剩余6条评论

21

你可以使用...

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

currentScript() 在所有浏览器中都支持,但 IE。

请确保它在文件解析和执行时运行,而不是在 DOM 准备好或 window 载入时。

如果它是空字符串,则你的 script 块没有或具有空的 src 属性。


1
虽然与答案不直接相关,但著名的 http://caniuse.com 目前还没有监控 document.currentScript。不过已经有人提出了这个问题。如果你想让这个功能出现在 caniuse.com 上,可以投票支持:https://github.com/Fyrd/caniuse/issues/1099。 - Stephan
2
我喜欢这个解决方案即使在“async”脚本中也很有用,而不像其他一些答案。不幸的是,如果在事件处理程序或全局函数中调用currentScript,并且该函数本身是从另一个文件中调用的,则它将返回该其他文件。 - trysis
3
根据@Stephan的评论,现在caniuse.com网站上有一个document.currentScript的条目。 - faintsignal

9
在Node.js中:
var abc = __filename.split(__dirname+"/").pop();

我尝试了这个,但是出现了“__filename未定义”的错误... 我使用方法不对吗? - João Ciocca
9
显然,__filename和__dirname是Node.js的概念,仅在Node.js环境中有效。 - Alichino

5
Shog9的建议更简短:
alert("loading: " + document.scripts[document.scripts.length-1].src);

3
您可以返回页面中脚本元素的列表:
var scripts = document.getElementsByTagName("script");

然后评估每个,并检索其位置:

var location;

for(var i=0; i<scripts.length;++i) {
   location = scripts[i].src;

   //Do stuff with the script location here
}

2

由于“src”属性包含脚本文件的完整路径,因此您可以添加一个子字符串调用来仅获取文件名。

var path = document.scripts[document.scripts.length-1].src;

var fileName = path.substring(path.lastIndexOf('/')+1);

1
如果您不想使用jQuery:
function getCurrentFile() {
    var filename = document.location.href;
    var tail = (filename.indexOf(".", (filename.indexOf(".org") + 1)) == -1) ? filename.length : filename.lastIndexOf(".");
    return (filename.lastIndexOf("/") >= (filename.length - 1)) ? (filename.substring(filename.substring(0, filename.length - 2).lastIndexOf("/") + 1, filename.lastIndexOf("/"))).toLowerCase() : (filename.substring(filename.lastIndexOf("/") + 1, tail)).toLowerCase();
}

1

当调用代码包含在 .html 文件中时,我在提取脚本名称方面遇到了问题。因此,我开发了这个解决方案:

var scripts = document.getElementsByTagName( "script" ) ;
var currentScriptUrl = ( document.currentScript || scripts[scripts.length - 1] ).src ;
var scriptName = currentScriptUrl.length > 0 ? currentScriptUrl : scripts[scripts.length-1].baseURI.split( "/" ).pop() ; 

1
您可以尝试将以下内容放在JavaScript文件的顶部:
window.myJSFilename = "";
window.onerror = function(message, url, line) {
    if (window.myJSFilename != "") return;
    window.myJSFilename =  url;
}
throw 1;

请确保您只有以下这些功能。myJSFilename变量将包含JavaScript文件的完整路径,文件名可以从中解析出来。在IE11中进行了测试,但它应该在其他地方也能工作。


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