現在実行中のスクリプトをロードしたスクリプトタグをどのように参照できますか?


303

現在実行中のJavaScriptをロードしたスクリプト要素を参照するにはどうすればよいですか?

これが状況です。「マスター」スクリプトがページの上位に読み込まれています。まず、HEADタグの下にあります。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<script type="text/javascript" src="scripts.js"></script>

「scripts.js」には、他のスクリプトをオンデマンドでロードできるスクリプトが必要です。HEAD要素のレンダリングが完了していないため、HEADタグを参照せずに新しいスクリプトを追加する必要があるため、通常の方法ではうまくいきません。

document.getElementsByTagName('head')[0].appendChild(v);

私がやりたいことは、現在のスクリプトを読み込んだスクリプト要素を参照して、動的に読み込まれた新しいスクリプトタグをDOMの後に追加できるようにすることです。

<script type="text/javascript" src="scripts.js"></script>
loaded by scripts.js--><script type="text/javascript" src="new_script1.js"></script>
loaded by scripts.js --><script type="text/javascript" src="new_script2.js"></script>

1
警告:DOMがまだロードされている間にDOMを変更すると、IE6とIE7に悪影響を与えるでしょう。ページの読み込み後にそのコードを実行したほうがよいでしょう。
トリプティク

6
caniuseで動作しているようです:caniuse.com/#feat=document-currentscript
Tyler

回答:


653

現在のスクリプト要素を取得する方法:

1.使用 document.currentScript

document.currentScript<script>スクリプトが現在処理されている要素を返します。

<script>
var me = document.currentScript;
</script>

利点

  • シンプルで明示的。信頼性のある。
  • スクリプトタグを変更する必要はありません
  • 非同期スクリプト(deferasync)で動作します
  • 動的に挿入されたスクリプトで動作します

問題

  • 古いブラウザとIEでは機能しません。
  • モジュールでは機能しません <script type="module">

2. IDでスクリプトを選択

スクリプトにid属性を指定すると、を使用して、スクリプトをidで簡単に選択できますdocument.getElementById()

<script id="myscript">
var me = document.getElementById('myscript');
</script>

利点

  • シンプルで明示的。信頼性のある。
  • ほとんど普遍的にサポートされています
  • 非同期スクリプトで動作します(deferasync)で動作します
  • 動的に挿入されたスクリプトで動作します

問題

  • スクリプトタグにカスタム属性を追加する必要があります
  • id 一部のブラウザでは、一部のエッジケースで属性がスクリプトの奇妙な動作を引き起こす可能性があります

3.を使用してスクリプトを選択します data-*属性ます

スクリプトにdata-*属性を与えると、スクリプトを簡単に選択できるようになります。

<script data-name="myscript">
var me = document.querySelector('script[data-name="myscript"]');
</script>

これには、前のオプションに比べていくつかの利点があります。

利点

  • シンプルで明示的。
  • 非同期スクリプトで動作します(deferasync)で動作します
  • 動的に挿入されたスクリプトで動作します

問題

  • スクリプトタグにカスタム属性を追加する必要があります
  • HTML5、および querySelector()すべてのブラウザーに準拠していません
  • を使用するよりも広くサポートされていません id属性ません
  • エッジケースで回避<script>idます。
  • 別の要素がページ上の同じデータ属性と値を持っている場合、混乱する可能性があります。

4. srcでスクリプトを選択します

データ属性を使用する代わりに、セレクターを使用して、ソースによってスクリプトを選択できます。

<script src="//example.com/embed.js"></script>

embed.jsで:

var me = document.querySelector('script[src="//example.com/embed.js"]');

利点

  • 信頼性のある
  • 非同期スクリプトで動作します(deferasync)で動作します
  • 動的に挿入されたスクリプトで動作します
  • カスタム属性やIDは不要

問題

  • ないローカルスクリプトで
  • 開発や本番など、さまざまな環境で問題が発生します
  • 静的で壊れやすい。スクリプトファイルの場所を変更するには、スクリプトを変更する必要があります
  • を使用するよりも広くサポートされていません id属性ません
  • 同じスクリプトを2回ロードすると問題が発生します

5.すべてのスクリプトをループして、必要なスクリプトを見つけます

また、すべてのスクリプト要素をループして、それぞれを個別にチェックして、必要なものを選択することもできます。

<script>
var me = null;
var scripts = document.getElementsByTagName("script")
for (var i = 0; i < scripts.length; ++i) {
    if( isMe(scripts[i])){
      me = scripts[i];
    }
}
</script>

これによりquerySelector()、属性で十分にサポートされていない古いブラウザーで以前の両方の手法を使用できます。例えば:

function isMe(scriptElem){
    return scriptElem.getAttribute('src') === "//example.com/embed.js";
}

これは、どのようなアプローチをとってもメリットと問題を継承しますがquerySelector()、古いブラウザでも機能するため、依存していません。

6.最後に実行されたスクリプトを取得する

スクリプトは順番に実行されるため、最後のスクリプト要素は現在実行中のスクリプトになることがよくあります。

<script>
var scripts = document.getElementsByTagName( 'script' );
var me = scripts[ scripts.length - 1 ];
</script>

利点

  • シンプル。
  • ほとんど普遍的にサポートされています
  • カスタム属性やIDは不要

問題

  • 非同期スクリプト(&)では機能しませんdeferasync
  • 動的に挿入されたスクリプトでは機能しません

4
これが答えです。
Royi Namir 2014

1
@RoyiNamirに同意します。これが最良の答えです。
ハンス

27
みんなありがとう、でも私は受け入れられた答えの4 後に答えたよね、そうだね:)
brice

5
「document.currentScript」は、動的に読み込まれるスクリプトでは機能せず、最新のchrome / firefoxではnullを返します。「最後に実行されたスクリプト」は機能します
xwild

1
がShadow DOMに挿入されているscriptと機能しませんtemplate
Supersharp

86

スクリプトは順次実行されるため、現在実行されているスクリプトタグは、それまでは常にページ上の最後のスクリプトタグです。したがって、スクリプトタグを取得するには、次のようにします。

var scripts = document.getElementsByTagName( 'script' );
var thisScriptTag = scripts[ scripts.length - 1 ];

3
これはシンプルでエレガントです。JavaScriptを解凍すると、新しいGoogle Charts / Visualizations APIにその例があります。スクリプトタグ内からJSONデータを読み込みます。次を
Jason Thrasher

1
これは素晴らしいアイデアであり、通常はうまくいきます。ただし、別のスクリプトへの参照を返すことがわかった場合があることも付け加えておきます。理由がわかりません-それを追跡できませんでした。したがって、通常は別の方法を使用します。たとえば、スクリプトファイルの名前をハードコードし、そのファイル名のスクリプトタグを探します。
Ken Smith

53
これが間違った結果を返す可能性があると考えることができる1つの例は、スクリプトタグが非同期でDOMに追加されたときです。
Coffee Bite、

9
はい、これは予期しない結果になる可能性があるので、代わりにセレクターを使用してみることができます:$( 'script [src * = "/ mysource.js"]')???
Jason Sebring

7
ページが読み込まれた後にスクリプトが読み込まれた場合は機能しません。あなたはおそらく正しいタグを取得しません。
ThemeZ 2013

11

おそらく、最も簡単なことは、scripタグにid属性を与えることです。


2
あなたが正しいですが、たくさんのOPの質問が有効である例があり、カップルは次のようになります。1)あなたは2をクロールしているとき)あなたは、クライアントのDOMを操作している、と彼は変更に不本意であるとき
nichochar

10

スクリプトは、「defer」属性または「async」属性がない場合にのみ順次実行されます。スクリプトタグの可能なID / SRC / TITLE属性の1つを知ることは、それらの場合にも機能する可能性があります。したがって、グレッグとジャスティンの両方の提案は正しいです。

の提案はすでにあります document.currentScriptWHATWGリストにます。

編集:Firefox> 4はすでにこの非常に便利なプロパティを実装していますが、前回チェックしたIE11では使用できず、Chrome 29とSafari 8でのみ使用できます。

編集:「document.scripts」コレクションについては誰も言及していませんが、現在実行中のスクリプトを取得するためのクロスブラウザーの代替としては、次のものが良いと思います。

var me = document.scripts[document.scripts.length -1];

1
document.scriptではなくdocument.scriptsです
Moritz

9

document.CurrentScriptこれが存在する場合に活用し、IDでスクリプトを見つけることにフォールバックするポリフィルのビットです。

<script id="uniqueScriptId">
    (function () {
        var thisScript = document.CurrentScript || document.getElementByID('uniqueScriptId');

        // your code referencing thisScript here
    ());
</script>

すべてのスクリプトタグの上部にこれを含めると、どのスクリプトタグが呼び出されているかを一貫して知ることができ、非同期コールバックのコンテキストでスクリプトタグを参照できるようになると思います。

テストされていないので、試してみる場合は他の人にフィードバックを残してください。


id属性があり、無効scriptかかわらず要素。このアプローチではどのような問題が発生する可能性がありますか?
nr

1
@nr-いいえ、すべての要素がid属性を持つことができます。idclass、およびslotDOMレベルではなく、HTMLレベルで定義されています。HTMLグローバル属性に移動し、リストをスクロールすると、「DOM標準は、任意の名前空間の任意の要素のクラス、ID、およびスロット属性のユーザーエージェント要件を定義します」とわかります。続いて、「クラスID、およびスロットの属性は、すべてのHTML要素に指定することができます。」DOM仕様はここでそれをカバーします
TJクラウダー

6

ページの読み込み時と、JavaScriptタグを使用してスクリプトタグが追加されたときに(たとえば、ajaxを使用して)機能する必要があります。

<script id="currentScript">
var $this = document.getElementById("currentScript");
$this.setAttribute("id","");
//...
</script>

3

次の簡単な手順に従って、現在実行中のスクリプトブロックへの参照を取得します。

  1. スクリプトブロック内にランダムな一意の文字列を配置します(一意である必要があります/各スクリプトブロックで異なる)
  2. document.getElementsByTagName( 'script')の結果を繰り返し、各コンテンツからの一意の文字列を検索します(innerText / textContentプロパティから取得)。

例(ABCDE345678は一意のID)

<script type="text/javascript">
var A=document.getElementsByTagName('script'),i=count(A),thi$;
for(;i;thi$=A[--i])
  if((thi$.innerText||thi$.textContent).indexOf('ABCDE345678'))break;
// Now thi$ is refer to current script block
</script>

ところで、あなたの場合は、古い形式のdocument.write()メソッドを使用して、別のスクリプトを含めることができます。DOMはまだレンダリングされていないと述べたように、ブラウザーは常に線形シーケンスでスクリプトを実行するという事実を利用できます(後でレンダリングされる据え置きスクリプトを除く)。したがって、ドキュメントの残りの部分はまだ「存在しません」。document.write()で書き込んだものはすべて、呼び出し元スクリプトの直後に配置されます。

元のHTMLページの例

<!doctype html>
<html><head>
<script src="script.js"></script>
<script src="otherscript.js"></script>
<body>anything</body></html>

script.jsのコンテンツ

document.write('<script src="inserted.js"></script>');

レンダリング後、DOM構造は次のようになります。

HEAD
  SCRIPT script.js
  SCRIPT inserted.js
  SCRIPT otherscript.js
BODY

これはインラインスクリプトでのみ機能し、外部スクリプトでは機能しないようです。後者の場合、innerText、text、およびtextContentのすべてのプロパティは空です。
Jos de Jong

3

非同期および据え置きスクリプトを処理するアプローチは、onloadハンドラーを活用することです。すべてのスクリプトタグにonloadハンドラーを設定し、最初に実行されるものは自分のものにする必要があります。

function getCurrentScript(callback) {
  if (document.currentScript) {
    callback(document.currentScript);
    return;
  }
  var scripts = document.scripts;
  function onLoad() {
    for (var i = 0; i < scripts.length; ++i) {
      scripts[i].removeEventListener('load', onLoad, false);
    }
    callback(event.target);
  }
  for (var i = 0; i < scripts.length; ++i) {
    scripts[i].addEventListener('load', onLoad, false);
  }
}

getCurrentScript(function(currentScript) {
  window.console.log(currentScript.src);
});

3

スクリプトを取得するには、現在ロードされているスクリプトを使用できます

var thisScript = document.currentScript;

スクリプトの最初に参照を保持する必要があるので、後で呼び出すことができます

var url = thisScript.src

2

このアルゴリズムを考えてみましょう。スクリプトがロードされたら(複数の同一のスクリプトがある場合)、document.scriptsを調べ、正しい「src」属性を持つ最初のスクリプトを見つけて保存し、データ属性または一意のclassNameで「visited」としてマークします。

次のスクリプトが読み込まれたら、再度document.scriptsをスキャンし、訪問済みとしてすでにマークされているスクリプトを渡します。そのスクリプトの最初の未訪問インスタンスを取得します。

これは、同一のスクリプトがロードされた順に、ヘッドからボディ、上から下、同期から非同期の順に実行されることを想定しています。

(function () {
  var scripts = document.scripts;

  // Scan for this data-* attribute
  var dataAttr = 'data-your-attribute-here';

  var i = 0;
  var script;
  while (i < scripts.length) {
    script = scripts[i];
    if (/your_script_here\.js/i.test(script.src)
        && !script.hasAttribute(dataAttr)) {

        // A good match will break the loop before
        // script is set to null.
        break;
    }

    // If we exit the loop through a while condition failure,
    // a check for null will reveal there are no matches.
    script = null;
    ++i;
  }

  /**
   * This specific your_script_here.js script tag.
   * @type {Element|Node}
   */
  var yourScriptVariable = null;

  // Mark the script an pass it on.
  if (script) {
    script.setAttribute(dataAttr, '');
    yourScriptVariable = script;
  }
})();

これにより、特別な属性でマークされていない最初の一致するスクリプトのすべてのスクリプトがスキャンされます。

次に、そのノードが見つかった場合は、その後のスキャンで選択されないようにデータ属性でマークします。これは、ノードが再訪問を防ぐために「訪問済み」としてマークされるグラフトラバーサルBFSおよびDFSアルゴリズムに似ています。


Stack Overflowへようこそ。アルゴリズムにコードを含めますか?
Gary99 2017年

Thar you go、@ Gary99
LSOJ

0

これはFF3、IE6、7で機能します。オンデマンドで読み込まれたスクリプトのメソッドは、ページの読み込みが完了するまで利用できませんが、これは非常に便利です。

//handle on-demand loading of javascripts
makescript = function(url){
    var v = document.createElement('script');
    v.src=url;
    v.type='text/javascript';

    //insertAfter. Get last <script> tag in DOM
    d=document.getElementsByTagName('script')[(document.getElementsByTagName('script').length-1)];
    d.parentNode.insertBefore( v, d.nextSibling );
}

0

スクリプトのファイル名を推測できる場合は、それを見つけることができます。これまでのところ、Firefoxで次の機能を実際にテストしただけです。

  function findMe(tag, attr, file) {
    var tags = document.getElementsByTagName(tag);
    var r = new RegExp(file + '$');
    for (var i = 0;i < tags.length;i++) {
      if (r.exec(tags[i][attr])) {
        return tags[i][attr];
      }
    }
  };
  var element = findMe('script', 'src', 'scripts.js');

1
とても時代遅れです。これは、単純なワンライナーであるquerySelectorで実行できます。
Fabian von Ellerts、2018

-1

次のコードが最も一貫性があり、パフォーマンスが高く、シンプルであることがわかりました。

var scripts = document.getElementsByTagName('script');
var thisScript = null;
var i = scripts.length;
while (i--) {
  if (scripts[i].src && (scripts[i].src.indexOf('yourscript.js') !== -1)) {
    thisScript = scripts[i];
    break;
  }
}
console.log(thisScript);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.