このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

JavaScript大域変数の存在確認

[追記]id:zorioさんのブックマークコメントの指摘により、抜けていた「.apply」を挿入しました。[/追記]

JavaScriptで、大域変数(大域オブジェクトのプロパティ)fooが存在しないときに何かをしたいとしましょう。例えば、こんな書き方をしますよね。


if (!foo) {
// 何か
}

でも、式 !foo は、fooがnullでもfalseでも0でもtrueに評価されます。


if (foo == undefined) {
// 何か
}
としたほうがよさそうです。が、null == undefined もtrueとなるのであまり改善されてません。

if (foo === undefined) {
// 何か
}
イコールが3つなら、厳密に「fooが未定義値であるとき」を表現します。ここで、undefinedはリテラルではなくて、仕様として事前に定義されている大域変数です。undefinedは変数ですから値を書き換えることができます(例えば、undefined = "hello";)。万が一の事態を用心するなら、undefinedは使わないほうがいいでしょう。


if (foo === (void 0)) {
// 何か
}

ところで、僕はJavaScript対話系Rhinoを厳密モード(strict mode)で使っているのですが、if (foo === (void 0)) {...}のように書くと、


Attempt to assign non-existing name "foo" in the strict mode.
It could indicate a missing variable statement.
と叱られます。大域変数への参照をいきなり名前で書くのではなくて、window.fooのようなドット形式にすれば大丈夫です。たまたま局所変数fooがあって大域変数fooが隠れてしまうような事故も防げます。


if (window.foo === (void 0)) {
// 何か
}

あるいは、


if (typeof window.foo == 'undefined') {
// 何か
}

あれっ? 待てよ。Rhinoではそもそもwindowってのが定義されてないからやっぱりエラーでした。ハニャニャニャ。大域オブジェクトを名前によらずに確実に参照するには、(function() {return this;}).apply(null, [])って式が使えます*1


if (typeof ((function() {return this;}).apply(null, [])).foo == 'undefined') {
// 何か
}
なげー、みにくい。変数を使いましょう。


var g = (function() {return this;}).apply(null, []);
if (typeof g.foo == 'undefined') {
// 何か
}

これでよいかな? いやっ、実はこれでは存在判定になってません。プロパティg.fooが存在してかつ値が未定義値のときもtypeof g.foo == 'undefined'は真になりますからね。in演算子を使うとよさそうです。


var g = (function() {return this;}).apply(null, []);
if (!("foo" in g)) {
// 何か
}

実際上は、値が未定義値のときは“存在しないも同様”とみなして、たいてい大丈夫ですけどね。

*1:この方法は、以前id:nak2kさんに教えていただきました。http://d.hatena.ne.jp/m-hiyama/20050927/c 参照