JavaScriptの難しいところ覚書

投稿者: | 2018/9/15 土曜日

C++プログラマやJavaプログラマにとってJavaScriptの分かりづらいところを解説。

スコープ

C++では{}で括ったブロックがスコープになるがJavaScriptではスコープにならない。

2つのaは同じaになる。

関数はスコープを持つ

上のコードでfunction内のvarを外すと同じaを参照する。

コンパイルと実行

JavaScriptの実行は2段階で行われる。最初は変数を割り当て、次に実行する。割当時にはどのスコープにどの変数があるかを確定する。varによる変数の宣言や変数への書き込みは割当であり、変数の読み込みは割当処理ではスルーされる。

上記のコードではa,b,cは割当時に割り当てられるが、dは割り当てられないので実行時にエラーになる。cは書き込み処理なので割当時に割り当てられる。cでもエラーにしたい場合はファイルの最初に"use strict"(ダブルクオーテーション含む)と記述する。

オブジェクトと辞書

オブジェクトと辞書は同じ。

Objectは実際は関数である(後述)。

関数とオブジェクト

JavaScriptにはクラスがない。クラスのようなものをつくりたいときは関数で行う。

newを使うと、空のオブジェクトをつくりそれを暗黙の引数として渡す。関数内ではthisとして参照しそのオブジェクトを返す。

this

C++と同じようにオブジェクトのメンバ関数をコールすると暗黙の引数thisが渡される。

getasetaではthisを参照しているので関数を呼び出したオブジェクトがthisになりその値が変わる。

getcsetcではthisを参照していないのでオブジェクトは変更されない。そもそもこのcはオブジェクトに含まれてはおらず関数funcが持っている変数である。getcsetcはそのcを参照するがstaticでもなく、newでオブジェクトがつくられるごとにつくられそれが参照されている。よってcはオブジェクトがもつprivate変数のように扱える。

ここでnewを使わずにfuncをコールするとthisWindowオブジェクトになる。このオブジェクトは実行環境で変わり、ブラウザ上ではWindowオブジェクトになる。グローバルに宣言された変数はこのWindowオブジェクトのプロパティになっている。

prototypeと__proto__

関数はprototypeメンバとしてObjectをもつ。この関数でnewしてつくられたオブジェクトは__proto__メンバをもち同じObjectをもつ。

オブジェクトのプロパティを参照するとき、そのプロパティが見つからなかった場合は、__proto__から探す。よって関数のprototypeにあるプロパティを持たしておくと、オブジェクトで共通のプロパティを持つことができる。

prototype自体もオブジェクトでObjectは関数なのでprototype__proto__をもつ。よってあるプロパティを参照してそれが見つからないとき__proto__から見つけようとするがそれもないときは__proto__.__proto__から見つけようとする。よってObject.prototypeにプロパティを設定しておくとすべてのオブジェクトで共通のプロパティを持つことができる。

Object.prototype__proto__nullになっているので無限ループにはならない。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です