新人にjavascriptを教えている最中ですが、
nullと0の違いがなかなか理解できないみたいです。
まったくのプログラム未経験者に伝えるにはどのように伝えれば
Nullと0の違いを説明できるでしょうか?
ちなみに、私の説明では
「nullは存在しない、0は0という数字が存在している。」
という風に説明しているのですが、
なんとなくわかったけど、腑に落ちない。
という感じです。
もうちょっとわかりやすく伝わりやすい方法があれば教えてください!
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答38件
0
変数とオブジェクト、そして、型というものをどのように説明したでしょうか?もし、変数を「箱」と説明したのであれば、それが混乱の元です。変数は「箱」ではありません。変数は「名札」です。
変数は「箱」では無い 〜オブジェクトの海を潜って〜
近代的なオブジェクト指向言語※では変数を「箱」と表現することは間違っています。「箱」ではなく「名札」です。どういうことかを順を追って説明しながら、0
とnull
の違いを述べたいと思います。
※ C++はもちろんのこと、Javaもこの中には__含まれない__。
プログラミング言語の世界にはオブジェクトの海があります。あらゆるオブジェクトはそこに生息します。0
も1
も"abc"
も[]
もfunction() {}
もです。それらオブジェクトは調べれば外見がわかりますが、それを呼び出す時は名前で呼ばなければなりません。これは人間の営みと同じです。太郎君は太郎と呼ばれるなんらかの人間(オブジェクト)です。しかし、太郎君の体をいくら調べても太郎という名前があるわけではありません。そう、私達は便宜上、太郎君を太郎と名付けているだけにすぎないのです。
JavaScript
1var x = 1;
JavaScriptに戻りましょう。上の文は二つの意味があります。まず、var x
に相当する部分ですが、これは、「x」という名札を作ったという意味です。次にx = 1
と言う部分ですが、これはオブジェクトの海に漂う1
なる物体(オブジェクト)をいまから「x」と呼ぶことにするという意味です。「x」に1
が入っているのではありません。単に1
という何らかの物体を「x」と呼ぶようにしただけです。同様にvar str = "abc";
やvar f = function() {return 1;};
もそれぞれ実体はオブジェクトの海に漂う物体があり、それらを「str」や「f」と名付けただけにすぎません。
話は変わりますが、オブジェクトの海にどんな物があるのでしょうか?まずは、数字です。0
や1
、42
、3.14
などが漂っています。他に、真偽値(true
、false
)や文字列("abc"
)、関数(function() {}
)、配列([4, 2]
)などがあります。それらは何かしらの意味を持つ何かです。数字の1
は私達が知っている1と同じような意味持ちますし、同様に数字の0
もインド人が発明したとされる0と同じような意味を持っています。そう、0
は0という数字であり、1
が1という数字であること同じであり、それ以上の意味を持ちません。
このようにオブジェクトの海には何らかの意味を持つ物があるのですが、これでは不便なことがあります。何の意味も持ち合わせていない物ということを表現したいときです。言い換えると何らかの意味のある物では無い物を表現したいときです。それがnull
です。
null
もオブジェクトの海に漂う物体の一つです。しかし、他とは違い意味を持ちません。いや、正確には__意味を持たないという意味__を持っています。var a = null;
となっていたとき、「a」は何なのでしょうか?変数は「名札」でした。つまり、「a」と言う名前の奴は何の意味も無い奴だ、ということです。そいつは、数字でもないので、0
ではありません。ましてや、文字列でも、真偽値でもありません。なので、""
のような空の配列という意味ある物でも、false
のような偽である意味ある物でも決して無いのです。null
は「虚無」であり、他のあらゆる全てとは一線を画していると言えます。
さて、JavaScriptにはもう一つ似たような物にundefind
があります。これはJavaScriptにおいて失敗した仕様の一つと私は考えています。var z;
としたとき、何を表すのでしょうか?まずは「z」という名札をこれから使うとしました。さて、「z」という名前の物は一体なになるのでしょう?JavaScriptの開発者達は、このようなときのために、「まだ定義されていない何か」という意味ある物をオブジェクトの海に投げ込み、「z」の名前をこの「まだ定義されていない何か」に紐付けるようにしました。これがundefined
です。ややこしいことに、undefined
は「まだ定義されていない何か」という意味があるので、null
とは異なります。しかし、「まだ定義されていない何か」は他の意味ある物のように、何かしら有用な情報を持っているわけではありません。null
と同様に扱って問題はないのです。それを示すかのように、JavaScript以外のほとんどはの言語にはundefind
はありません。変数が未定義の場合は、null
またはその言語においてnull
相当の物を使うようになっています。そう、JavaScriptだけがややこしく、言語仕様を複雑にしています。その意味では、JavaScriptは複雑な言語であると言えます。
ついでに型について話をしましょう。オブジェクトの海にたくさんある物体を分類わけしたのが型です。人間世界でも、動物や植物、鉱物、現象、概念など名前が付く物を分類わけしています。それと同じです。1
や0
はNumber型、"abc"
や"def"
はString型とわかれています。null
はNull型であり、Null型はnull
のみです。undefined
はUndefined型であり、これまたUndefined型もundefinde
のみです。こういう意味でも、0
とnull
は型そのものが違います。分類わけでいうと、「太陽」という天体と「無」という概念ぐらい違うと言えるでしょう。
ここまできても混乱するとしたら、それは==
という失敗した仕様の一つの影響かと思います。==
はJavaScriptにおいて使用してはいけない機能の一つです。なので、==
の存在を初心者に教えてはいけません。他にもtypeof
は先ほど言った型とは微妙に異なる動きをします。さらに混乱に拍車をかけるのが"abc"
とnew String("abc")
が意味がほぼ同じなのに別物であるという事実です。このようにJavaScriptは大変難しい言語です。プログラム未経験の初心者が簡単に理解できるような言語では決してありません。
投稿2016/04/25 15:00
編集2016/04/25 15:03総合スコア21735
0
どういうイメージを持っているのか
null
と 0
では大分違うと思いますが、0
と 1
でフラグ変数を作るタイプの人なんでしょうか。
その場合、false
や undefined
辺りとも混同しそうですが、まずは新人さんの持っているイメージだとか固定観念が何かを聞いてみる事から始めた方が良いと思います。
出発地点が分からず、説明を始めてもその人に伝わる説明が出来るとも限りませんから。
どういう状況で違いを認識したのか
「わからない」といっても「わからない」に至った経緯によって教え方も変わってくると思うのです。
getElementById
はなぜ要素が見つからない時に0
ではなく、null
を返すのがわからない- あるコードで演算する時になぜここの部分で
0
ではなく、null
を指定するのか分からない - 上述のような疑問に思うポイントは全くなく、ただ単に漠然と「
0
とnull
の違いが分かりません」と質問してきた
コードで教える
「イメージを与えてコードの書き方を教える」のは好ましくない教え方だと思っています。
下手に固定観念を植え付けると自由な発想でコーディングできなくなります。
漠然とした疑問ならまずはコードを書かせてより具体的な疑問点まで昇華してから解消させるべきだと思います。
型の違い
「型」を認識しているか確認して認識していないようだったら一通りの型を教えてあげてください。
JavaScript は「暗黙の型変換」が頻繁に発生する言語なので現在の型を意識しないといろいろとはまります。
- Undefined 型
- Null 型
- Boolean 型
- String 型
- Symbol 型 (ES6 規定)
- Number 型
- Object 型
typeof 演算子
typeof
演算子はその名称から「型を表す文字列を返す演算子」と読み取れますが、実際には型と一致しない文字列を返す場合があります。
JavaScript
1console.log(typeof undefined); // "undefined" 2console.log(typeof null); // "object" (Null型: typeof 演算子は Null 型に対して "object" を返す仕様バグがあります) 3console.log(typeof true); // "boolean" (Boolean 型) 4console.log(typeof 1); // "number" (Number 型) 5console.log(typeof "sample"); // "string" (String 型) 6console.log(typeof Symbol()); // "symbol" (Symbol 型: ES6 既定) 7console.log(typeof {}); // "object" (Object 型: [[Call]] を持たない一般的なオブジェクト) 8console.log(typeof document); // "object" (Object 型: [[Call]] を持たず、標準的な外来のオブジェクト) 9console.log(typeof new Function); // "function" (Object 型: [[Call]] を持つオブジェクト) 10console.log(typeof hoge); // "hoge" (Object 型: 非標準で外来の [[Call]] を持たないオブジェクト。詳細は後述の (*1) を参照。) 11 12/** 13 * (*1) Object (non-standard exotic and does not implement [[Call]]) 14 * typeof 演算子はこのオブジェクトに対して "undefined", "boolean", "function", "number", "symbol", "string" を返してはならない。 15 * つまり、"undefined", "boolean", "function", "number", "symbol", "string" 以外の文字列であれば何を返しても良い。 16 */
typeof null === 'object' は仕様バグだそうですが、今更修正できないのでそのままになってしまっています。
関数に対して "function" を返す動作も困りものですが、一番対処に困るのは「Object (non-standard exotic...)」です。
このオブジェクトは既定文字列以外の全ての文字列を取りうるので typeof
演算子で真面目に Object 型を判定しようとすると「既定文字列以外の全て」を判定する事になります。
実際に私は ES5 当時にそのようにコーディングしていました。
JavaScript
1/** 2 * get-type.js 3 * 4 * @version 1.0.2 5 * @author think49 6 * @url https://gist.github.com/862085 7 * @license http://www.opensource.org/licenses/mit-license.php (The MIT License) 8 */ 9 10function getType (value) { 11 var type, typeofValue; 12 13 if (value === null) { // Null Type 14 return 'Null'; 15 } 16 17 typeofValue = typeof value; 18 19 switch (typeofValue) { 20 case 'undefined': // Undefined Type 21 case 'boolean': // Boolean Type 22 case 'number': // Number Type 23 case 'string': // String Type 24 type = typeofValue.charAt(0).toUpperCase() + typeofValue.slice(1); 25 break; 26 case 'object': // Object Type (native and does not implement [[Call]]) 27 case 'function': // Object Type (native or host and does implement [[Call]]) 28 default: // Object Type (host and does not implement [[Call]]) 29 type = 'Object'; 30 break; 31 } 32 33 return type; 34}
ES5 当時には typeof
演算子が "symbol" を返した場合、それを「Object Type (host and does not implement [[Call]])」と見なして Object 型と判定する動作が正しい動作でした。
ところが、ES6 で Symbol 型が増えた事によって "symbol"
という新しく定義済文字列が出来た為、上記コードは ES6 準拠の実装において Symbol 型を Object 型と判定してしまいます。
新しい型が増える度にコードを修正するいたちごっこには付き合ってられませんので ToObject
で Object 型に変換して変換前と照合する事にしました。
JavaScript
1if (Object(arg) === arg) { // ToObject で Object 型に変換する 2 console.log(arg + ' は Object 型である'); 3}
このコードも ToObject
の動作次第では破綻しますが、「"undefined", "boolean", "function", "number", "symbol", "string" 以外の文字列は Object 型である」の判定ロジックに修正するよりはマシです。
ES6 では Object 型を判定する関数として Object.isObject()
の導入が検討されたようですが、残念ながら見送られました。
- 7.1.13 ToObject ( argument ) – ECMA-262 6th Edition
- 19.1.1.1 Object ( [ value ] ) – ECMA-262 6th Edition
「存在しない」を表す値
変数や返り値には既定の型があり、「存在しない事を表す値」は型によって変化します。
JavaScript
1/** 2 * Number 型 3 */ 4Number('hoge'); // NaN (Number 型へ変換不可能な場合、NaN (Not a Number)を返す、NaN は Number ではない事を表す) 5''.charCodeAt(); // NaN (存在しない場所の文字を指定した場合、Unicodeコードポイントは NaN となる) 6'sample'.indexOf('hoge'); // -1 (存在しない index は -1 で表す) 7console.log([].length); // 0 (空の配列の length 値は 0 である) 8console.log(Object.keys({}).length); // 0 (直属のプロパティを持たないオブquerySelectorAll は存在しない要素のセレクタを指定した場合、空の NodeList (擬似配列) を返す。この NodeList の length 値は 0 である。) 9 10/** 11 * String 型 12 */ 13[].join(); // "" (対象の文字列が存在しない場合、空文字を返す) 14''.charAt(); // "" (対象の文字列が存在しない場合、空文字を返す) 15 16/** 17 * Undefined 型 18 */ 19(function () {}()); // undefined (return 節がない関数は未定義値を返す) 20var a; // undefined (var 宣言の既定値は未定義値である) 21void true; // undefined (void 演算子は常に undefined を返す) 22document.hoge; // undefined (プロパティアクセス演算子は存在しないプロパティを指定した場合、undefined を返す) 23 24/** 25 * Null 型 26 */ 27console.log(document.onclick); // null (onclick の既定値は null である) 28document.onclick = function (event) { console.log(event.type); }; // onclickイベントハンドラを定義する 29document.onclick = null; // onclickイベントハンドラを削除するには null を代入する 30console.log(document.getElementById('hogehoge')); // null (getElementById は存在しない要素を検索した場合、null を返す) 31console.log(/hoge/.exec('test')); // null (RegExp#exec はマッチしなかった場合に null を返す) 32console.log('test'.match(/hoge/)); // null (String#match はマッチしなかった場合に null を返す) 33 34/** 35 * Object 型 36 */ 37new Object; // {} (引数なしで new Object が呼び出された場合、直属のプロパティを持たない空のオブジェクトを返す) 38new function () {}; // {} (this 値を操作せず、prototype も設定しない関数が new 演算子で呼び出された場合、直属のプロパティを持たない空のオブジェクトを返す) 39new Array; // [] (引数無しで new Array が呼び出された場合、length 値が 0 の空の配列を返す) 40document.querySelectorAll('.hoge'); // [] (querySelectorAll は存在しない要素のセレクタを指定した場合、空の NodeList (擬似配列) を返す)
Undefined 型と Null 型
ECMAScript 6 では undefined
, null
値を次のように定義しています。
4.3.10 undefined 値
変数に値が割り当てられる前に使われるプリミティブ値。
4.3.12 null 値
任意のオブジェクト値が意図的に存在しないことを表すプリミティブ値。
getElementById
は存在しない id を指定した場合、対象のオブジェクト(要素ノード)が存在しない事を表す null
を返します。
document.onclick
は初期値としてオブジェクト(イベントハンドラ関数)が存在しない事を表す null
を持ちます。
(2016/05/04 23:15 追記) この節には別の説明を書いていましたが、ES6 で適切な説明があった為、修正しました。)
更新履歴
- 2016/05/03 17:02 コード事例を追記
- 2016/05/04 22:17 typeof 演算子、「存在しない」を表す値、Undefined 型と Null 型の説明追加
- 2016/05/04 22:38 Symbol 型が増えた事による typeof 演算子による Object 型の判定方法の複雑化について説明&コード追記
- 2016/05/04 23:15 「Undefined 型と Null 型」の説明が ES6 に準拠したものではなかった為、修正
Re: a_yanyan さん
投稿2016/04/25 16:33
編集2016/05/04 14:16総合スコア18164
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/04 00:47
0
そもそも論ですが、「JavaScriptで」0とnullを混同するような場面、というのがちょっと想像できません。
JavaScriptの場合、未定義値はundefinedというものが別にあってnullではありませんし、数値演算で異常値になってもNaNか例外になってnullの出る幕はありません。
自分が思いついた「JavaScriptでnullの登場する」場面は、「getElementByID()
で指定の値がなかった場合」、あるいは「Google Map APIで、指定すべきオブジェクトがない場合の引数に使う」など、いずれもオブジェクトが存在しない場合のものでした。
投稿2016/04/25 05:53
総合スコア145184
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
細かいお話ですが、javascriptの場合undefinedというのもありまして。。。
javascript
1console.log(undefined === null); // false 2console.log(undefined == null); // true 3console.log(isNaN(undefined)); // true 4console.log(isNaN(null)); // false 5console.log(null + 100); // 100
undefiend:変数は宣言しているがその値をセットしていない状態
null:「null」というオブジェクトをセットしている状態
0:数値
というぐらいしか思いつきませんねぇ。
投稿2016/04/25 04:40
総合スコア5572
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
厳密に言うと違うんでしょうが、「箱が空っぽ:0」と「箱そのものがない状態:Null」ですかね
箱そのものがない状態で箱を触ろうとする→ヌルポ
入れ物に入れすぎてあふれてしまう→オーバーフロー
って説明しています
投稿2016/04/25 04:37
編集2016/04/25 04:37総合スコア3939
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/04/25 04:41 編集
2016/04/25 04:48
2016/04/25 05:00
2016/04/25 09:20 編集
2016/04/27 01:47
2016/04/27 03:22
0
自分がプログラム未経験者の方にまず最初に説明するならば、
null:存在しない状態を指す
0:数値
と、言う気がします。ほとんど質問者さんと変わらなくてすみません。
プログラム未経験者の方の考え方を推察すると、モノが1個以上なら存在する、0個の場合は何もない = null?と考えてしまい腑に落ちないのではないかという気がします。だとすると「0」を特別視しているように思います。
0は0。1より-1少ないだけのただの数値。プログラムでは存在しない場合は「0」ではなく別の表現(= null)で表すため、「0」と null は別物である。
・・・人に伝えるのは難しいですね。
投稿2016/04/25 05:18
総合スコア247
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/02 08:47
2016/05/02 10:52
0
相手が未経験者だということで例を挙げて説明します。
時事ネタになりますが、日本のあるところで大地震が発生したとします。日本政府が地震のあった地方の自治体に被害情報を問い合わせたところ以下のような回答がありました。
A市:死者数:0
B市:未回答(市民5000人全員が死亡したため回答できない。)
C市:未回答(実際は0人だが市の施設が全壊し回答ができない。)
D市:未回答(実際は10人だがまだ集計が済んでおらず回答ができない。)
この場合、A市は死者数0ですが未回答であるB、C、D市は0ではありません。B、D市は実際に死者がいるので未回答だからといって0にしてしまえば死者は0人になってしまいます。
プログラム的にはメソッド「死者数はいくつか?(getNumberOfDeath)」の戻り値は数値型になりますが、何らかの理由により回答不能であれば数値を戻り値にはできません。このためnullのような値が存在します。当然ながら結果が0の場合とnullの場合では後続の処理が異なることもあり得ます。(リトライやエラーメッセージの表示など。)
これがすなわち「0は0という値が存在するがnullは値がそもそも存在していない(数値化できていない)。」ということになります。
数学と情報学は違います。0はあくまでも数学上の何もない概念です。情報学上は数学上の表現がもはや不可能な状態になって初めて何もない状態になります。
投稿2016/05/04 09:01
総合スコア28
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
###あらすじ
JavaScriptを最近学び始めた見習いエンジニアの山田さん。
今日の仕事を終えて帰宅する途中の山田さんは買い物をするために近所のスーパーへ向かうようです。
###第一章「null - 値に内容が無いことを明示するための宣言」
山田さんは、まず好物である暴君ハ○ネロを買おうとお菓子売り場へ行きました。
しかし、暴君ハ○ネロが置いてあるはずの売り場には肝心の商品がありません。
店員さんに在庫はないか尋ねてみたところ、店員さんはこう答えました。
「暴君ハ○ネロは某外国人団体の爆買いで全部売り切れてしまいまして、今日はもう在庫がないんですよ」
なんということでしょう。
JavaScript
1var tyrant_haxxnero_stock = null; 2console.log('暴君ハ○ネロの在庫:', tyrant_haxxnero_stock);
「在庫が存在しない」と言われてがっくりと肩を落とした山田さんでしたが、無いものは仕方がありません。
山田さんは買い物を続けるため、別の売り場へと行くことにしました。
###第二章「0 - 数値を表している」
商品をかごに入れた山田さんはレジへ向かいました。
そしていつものようにポイントカードを提示すると、店員さんがこう尋ねてきました。
「500円分お値引きできるポイントが貯まっています。今お使いになられますか?」
店員さんの問いに山田さんは「はい、お願いします」と答えました。
すると、商品をレジに通し終えた店員さんが何かに気づいたような素振りでこう言いました。
「お会計は0円ですね」
どうやら買い物の金額は丁度500円だったようです。
そして500円の値引きにより会計は0円。
受け取ったレシートにも「合計 ¥0」と印刷されています。
つまり無料です。
JavaScript
1// その数値が何の意味を持つのかはその時々で異なる(数・位置・距離・時間・サイズ等々) 2var price = 500; 3var discount = -500; 4var payment = price + discount; 5console.log('会計:', payment);
会計を済ませた山田さんは少し得した気分を味わいながら店を出ました。
###第三章「undefined - まだ値に何も代入されていないことを表す」
買い物を済ませた山田さんは夕食をとろうと定食屋に入ります。
そして席に着いた山田さんがメニューを見ていると「煮込み雑炊」の文字が目に飛び込んできました。
完全に煮込み雑炊の舌になった山田さんは早速店員さんに注文します。
しかし店員さんの返事は期待したものではありませんでした。
「あ…ごめんなさい。それ、来月からなんですよ。ごめんなさいね」
返ってきた答えに落胆した山田さんは改めて煮込み雑煮を注文しましたが、煮込み雑煮も来月からだと言われて意気消沈してしまい、結局別のものを頼んで食べました。
食事を終えた山田さんは、死んだ魚のような目をしながら帰宅しました。
JavaScript
1// null も含めて値に何も代入されていないときに返ってくる初期値 2var nikomizousui; 3var nikomizouni; 4console.log('煮込み雑炊:', nikomizousui); 5console.log('煮込み雑煮:', nikomizouni);
「メニューには書いてあるけどまだ用意していない」という予想だにしない出来事にショックを受けた山田さん。
その日の夜は枕を濡らしながら眠りにつきました。
###後書き
これでざっくりとしたイメージを掴んでもらって「違うんだ」と何となくでも分かってもらったら、その後に「JavaScriptには型というものがあって、こういう型があるんだよ~」と型の説明をする感じでどうでしょうか。
JavaScript
1var tyrant_haxxnero_stock = null; 2 3var price = 500; 4var discount = -500; 5var payment = price + discount; 6 7var nikomizousui; 8 9// 0 と null の型も含めた厳密な比較 10console.log( payment === tyrant_haxxnero_stock ); 11 12// 0 と undefined の型も含めた厳密な比較 13console.log( payment === nikomizousui ); 14 15// null と undefined の型も含めた厳密な比較 16console.log( tyrant_haxxnero_stock === nikomizousui );
投稿2016/04/26 03:39
編集2016/05/04 07:43総合スコア617
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/02 05:09
2016/05/02 06:06
2016/05/03 21:04 編集
2016/05/04 01:23 編集
2016/05/04 01:15
2016/05/04 01:37
0
nullは有無の概念
0は数値の概念
概念が違うのだから、比較すること自体ナンセンスです。
これは、理解させるより強引に覚えてもらった方が良いかと思います。
さて、Javascriptにおけるnullの挙動ですが、
以下の様な文字列演算であれば、0strとnullstrという結果になります。
どちらも、dは文字列に変換されます。
<script> var d = 0; // 文字列連結 alert(d + "str"); </script> <script> var d = null; // 文字列連結 alert(d + "str"); </script>
まあ、このケースのnullはだいたいバグですね。
そして、以下のように数値演算をすると、1と1、同じ結果になります。
これは、数値演算のnullは0に変換されているからです。
<script> var d = 0; // 数値演算 alert(d + 1); </script> <script> var d = null; // 数値演算 alert(d + 1); </script>
このケースで、nullと数値を演算するのは間違ってるんじゃないか
という意見も出てきそうですが、
私なら、Javascriptだったら期待する結果がOKなら問題ない、と言ってしまってます。
投稿2016/05/02 22:09
総合スコア1124
0
こんにちは。
その新人さんが、プログラミングについて、どの程度の知識と経験を持って
a_yanyanさんの元に預けられてきたのかによって、答えは変わってくると
思うのですが、その新人さんがjavascriptが初めてのプログラミング言語で
あると推定しています。
以下の3点は、私はa_yanyanさんのような指導役の状況になったときにきっと
考えると思われることです。
(1) 0とnullの違いというのは、Javascriptだけに限らず、どの言語でも
出てくる、プログラミングの基礎の範疇にある重要なトピックである。
(2) Javascriptのnullに限らず、プログラミング言語で扱うNULLの概念を
理解するにはC言語でいう「ポインター」を理解する必要がある。
(3) ポインター(あるいは参照)を理解するには、プログラムがメモリに
どのように展開されて、CPUがどう動くのかの基礎を知っておく必要がある。
余談ですが、もし教えている言語が、javascriptではなくjavaだったら
値がnullである変数を参照しようとすると
NullPointerException
が投げられるので、「エラーメッセージにヌルポインター例外って出てるでしょう」
みたいな感じで、「ポインター」という言葉を知ってもらう機会があるのですが。
それはさておき、ご質問にある新人の方は、javascriptが初めてのプログラミング
言語のように推測致しますし、もしかするとjavascriptプログラマーとして、
とりあえず現場にすぐにでも出てもらわないといけない、差し迫った状況かもしれ
ません。そんなときに、JSと並行してC言語も教えるなんてことはできないと思い
ますので、私ならこう教えます。
・今のところは、0とnullの違いというのは、0はゼロという数で、nullは何もない
ということ、ぐらいに思っておいてください。
・でもこの説明では違いがよく分からないと思う。
・よく分からなくて問題ない。むしろ今ここですっきり分かったつもりに
ならないで欲しい。
・では、なぜ分からないかといえば、nullの意味をちゃんと理解するにはポインター
(とか参照)という概念を知ってないと分からないから。
・それで、ポインター(とか参照)を理解するには、C言語かアセンブラという
言語を学ぶとよいのだけど、今それを教えてる時間はないので、もしそのあたりを
ざっと知っておきたければ、たとえばこの本を読むといい。
と言って、
プログラムはなぜ動くのか 日経ソフトウエア
あたりを勧めます。
(ほんとに理解したい新人なら、ゴールデンウィーク中、遊ばないで読むでしょうし)
その上で、0とnullの話に限らず、
・ある概念Aを理解するには、その前提として概念Bを知っておかなければならない。
・今はその前提となる概念Bを知らないので、Aがよく分からなくていい。
(逆に、簡単に分かったつもりになることのほうがよくない)
・もしAを分かるためのBを分かりたければ、これこれこういうことを勉強する必要がある。
・だけど、今Bを勉強する時間はないので、Aの理解は漠然としたものでいいから
先に進もう。
・ただし、先に進んでいく際に、
「自分はAについての理解が不十分で、それはBを学んでないから」
という自覚を忘れないようにしておく必要がある。
・・・といったような状況(=「Bを知らないからAを完全には分からない」という因果関係は
分かった上で、Aの理解は曖昧なまま、Aを使う何かの学習を進めていくという状況)
は、プログラミングの学習途上にはしばしばあるのだ、ということを知ってもらう
事例にするだろうと思います。
自分の回答は以上です。
ご参考になれば幸いです。
投稿2016/05/02 05:38
総合スコア9058
0
JavaScriptは動的型言語なので、原則的には型を意識しないで良いのですが、型システムについて「これだけは理解しなければならない」という概念が有ります。
値型と参照型の違いです。
例えば、次のコードで、(1)と(2)の部分の結果が異なるのは何故でしょう。
JavaScript
1// 値型の例 2var v1 = 1; 3var v2 = v1; // 最初の変数を代入して 4 5console.log(v1); // 1 6console.log(v2); // 1 7 8v1 = 2; // 最初の変数を書き換える 9 10// (1) v1とv2の出力結果は異なる 11console.log(v1); // 2 12console.log(v2); // 1
JavaScript
1// 参照型の例 2var r1 = { m: 1 }; 3var r2 = r1; // 最初の変数を代入して 4 5console.log(r1) // { m: 1 } 6console.log(r2) // { m: 1 } 7 8r1.m = 2; // 最初の変数を書き換える 9 10// (1) r1とr2の出力結果は同じ 11console.log(r1); // { m: 2 } 12console.log(r2); // { m: 2 }
1つ目のプログラムでは、最終的に別の値が出力されるのに対し、2つ目のプログラムでは同じ値が出力されています。これは何故でしょう。
そう、質問者をはじめ、プログラミングに親しまれている皆様は直ぐお分かりでしょうが、これは、整数のような単純な物は値で、オブジェクトのような複雑な物は参照で扱うという決まりがあるからです。
新人さんは、この値型と参照型の違い、どういう物が値型になり、参照型になるのはどれかという事が、明確に理解できていないのでは無いでしょうか。
先ずは、この違いを教えてはどうでしょうか。
値型と参照型の違いが理解できれば、0とnullの違いも理解できるのではないかと思います。
0は0という数値ですが、nullは「何も参照してない」という事実を表します。変数に格納される「何か」という点では同じですが、別の概念を表しているのです。
なお、「値の種類に依って値型か参照型か決まる」というのは、Javaを初めオブジェクト指向言語では主流ですが、そうでない言語も存在します。
例えばC#は、ユーザー定義型が値型か参照型か、プログラマが決める事が出来ます。
C++やCだと、基本的に全て値型ですね。特別な修飾を型名に行った場合に、参照型を作る事が出来ます(この説明は、厳密には間違っているのですが ;-) )
投稿2016/04/26 15:55
編集2016/05/02 04:34総合スコア105
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
例えば下記のようなコードと実行結果を見せ、変数型と「無い」を表現する方法に関してうっすらと説明したら、理解を深めることができるのではないでしょうか。
JavaScript
1// 変数型と初期化に関する実験 2var x; 3console.log(typeof(x)); // 'undefined' 4x = null; 5console.log(typeof(x)); // 'object' 6x = 0; 7console.log(typeof(x)); // 'number' 8x = ''; 9console.log(typeof(x)); // 'string' 10x = false; 11console.log(typeof(x)); // 'boolean'
投稿2016/04/25 05:53
総合スコア2425
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
楽しみにしていたイチゴのショート。帰って箱を開けてみると‥
- 空っぽ! → 0
- 小宇宙が広がっていた‥ → undefined
- ぬるっとしたものが入っていた! → null
JavaScript知りません、すみません。
投稿2016/04/25 05:21
編集2016/04/25 09:19総合スコア16731
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/04/25 06:05
2016/04/27 03:58 編集
2016/04/25 09:20
2016/05/04 14:59
2016/05/05 15:28
0
使う側が区別すると良いと思います。
「ヌル」はヌルポインタ-で、0000:0000(286リアルとして)のアドレスを示して、アドレス1122:2378 のunsigned型の値が「零」とすべきです。
従って、ヌルは変数(レジスタ)の値が「零」つまり、「零」を指し示すポインターとなります。
Wikipediaや常識がどーのとか、ヌルがどーのとか、まず利用者側で「定義」をすべきです。
投稿2016/05/13 23:27
退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
まずは「型」の概念を先に理解するといいと思います。
投稿2016/05/06 16:14
総合スコア4830
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
「存在しない」という言葉の意味自体が、初心者には難しいかもしれません。
0(ゼロ)も人によっては、「値がない」と捉らえてしまうかもしれません。
プログラミング経験のある人にとっては、0 とは「0という値に設定されている」と思えたり、「0 という値が存在している」と思えたりしますが。
そのため、意味の理解はひとまず置いておき、null の使い方や使う状況、エラーになる場合などを説明し、覚えてもらうことを優先してはいかがでしょう。
おそらく、その初心者も JavaScript でのプログラミング経験を重ねていけば、自然と null の扱い方に慣れるのではないでしょうか。
投稿2016/05/02 08:38
総合スコア179
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
他の言語も踏まえてゼロベースから簡単に。
変数にはstrig,intなど複数の型がある。
0や94や5はint型の数字でしかない。(例)
nullは全ての型の変数が入っていない状態。
投稿2016/05/02 05:17
編集2016/05/02 05:43総合スコア16
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
この部屋の中にある袋に入っているリンゴの数は? って聞いたときに、
「袋、空っぽだったよ」ってのが「0」って状態
「袋なんてないよ」ってのが「null」て状態
袋がなければ中のリンゴの数、なんて概念は存在しませんからね
投稿2016/05/02 04:25
総合スコア1720
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/02 06:14
2016/05/02 06:24
2016/05/02 12:51
0
javascript
1$ node 2> typeof(x) 3'undefined' 4> x = 0 50 6> typeof(x) 7'number' 8> x = null 9null 10> typeof(x) 11'object' 12> 0 == null 13false
typeof での結果も == での比較も "違う" のですから。
追記:
昔は 1, 2, 3 を物理的な物の存在と結びつけていたので、 0 は、画期的な概念でした。
数学の集合論でも 空集合はちょっと特別です。
プログラミングで次のことが区別できることに似ているかもしれません。
0 と '0' の差
'\0' と "" の差
[] と {} の差 (ruby 表記で)
char * p = null と char *p = 0 の差 (c の表記で。 実際には区別していなくてもプログラムは動作する)
Int と Int? の差 (Swift の表記で)
投稿2016/04/28 13:28
編集2016/05/02 08:58総合スコア22324
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
処理の結果数字か null を返す関数と、その関数の結果を受け取って数字を処理する関数を組ませてみるのが早いような気がします。
下記のような判定で値を厳密に判断する癖が付いていないと、と思うのはこれにたくさん躓いたからかなと思います。
JavaScript
1if ( !hoge ) { /* 内容 */ }
【[JavaScript] null とか undefined とか 0 とか 空文字('') とか false とかの判定について - Qiita】
http://qiita.com/phi/items/723aa59851b0716a87e3
投稿2016/04/25 05:22
総合スコア69407
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
「変数」だけで 0 と null の違いを理解するには、必要な概念が不足しているので難しいと思われます。
※0 や null の使い道、使い分けなどは他の方の説明が素晴らしいので、それぞれの意味のみに的を絞ります。
【CPUとメモリとメモリアドレスの関係をイメージしてもらう】
var a = 0 で変数を作成するというのは、メモリ(分からなければExcelシートをイメージしてもらう)上の 空いている場所 に 0 という値を保存することを意味する。
次に
console.log(a) としたとき、 0 を表示するためには、CPUがメモリ上から 0 が保存されている場所を探しにいく必要がある。
これをメモリアドレス(分からなければExcelシートのセル番地「A1」をイメージしてもらう)という。
このメモリアドレスについては、CPU側がうまく管理してくれるが、これを破棄するのが
a = null
つまり、Excelシートのイメージでは、仮にA1というセルに 5 という値がある状態は「5 という値は A1 にあるよ」といえる。
ここでセル番地(メモリアドレス)だけ消してしまうとどうなるでしょう。
この状態は「5 という値は ?? にあるよ」と言うのと同じで、「存在するけど見つけられない」から「使えない」状態になります。
投稿2018/09/11 02:55
総合スコア12
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
###もしもあなたがテストの回答判定プログラムを作ったなら
どんなときでも置き換えるのが一番ということで置き換えます。
数学のテストの回答用紙を思い浮かべてください。
式の答え(いわゆる解)がそれぞれの解答欄に書きだされていると思いますが、
すべての解答欄の中に必ずしも記入されているわけではない。
要は空欄の状態は必ず存在するわけなのです。
それを言語に置きかえます。
[ 空欄の状態 = Null ]
となります。
では、ある数学のテスト問題に(-1)+1という問題があったとしてその答えを記入する解答欄があったとしましょう。
[ 解答は0 ]
プログラムの認識も0になるでしょう。
では、nullと0の意味が一緒だったらどうなるでしょう?
テストで空欄だった場合、普通は点数をもらえません。要は不正解です。
[ 空欄=Null=0 ]
だったら、どうでしょう
[ 空欄=不正解 ]
です。
ということは必然的に
[ 不正解=0でもあるわけですから。 ]
後者の問題でせっかくあっている答えでも間違っている!ということになります。
投稿2016/05/23 07:03
総合スコア46
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
こんな話題もありますね。
参考:
- NULL と nullptr って何が違う? http://qiita.com/go_astrayer/items/6afb1592a8a5763fede1
- NULLの定義 http://denpa-shinbun.com/entry/2016/02/29/231949
投稿2016/05/18 22:26
総合スコア22324
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
1.まず紙と鉛筆と消しゴムを用意します。
2.紙に0〜9の数字を書き「ここに0〜9の数字があります」
3.「今からこの数字をnullにしたいとおもいます」と言い、「1」を消しゴムで消します。
4.「0という数字は存在していますが、1は存在すらしなくなりました。この存在していないという状態がnullです」
という説明はいかがでしょうか?
投稿2016/05/17 00:38
総合スコア36
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
例えば変数a = null, 変数b = 0が宣言されたとする。
変数aを使って何か処理をしようとすると、「NullPointerException」の例外が発生する。
理由はnull = 何もない、つまり変数の中身は空ということだから。
「何もないのに処理はできませんよ」ということ。
一方、変数bは0が入っているので処理ができる。
なぜなら、0という数字か文字が入っていて空ではないから。
試しにnullと0が入っている変数を使って簡単な四則演算で説明してみるといいのでは
ないでしょうか?
投稿2016/05/10 01:35
総合スコア25
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/10 04:22
0
私はバリバリの文系かつ全く未経験で、入社して初めてプログラミングを学びました。「0は数値」で「nullは何型でもない"無"」(null型とか言うと「型なんじゃん!」と混乱しそうなので避けたほうが良い気がします)といったところで納得したのですが……。SQLの外部結合を知っていれば「条件に一致するデータがない時にnullが返ってくる = 何も見つからなかった」という感覚が掴めるかと思います。
投稿2016/05/02 23:02
総合スコア29
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/02 23:31
2016/05/02 23:46
2016/05/04 13:56
2016/05/04 14:29
0
エクセルで0とnullの違いを表現してみよう!というのはどうでしょう?
var A1 = 0; を表すには
A1に「=B1」を入力
B1に「0」を入力
var A1 = null; を表すには
A1に「=Sheet2!B1」を入力
Sheet2を削除して参照不可にする
投稿2016/05/02 08:49
総合スコア51
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
新人さん、変数や型、そしてその使い方の仕組みについての理解度がまだ低いようですね。
変数とはよく値を入れるための器と表現されますが、器の中には何も数値ばかりが入るわけではありません。
変数の型が文字列型だったとしたら、値がNullだったとしても0とは思わず、せめて空文字列('')と思うのではないでしょうか?
空文字列とNullの違いもまた新人さんに説明するのは難しいわけですが、NULL=0ではないことは理解してもらえると思います。
自分がNullと0の違いを説明するとしたら、プログラミングに無縁な人であれば
「正解の数字は、封筒の中に入れてある」 といわれたとき、 ・0という数字が入っていた ⇒ 0が正解だとわかる。 ・何も入っていなかった ⇒ だからといって正解が0とは言えない。正解などない。 Undefinedは、、「これから封筒に入れるつもりだけど、まだ入っていないよ」という補足説明があった ・・・という感じでしょうか。
ちょっと苦しいですかね?(^-^;
これからプログラミングに関わっていく人であれば、もう少し理解度を高めていただく必要があると思います。
そのうえで、
・0とは、(当然ですが)数値で0という値を表します。 つまり、-1より大きくて、1よりは小さい、0という値を指します。 ・Nullとは、(ちょっとわかりにくいですが)「値がない」ということを表現するための特別な値です。 (NULL:空っぽとか虚という意味) ・Undefinedとは、「値がまだ未設定」であることを表現するための特別な値(状態)です。
みたいな説明をすると思います。
Javaの畑のものではないので、変な説明になっていたらすみません。
投稿2016/05/02 05:42
総合スコア3013
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
建物を例に言います。
変数=建物の名称。メモリの番地(住所)をわかりやすく表すようなもの。変数には必ず対になるアドレスが存在します。
変数の中身=nullの場合、番地がなく空間が存在しない状態(架空請求で言えば実態がない住所を言ってるようなもん?そこに建物は存在しない的な…。余計こんがらがるかな?w)
変数の中身=0(番地はあるが中身が0 土地はあるけど建物がない。つまり0階建て)
変数の中身=1(建物に例えると1階建て)
まぁ、建物の場合マイナスを説明するのは難しいですが、イメージだけつかんでもらえれば…。
追記
javascriptでアドレスが確認できるかはわかりませんが、
javascriptで説明が難しい場合は、他の言語 例えばcなどで、
変数には必ずアドレスが存在し、別に中身が存在するという事を説明すれば良いように思います。
投稿2016/05/02 04:25
編集2016/05/02 04:39総合スコア23
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/05/02 15:38
2016/05/04 01:11
2016/05/04 02:43
2016/05/04 02:46
2016/05/04 13:27
2016/05/04 14:18 編集
2016/05/04 15:26
2016/05/05 22:17
2016/05/06 11:41