JavaScripの中から別ファイルのJavaScriptを読み込みたいときがよくあります。
複数人で作業するときや、スマホ対応するときに読み込むJavaScriptファイルを動的に変えたり。
いつもHTMLの中に読み込むJavaScriptファイルを固定的に書くのはとてもめんどくさい。
JavaScripファイルを分割して読み込みたい要求はたくさんあります。
しかしWebで調べてもみたのですが、JavaScriptを動的にincludeする方法はChromeで動かなかったり、どれもいまいち。
ということで、JavaScriptファイルを動的に読み込むinclude関数を作ってみました。
読み込む側(main.js)
--------------------------------------
include=function(src){
var xhr=null;
if (window.XMLHttpRequest)xhr=new XMLHttpRequest();
else if(window.ActiveXObject)try {
xhr=new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){xhr=new ActiveXObject("Microsoft.XMLHTTP");}
xhr.open("GET",src,false);xhr.send("");eval(xhr.responseText);
}
include("test.js");
println("Hello!");
--------------------------------------
読み込まれる側(test.js)
--------------------------------------
println=function(src){
alert(src);
}
--------------------------------------
上記場合の注意点として、関数や変数はvarをつけないで「hoghoge=」として宣言しないといけないです。include()関数は内部でeval()関数を使用しているのですが、Chromeとかではeval()関数内で宣言したvar変数や関数がローカル変数として扱われてしまうからです。varをつけないで宣言するとグローバル変数として扱われ、元のJavaScriptファイルから呼び出せます。
でもこれだとincludeされる関数を作るのがめんどくさい・・・。
しかも外部のライブラリ使えないジャン。
じゃあどうするのか。
ここからが本日最大のポイント。
「eval」のところを「(0,eval)」にすればよさそうな気がする。
自分で書いていて思うんですが、
はぁ僕何言っての?
いっている意味まったくもってわからない。
(function(){ return eval;}(0))('hoge');
上記の式が等価なのですが、詳しくは以下のサイトに書いてあります。
http://qiita.com/SFPGMR/items/7a09507eead5b5db8d17簡単にまとめると、JavaScriptのeval関数の仕様では、関数を直接呼び出すと関数内で宣言された変数のスコープが呼び出し元の関数となるのですが、関数を変数経由で間接的に呼び出すと変数のスコープがグローバルになるのです。
そして、eval関数を簡単に間接的に呼び出す方法が、(0,eval)('hoge')なのです。
ということでeval部分を修正してみました。
読み込む側(main.js)
--------------------------------------
function include(src){
var xhr=null;
if (window.XMLHttpRequest)xhr=new XMLHttpRequest();
else if(window.ActiveXObject)try {
xhr=new ActiveXObject("Msxml2.XMLHTTP");
}catch(e){xhr=new ActiveXObject("Microsoft.XMLHTTP");}
xhr.open("GET",src,false);xhr.send("");(0,eval)(xhr.responseText);
}
include("test.js");
println("Hello2!");
--------------------------------------
読み込まれる側(test.js)
--------------------------------------
function println(src){
alert(src);
}
--------------------------------------
やったーinclude関数ができた。
ちゃんとincludeが終わるまで関数をぬけないので、includeが終わった直後からincludeした関数使えるし、includeしたファイルの中からさらにincudeできるし、完璧。
セキュリティーの関係上、他のサーバのファイルはincludeできないのはAJAXと同じです。
eval関数のこの仕様はEcmaScript5から適用されて、それ以前の仕様では変数はローカルスコープになるようです。
したがって、読み込まれる方の関数の形式は後者の方法はInternetExploler8では動かないらしいので、InternetExploler8に対応したい場合は前者の方法で、InternetExploler9以降やスマホのみでよい場合はこの方法が使えます。
読み込む方のinclude関数は後者の方法にしておけばどれでも大丈夫です。
InternetExploler8のシェア2%くらいしかないので、ほとんど無視できますが。
JavaScriptほんとうに奥が深いです。
0 件のコメント:
コメントを投稿