ES6でいいのでは?
ES6のclass
等は、本来あった文法のシンタックスシュガー。なので、ES6の便利な書き方じゃないJavaScriptを押さえて、**JS使えます!!**って言えるようになりたい。
この記事では、**オブジェクト・関数・スコープチェーン(クロージャー)**について記載します。
JavaScriptのオブジェクト
一般的なプログラミング言語で使われるすべてのモノを表す文脈で使用される場合と、Objectオブジェクトのインスタンス(生成元のオブジェクトのプロパティを継承したオブジェクト)として使われる場合がある。
前者はいいとして、後者は以下のようになる。
var obj = {
name: 'objectName',
getObj: function() {
console.log(this.name);
}
}
console.log(obj.name); // objectName
obj.getObj(); // objectName
この変数に代入している{}
がObjectオブジェクトの生成。new Object()
で生成するのと同じ(シンタックスシュガー)。オブジェクト自身には、プロパティname
やメソッドgetObj
を定義することができる。
var obj1 = {};
var obj2 = new Object();
console.log(typeof(obj1)) // object
console.log(typeof(obj2)) // object
関数について
関数もオブジェクトの仲間
JavaScriptの関数は第一級オブジェクトである。(これ言ってみたかった)
第一級オブジェクト=生成、代入、演算などが制限なく行える対象 by wiki
... ちょっと難しいが、1
や2
などの数値、a
やb
などの文字列などのリテラルと言われる対象のこと。ここで大事なのは関数もオブジェクトなので、変数に自由に代入したりできるということだけ。
var foo = function() { console.log('foooooo'); }
foo() // foooooo
通常の関数呼び出しと、new付きの関数呼び出し
定義した関数を呼び出すときに、new
をつけるかつけないかで処理が大きく変わる。
var testFunc = function() {
this.name = 'foo';
}
var obj1 = new testFunc();
var obj2 = testFunc();
console.log(obj1); // testFunc {name: 'foo'}
console.log(obj2); // undefined
obj2
の場合はnew
がないので、ただの関数呼び出しになる。returnがない関数の戻り値はundefined
なのでundefined
エラーになってしまう。
一方、obj1
の場合はインスタンスが生成されていることがわかる。これはnew
したときに以下のような暗黙の処理が入ることによる。
var testFunc = function() {
// var this = {}
this.name = 'foo';
// return this;
}
コメントアウトした部分が暗黙の処理にあたる。
this
1オブジェクトが内部で定義され、そのオブジェクトにname
プロパティがセットされて、this
オブジェクトを返却するという処理を行ってくれると考えると(個人的には..)わかりやすい。
スコープチェーンについて
JavaScriptのイケてるクロージャーを理解するためにはスコープチェーンを理解する必要がある。=プログラミングの裏側で何が起こってるかを意識する必要がある。
まず、JavaScriptを実行すると、グローバルスコープ上にオブジェクトの最上位存在であるGlobalオブジェクトが自動で生成される。例えば、webブラウザのconsoleで実行した場合はwindow2オブジェクトがグローバルオブジェクトになる。グローバル変数の定義=windowオブジェクトのプロパティ定義である。
var foo = 'foo';
foo === window.foo; //true
次に、関数を呼び出す度に自動で生成されるオブジェクトがCallオブジェクトで、関数内のローカル変数・引数・親Callオブジェクトのアドレスなどを管理3する。
このCallオブジェクトをチェーンのように連結したリストは、Globalオブジェクトを末端にし、Callオブジェクトが生成されるたびに伸びていく。
変数などを探索する場合は、Globalオブジェクトと逆の先端から探索して最初に見つかった値を返却する。このリストがスコープチェーンといわれる。
// Globalオブジェクトが生成される #1
var prop1 = 'global';
var prop2 = 'global';
// outer関数用のCallオブジェクトが生成される #2
function outer() {
var prop1 = 'outer';
// inner関数用のCallオブジェクトが生成される #3
function inner() {
var prop3 = 'inner';
console.log(prop1); // outer #3→#2に存在するため
console.log(prop2); // global #3→#2→#1に存在するため
console.log(prop3); // inner #3に存在するため
}
inner();
console.log(prop1); // outer #3→#2に存在するため
}
outer();
上記のサンプルでスコープチェーンを確認すると、Globalオブジェクト(#1)、outerオブジェクト用のCallオブジェクト(#2)、innerオブジェクト用のCallオブジェクト(#3)の順でリストが生成され、#3→#2→#1の順で変数の値を探索していき、値があればその値を返却する。ない場合はReferenceError
。
クロージャーについて
スコープチェーンがわかればクロージャーを(たぶん)理解したようなもの。
クロージャーとは、自身(関数)を定義している関数の中にローカル変数の参照があるもの。ローカル変数は通常、関数呼び出し後に破棄されるが、クロージャーはローカル変数を参照し続けることが可能。ローカル変数の参照を関数内に閉じ込める(closure)ということ。
先ほどのサンプルのinner関数もクロージャーといえる。が、わかりづらいのでよくあるカウントアップを記載する。
var counterFunc = function() {
var count = 0;
return function() {
count++;
console.log(count);
};
};
var counter = counterFunc();
counter(); // 1
counter(); // 2
counter(); // 3
return
以下の即時関数内に、counterFunc
のローカル変数count
を閉じ込める。counter
変数内にcounterFunc
を代入すると、グローバル変数counter
がcounterFunc
を通してcount
を参照し続けるので、Glovalオブジェクトがある限り参照され続けるので値が破棄(ガベージコレクション)されず残り続ける。
prototypeについて
オブジェクトはプロトタイプをコピーしたものを元に作成され、すべてのオブジェクトはプロトタイプを参照している。プロトタイプで作成されたメソッドはオブジェクトが継承することができる。
オブジェクト指向言語のメソッドに近く、ES6のclass
もこれを元にしている。prototypeを使うメリットは主に、メソッドを作るよりメモリ使用率が少なくなる4こと。
名前はかっこいいが、わかりにくい概念ではなさそう5なので使い方のみ記載。
Object.prototype.sum = function(arg1, arg2){
return arg1 + arg2;
}
var foo = {}
console.log(foo.sum(1,2));
最後に
JavaScriptはふわっとしか触ってこなかったので、自分なりにまとめるのは勉強になりました。得意な方のツッコミお待ちしてます。
次はthis
とか、関数巻き上げみたいな特殊(?)なものをまとめる予定です。
2019/11/7
[続きっぽいもの]
(https://qiita.com/qeema/items/42d4458ba3ddf5d686da)書きました。
特に参考にしたサイトなど
-
this
については別途まとめようかと。 ↩ -
何となく、昔JavaScript界隈でよく聞いたDOMを思い出して、ちょっと調べた。document.getElementById的な。数多くあるライブラリでもうすっかり見なくなったが。。DOM=DocumentObjectModelの略で、windowオブジェクト->documentオブジェクトの下にhtmlタグとかが存在して、それらの文章をツリー上に表現したものらしい。documentもwindowオブジェクトのプロパティの一部。 ↩
-
メモリ管理はヒープ領域で行っていて、ガベージコレクションする言語とのこと。なので、クロージャーとか使えるのかな? ↩
-
インスタンス生成時はプロパティやメソッド分のメモリを確保するが、prototypeだと参照だけを持つのでその分が節約になる。 ↩
-
やっていくうちに難しいと感じたらまとめ直す予定です。 ↩