※この記事は5年以上前の記事です。
現在は状況が異なる可能性がありますのでご注意ください。
どうも、朝からベビースターラーメンをほおばるみやびです。
(メシを食え)
さて、表記の件、実は、けっこう難しくて、長年頭を悩ませていたが、ついに方法を見つけたので、記事に起こしてみた。
例えば、中規模以上のライブラリ、Webアプリケーションを作ったりするときは、だいたいは下記のように、無名関数のスコープ内ないし、名前空間を利用するだろう。(スクリプト汚染を防ぐため)
(function(){ // 生のJS })(); $(function(){ // jQueryだとこれとか }); (function($){ $.fn.hoge = function(){ // jQueryプラグイン内容を定義 }; })(jQuery);
JavaScriptの性質上、基本一つのファイルで完結することが望ましいが、(他の言語よりスパゲティコードになりやすい)
中~大規模の開発の場合、どうしてもファイル分けをして、これらのスコープ内かつ、グローバル変数を定義したいときがある。
そういう時の技として、下記がある。
(function(){ window.hoge = 'aaaaa'; })();
windowオブジェクトに関しては、Webブラウザ上で動くJS限定ではあるが、他のプラットホームでも同様のものがあるはず。
とかく、WebブラウザJSに関しては、ルートで変数を定義した場合、全て関数も含め、windowのプロパティ(ざっくり異訳すると子要素)となるため、それを利用して、windowオブジェクトのプロパティとして、変数や関数を定義することによって、グローバルを定義できるのだ。
だが、このやり方だと、
再代入はできるわ、ぶっ壊すこともできるわで、あまり、スコープから定義した意味がなくなってしまう。
だが、constで変数を定義しようとしてもスコープ内の変数となってしまう。
どうすれば、スコープ内からグローバル変数を、定数っぽく、constで定義したような変数にすることができるのか。
Object.freeze()使えばいんじゃね?と思うかもしれないが、
これは実は、あくまでプロパティの凍結を行うだけで、
変数自体の再代入は可能なのだ。
(function(){ window.hoge = {}; hoge.mogu = 'ak47'; Object.freeze(hoge); hoge = 25; console.log(hoge); // 出力:25 })();
しかし、class構文は、まだ使えるブラウザもそう多くない。
じゃぁ、どうするか。
便利な関数があるんですよ。お兄さん。
(function(){ Object.defineProperty(window, 'hoge', {writable: false, value: 'akb48'}); })();
この、defineProperty、要は、オブジェクトの定数的なプロパティを生成する関数。
もちろん値だけでなく、関数だって定義できる。(さすがゆるガバスクリプト言語)
(function(){ Object.defineProperty(window, 'mogu', {writable: false, value: function(){ // 処理内容 }}); })();
この、defineProperty、constとほぼ同じ挙動をし、
再代入はできないが、プロパティはいくらでも変更可能というもの。
(というか、const出る前に使われていた関数かもしれない)
プロパティも凍結したかったら、freezeとか、sealを使えばいい。(試してないけど多分イケる)
いやー、オブジェクト指向っぽくなんかかっこいいやり方ないか、探しに探してましたが、まさかこんな方法があったとはね。
でも、class構文がどのブラウザでもできるようになれば、こんないらん苦労しなくていいんだけどね 汗
どうにも、ここら辺の制約緩くてかなわんわ、JSは。
さて今回は、JSの変数に関して熱く語ってきましたが、特にSPAやるときなんかはけっこう使えるテクニックなんじゃないかな、と思います。
また、昨今のJS事情として、Web以外でもけっこう広く使われている傾向にあるので、JS自体もけっこう注目されてるんかなーとか個人的に思っており、これからも勉強していこうと思ってます。
ではまた。
コメントする