你能选择包含JavaScript的脚本元素吗?

Can you select the script element that included the JavaScript?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
How may I reference the script tag that loaded the currently-executing script?

有没有一种方法可以选择包含特定脚本的script元素,而不给它任何已知属性?

此示例将警告Window对象,因为它是在全局上下文中调用的:

1
  alert(this);

此示例不起作用,因为脚本的名称可能会更改(为了方便起见,我假设包含jquery):

1
2
3
<script type="text/javascript" src="/foo/bar/baz.js">
//baz.js
$('[src^="baz.js"]');

这个例子是次优的,因为它依赖于id属性:

1
2
<script type="text/javascript" id="foo">
  $('#foo');


在这种情况下,我不愿回答我自己的问题,因为我没有一个100%有效的答案,但我已经消除了足够多的错误,得到了一个稳定的解决方案。

@谢夫的回答是我想要/需要的一半。

通用JS版本:

1
2
3
4
5
6
function getActiveScript()
{
  var s;
  s=document.getElementsByTagName('script');
  return s[s.length - 1];
}

上述代码的问题在于,它将选择页面上的最后一个脚本,无论何时执行。如果在页面加载后包含调用脚本,则这是一个主要问题。

因为我不能直接选择script元素(除非有另一个解决方案出现),所以如果在页面加载后添加脚本,我宁愿不选择任何内容。

纯JS回答:

1
2
3
4
5
6
7
8
9
10
11
function getActiveScript()
{
  var r,s;
  r = document.readyState;
  if ( r && r != 'complete' )
  {
    s = document.getElementsByTagName('script');
    return s.length ? s[s.length - 1] : null;
  }
  return;
}

在新版本中,检查document.readyState以确保文档没有完成加载。另外,在没有使用document.readyState的浏览器上,它会失效(我想不出现在没有使用document.readyState的浏览器)。

对此解决方案的一个警告是,可以动态地将script元素插入文档的早期部分,然后在document.readyState'complete'之前执行。如果脚本要使用此代码,它可能引用了错误的script。我还没有检查过这个问题。通常我会用document.body.appendChild添加新的脚本标签(或者库中的等效标签),所以这对我来说不是什么大问题。

另一个可能的漏洞是,如果在调用getActiveScript之前,一个新脚本被附加到document.body上。同样,我还没有测试它,但这可能意味着最后一个选定脚本的计算结果与正在执行的脚本不同。

实际使用情况:

有人问我为什么要选择当前正在评估的脚本元素。虽然"因为我能"可能会被理解,但我确实有一个合理的理由想要使用这个功能/功能/肮脏的恶意黑客。

我创建了一个(两个)jquery插件来完成我最初想要的工作。

jquery插件:jquery.activesccript.js

1
2
3
4
5
6
7
8
(function($){
 "use strict";
  $.activeScript = function(){
    var r;
    r=document.readyState;
    return r && r != 'complete' ? $('script:last') : $();
  };
})(jQuery);

jquery插件:jquery.activesccript.plugin.js

jquery用户界面默认工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(function($){
 "use strict";
  var plugins,d,p,$p;
  d = $.activeScript().data();
  plugins = d.plugins || 'draggable droppable resizable selectable sortable accordion autocomplete button datepicker dialog progressbar slider tabs';
  plugins=plugins.split(' ');
  $(function(){
    while(p=plugins.pop())
    {
      $p=$(d[p+'Selector']);
      if ($p[p])$p[p]();
    }
  });
})(jQuery);

使用jquery.activescript.plugin.js的方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script type="text/javascript" src="jquery.activescript.plugin.js"
  data-draggable-selector=".draggable.default"
  data-droppable-selector=".droppable.default"
  data-resizable-selector=".resizable.default"
  data-selectable-selector=".selectable.default"
  data-sortable-selector=".sortable.default"
  data-accordion-selector=".accordion.default"
  data-autocomplete-selector=".autocomplete.default"
  data-button-selector=".button.default"
  data-datepicker-selector=".datepicker.default"
  data-dialog-selector=".dialog.default"
  data-progressbar-selector=".progressbar.default"
  data-slider-selector=".slider.default"
  data-tabs-selector=".tabs.default">

这将允许您在语义上将默认插件绑定到页面,而不必在JS文件中纠结。如果需要非默认值,您应该在JS文件中花点时间,所以我没有添加任何用于指定选项的机制(尽管一些插件确实可以使用它)。

独立插件可以使用相同的基本activescript机制来更容易地覆盖默认值。


在包含的脚本中:

1
2
3
(function($){
    var $current_script = $('script:last');
})(jQuery);

Javascript是一种自上而下的语言,因此,执行的最后一个脚本标记将是当前的。


您可以扫描各种脚本的innerhtml,不过对于包含的脚本来说,这并不太好。

1
2
3
$('script').filter(function () {
  return this.innerHTML.indexOf('alert(this)')==0;
});

另外,这需要您找出特定脚本特有的一些字符串。当然,除非你喜欢使用神奇的数字,而宁愿直接访问页面上的第四个脚本。由于0-索引,它只是$('script')[3]