ワテも最近勉強し始めたTypeScriptであるが、難しい。
JavaScriptを習い始めた当初も、undefinedやnullで悩んだ。
この記事では、JavaScriptの void 0 や undefined の意味を備忘録としてまとめておく。
これらは、JavaScriptのコードの中に良く登場するので、その意味を理解しておくと良いだろう。
では、本題に入ろう。
TypeScriptの void 0 とは何か?
TypeScriptで例えばこんなふうに書いて、関数myfunc()を定義する。
module mymod { export function myfunc(i = 0) { alert('i=' + i); } }
関数の引数はmyfunc(i=0)のような記述が可能で、もしiが与えられない場合にはデフォルトの引数0を使うと言う意味だ。
Visual Studio2015では、このTypeScriptは以下のようにJavaScriptに自動変換された。
var mymod; (function (mymod) { function myfunc(i) { if (i === void 0) { i = 0; } alert('i=' + i); } mymod.myfunc = myfunc; })(mymod || (mymod = {}));
なんだか見慣れぬ記述がある。
if (i === void 0) { i = 0; }
だ。
void 0
って何やねん?
分からん。
void演算子
そういう時はStackOverflowだ。
最近は、プログラミング関係で検索する場合には、まずは英語版のStackOverflowを見るようにしている。
そういう場合は、Google検索でもYahoo検索でもBing検索でも、検索時には
とすれば確実だ。
つまり質問文の後にsite:を指定するとそのサイト内から検索される。
で、第一位のヒット結果がこれだ。
javascript – What does `void 0` mean? – Stack Overflow
ワテの質問と全く同じ質問を見つけたぞ。
その回答を見てみたら、
voidという演算子(operator)は引数を一個取り、必ずundefinedをリターンする
と言う事だ。
例
void 0 void (0) void "hello" void (new Date())
どれもundefinedが得られる。
void 引数 void(引数)
のどちらの形式も可能だ。
ん?待てよ、
何でこんなvoidとかいう演算子が必要なのか?
と言う疑問が湧く。
その前に、JavaScriptの鬼門である、nullとundefinedを復習しておく。
JavaScriptのnullとundefinedを考察する
JavaScriptには
null undefined
という、似たような属性?がある。
JavaScriptを習得し始めた頃は、ワテは良く混乱していた。
ワテの場合にはC, C++でのプログラミング経験が長いので、何かが空の状態を表す属性は一つで十分でCならNULLが一つあればワテは足りる。
ptr = (char **) malloc (MAXELEMS * sizeof(char *)); free(ptr); ptr=NULL;
freeしたポインタは必ずNULLを入れる習慣を付けておくほうが良い。
もしC++の列挙型を自前で定義した場合などに、初期値として何も選択されていない状態を与えておきたいなら、こんなふうにUndefinedなどと言う要素を追加しておけば良いし。
class MyMode{ public: enum MyEN { Undefined = 0, Automatic = 1, Manual = 2, }; }; MyMode::MyEN mode_now = MyMode::MyEN::Undefined;
なので、ワテはJavaScriptのnullとundefinedは殆ど区別せずに使っている。
具体的に言うと、ある変数 a を参照する場合に、もしそれがnullやundefinedだと
a.property
などの属性を取り出そうとするとエラーするが、その為に
if(typeof(a)!=='undefined' && a!==null) var a_prop = a.property;
みたいなチェックをする場面が良くある。
この場合、変数aがnullになるのかundefinedになるのかは、aにはどういう値が入るのかを自分でちゃんと把握していれば両方の判定は不要で片一方(例えばnull)だけの判定で良いと思う。
でも、面倒なので、こんな安易な関数を作って使っている。
function isNullOrUndefined(some_variable) { if (typeof (some_variable) === 'undefined' || some_variable === null) { return true; } else { return false; } }
その結果、ワテのJavaScriptのコードには、
if(!isNullOrUndefined(a)){ ... }
という記述が良く出て来る。
あまりお勧めしないが。
JavaScriptのundefinedのヘンテコな仕様(現在は廃止)
一体全体、誰がJavaScriptにnullとundefinedという似たようなものを持ち込んだんだろうか。
一つでええやん。
二つもあったら紛らわしい。
そう思うのはワテだけかもしれないが。
それと、さらに驚くべきことに、JavaScriptのundefinedに関しては、アホみたいな信じられない事が出来るのだ。
それは、
var undefined = true;
というように変数undefinedを定義出来てしまう(ワテがJSを学習し始めた2015年頃)。
ワテはこの事実を知った時に、JavaScriptを設計した奴はアホかと思った。
JavaScriptの言語そのものは非常に使い易くて好きなのだが、この点だけは必然性が理解出来ない。
どういう目的があってこんな事が可能な言語仕様にしたのだろう。
C/C++でNULLの意味を自由に変更出来たりしたら、世の中のコンピュータがまともに動くとは思えない。
なお、本日(2016年5月)の時点では、こんなヘンテコな記述は出来ないようだ。
上記のStackOverflowの中にもこの点に関して説明があり、ワテ流に英訳すると
注意: ECMAScript 5 かそれ以降 (i.e. IE8などを除く)では、undefinedはread-onlyのglobal objectとして定義されているのでこの問題は起こらない。
と言う事だ。
なので、昔はJavaScriptプログラムの中でundefinedと言うのが出て来ても、本来のundefinedか、誰かが中身を入れ替えているかもしれない怪しいundefinedなのか分からない問題があった(今もあるか)。
なのでundefinedと言うのかも知れないな。
undefinedと’undefined’の使い分けも必要
さらにややこしいのは、JavaScriptやTypeScriptプログラミングでは、
undefined // 素のままのundefined(と呼ぶのかな?) 'undefined' // 文字列のundefined
の使い分けが必要になるのだ。
Visual Studio2015で以下のコードを実行してみた。
<script> var a = undefined; var b; if (b === undefined) { alert(a + ':' + b); } if (typeof b === 'undefined'){ alert(a + ':' + b); } </script>
その結果、二カ所にあるどちらのif文でも変数bはundefinedと判定されてalert文が実行されて
undefined:undefined
と表示された。
つまり、typeof 演算子を使った
typeof b
の演算結果は、文字列’undefined’ になるのだ。
ややこしいぞ!
さて、本題に戻って void 演算子が何故必要なのかを調査した。
何でこんなvoidとかいう演算子が必要なのか?
で、このvoidを使うと、
void(0); // 0でも100でも何でも良い。数字でなくても良い。
とすればそれは正真正銘の本物のundefinedが得られるのだ(なんのこっちゃ!)。
う~ん、まあこれを使えば誰かが中身を入れ替えているかもしれない正体不明なundefinedではなくて正真正銘のundefinedが得られると言う事なので、それで冒頭の
if (i === void 0) { i = 0; }
とすれば変数iがundefinedか否かの判定が出来ると言う事か。
面倒くさいなあJavaScript。
そんなヘンテコな事するくらいなら、undefinedの中身を変更できるなんていう仕様を採用するなよと言いたい。(現在はワテの希望通り変更出来ない仕様になっている)
JavaScriptを設計した人は、一体全体、何がしたくてundefinedの中身を変えられる仕様にしたのだろうか。
全く理解できない。
まとめ
当記事では、JavaScript/TypeScriptに登場する void 演算子に付いて考察した。
void(0) を実行すると正真正銘の undefined が得られると覚えておけば良い。
引数は0でも何でも良いのだが、通常は0が良く使われる。
まあ、ワテには馴染めない文法だが、JavaScript/TypeScriptではそうなっているので仕方ない。
なお、undefined変数を自由に定義出来る件に関しては、ECMAScript6が2015年6月にリリースされたので、今後はその手法は出来なくなった。なのでundefinedで混乱する事はなくなったかな。
注意:ECMAScript(エクマスクリプト)は、JavaScript の標準であり、Ecma Internationalのもとで標準化手続きなどが行われている。
一方、ワテにとって難解な、nullとundefinedの混同に関しては、
今後、nullとundefinedが一つに統一されれば、ワテとしては大変ありがたいが、まあそれは無理だろうなあ。
そんな大掛かりな仕様変更は無理そうだし。
と言う事で、ワテは今後も以下の自作関数を使い続けるだろう。
function isNullOrUndefined(some_variable) { ... }
安易だが、お手軽だし。
本を読む
ECMAScript6の本はアマゾンでも少ない。
有名な山田 祥寛(ヤマダ ヨシヒロ)さんの本だ。
次世代のJavaScriptと言っても、今日が2016/5/22なのに出版日が2017/4/25ってどういう事よ?
未来人が執筆したのか!!
コメント
undefinedを誰かが入れ替えていて実際に困ったという話は聞いたことがありません。
考えすぎです。
そんなことを言い出したらDateだってなんだって上書きされ得ます。
また、nullとundefinedは全くの別物で存在意義が違います。
きちんと使い分けてください。
通りすがり様
この度は、JavaScriptのnullとundefinedに関する件で有益なコメントありがとうございました。
>nullとundefinedは全くの別物で存在意義が違います。
確かに、JavaScriptに精通しておられる方々にとってはその通りだと思いますが、
私の場合、その辺りがまだ良く分からないので、殆ど同じ物として扱っています。
もちろん、他の皆さんにお勧めしている訳ではありませんが…
多くの御批判はあると予想していますが、こんなに早く反響があるとは思っていませんでした。
ありがとうございました。