最強オブジェクト指向言語 javascript 再入門!

194
最強オブジェクト指向言語 JavaScript 再入門!

Upload: yuji-nojima

Post on 13-Dec-2014

164.313 views

Category:

Technology


0 download

DESCRIPTION

この資料では、JavaScript でオブジェクト指向プログラミングを行う際に備えておくことが望ましい、基礎知識や概念について解説します。 【対象者】 ・JavaScript でアプリケーションを構築できる方 ・JavaScript におけるオブジェクト指向プログラミングの  実現手法や原理への理解を深めたい方 ・Java 的なクラスベースの言語との違いに違和感や混乱を  感じてらっしゃる方

TRANSCRIPT

Page 2: 最強オブジェクト指向言語 JavaScript 再入門!

自己紹介

‣ ノジマユウジ @yuka2py

‣ 株式会社フォーエンキー代表取締役

‣ システム開発、グラフィックデザイン、DTPや印刷なども

‣ PythonとJavaScriptが大好き(Dartに興味深々)

‣ 様々なWebアプリケーション設計・構築・運用。またWPによるシステム開発、プラグイン開発などが主なお仕事

‣ おしゃれも大好き☆リボンやお花が好き☆

‣ 参加コミュニティ● WordBench 神戸● HTML5-WEST.jp● 日本Androidの会 神戸支部

絶賛お仕事募集中

Page 3: 最強オブジェクト指向言語 JavaScript 再入門!

去年のボクPython

1%Design15%

iOS4%

Android10%

Web(PHP/JS)10%

Windows(C#)20%

お嫁40%

お嫁W i n d o w s ( C # )W e b ( P H P / J S )A n d r o i di O SD e s i g nP y t h o n

2012年11月2日株式会社フォーエンキー調べ

Page 4: 最強オブジェクト指向言語 JavaScript 再入門!

最近のボクPython

1%

Design5%

Android5%

Windows15%

Web/WordPress25%

お嫁50%

お嫁Web /Wo r d P r e s sW i n d o w sA n d r o i dD e s i g nP y t h o n

2013年6月1日株式会社フォーエンキー調べ

Page 5: 最強オブジェクト指向言語 JavaScript 再入門!

はじめに

本セッションでは、JavaScript でオブジェクト指向プログラミングを行う際に備えておくことが望ましい、基礎知識や概念について解説します。

対象者・JavaScript でアプリケーションを構築できる方・JavaScript におけるオブジェクト指向プログラミングの 実現手法や原理への理解を深めたい方・Java 的なクラスベースの言語との違いに違和感や混乱を 感じてらっしゃる方

Page 6: 最強オブジェクト指向言語 JavaScript 再入門!

Simple and PowerfullJavaScript はとてもシンプルな言語仕様でありながらも、とても強力にオブジェクト指向プログラミングをサポートしています。

Page 7: 最強オブジェクト指向言語 JavaScript 再入門!

var obj = {}

JavaScript はオブジェクトが基本です。

Page 8: 最強オブジェクト指向言語 JavaScript 再入門!

オブジェクトの構造は、単純なキーと値の組み合わせによるハッシュテーブルのようなものです。とても大切な概念です。難しく考え過ぎないでください。

var obj = { key: value}

Page 9: 最強オブジェクト指向言語 JavaScript 再入門!

関数は、JavaScript において「第一級オブジェクト」…簡単に言うと「値」です。値ですから、変数に代入したり、取り出したり、受け渡しが制約なく行えます。

var f = function() {...}

Page 10: 最強オブジェクト指向言語 JavaScript 再入門!

もちろん、関数をオブジェクトのプロパティに格納する事もできます。オブジェクトが単純なハッシュテーブルで、関数も値であるならば、それはとても自然なことですね。

var obj = { key: function() {...}}

Page 11: 最強オブジェクト指向言語 JavaScript 再入門!

言い換えると、オブジェクトのメソッドはそれをメソッドとして持つオブジェクトに束縛されているのではなく、 オブジェクトによってただ参照されているだけです。

var obj = { key: function() {...}}

Page 12: 最強オブジェクト指向言語 JavaScript 再入門!

おしながき

‣クラスはあるか?

‣プロトタイプチェイン● JSでのオブジェクト指向プログラミングの基礎概念

‣オブジェクトの生成● newとコンストラクタ関数● プロトタイプチェインとの関連

‣スコープチェイン● var の意味● スコープチェインの正体

‣クロージャ● 定義された環境を束縛する

‣ this● thisの決定● thisのコントロール

Page 13: 最強オブジェクト指向言語 JavaScript 再入門!

クラスはあるか?

追記。本資料では、いわゆる「Java言語的なクラス」を「クラス」と定義してお話しています。それは、このスライドを書きはじめた動機が、Web上でJava言語的OOPで解釈しようとする記事が多くあり、それがJSを学ぼうとされる方の理解を混乱させているように思えたので、その混乱を解消したかったからです。また、ES.next の class 構文も説明するには早そうなこと、かつさらに理解を難しくするものとして割愛。なお、これらの省略や定義付けに違和感を覚えられる方は既に本資料の内容は理解済みとの認識です! (*'-'*)

Page 14: 最強オブジェクト指向言語 JavaScript 再入門!

QJavaScript でクラスは作れますか?

(?_?)

Page 15: 最強オブジェクト指向言語 JavaScript 再入門!

A 無理ポ。

Page 16: 最強オブジェクト指向言語 JavaScript 再入門!

Qでは、クラスっぽいものは作れますか?

(?_?)

Page 17: 最強オブジェクト指向言語 JavaScript 再入門!

A だから、無理ポ。

Page 18: 最強オブジェクト指向言語 JavaScript 再入門!

だって「オブジェクト」しか 無いんだもん。

Page 19: 最強オブジェクト指向言語 JavaScript 再入門!

「クラス」って何それ?

Page 20: 最強オブジェクト指向言語 JavaScript 再入門!

おいしいの?

Page 21: 最強オブジェクト指向言語 JavaScript 再入門!

(・∀・)

Page 22: 最強オブジェクト指向言語 JavaScript 再入門!

クラスっぽいものは出来るっていう方もいらっしゃると思いますが…

Page 23: 最強オブジェクト指向言語 JavaScript 再入門!

それが理解を難しくする

と僕は思う

クラスが無いのに、クラスの概念を持ち込んで理解しようとしたら、メンドクサクなりそうでないっすか?

Page 24: 最強オブジェクト指向言語 JavaScript 再入門!

そもそも…

Page 25: 最強オブジェクト指向言語 JavaScript 再入門!

オブジェクト指向に

Page 26: 最強オブジェクト指向言語 JavaScript 再入門!

クラスなんて要らない。クラスや型は、オブジェクト指向を

扱い易くするためのテクニックのひとつに過ぎません。

Page 27: 最強オブジェクト指向言語 JavaScript 再入門!

必要なのはオブジェクト。だって「オブジェクト指向」だしぃ~

Page 28: 最強オブジェクト指向言語 JavaScript 再入門!

だから JavaScript は 代わりに、

Page 29: 最強オブジェクト指向言語 JavaScript 再入門!

もっと面白い方法を選んだ。(↑あくまでも個人的主観)

Page 30: 最強オブジェクト指向言語 JavaScript 再入門!

それが…

Page 31: 最強オブジェクト指向言語 JavaScript 再入門!

プロトタイプチェイン

Page 32: 最強オブジェクト指向言語 JavaScript 再入門!

 「クラス」とは?の前に

Page 33: 最強オブジェクト指向言語 JavaScript 再入門!

似たオブジェクトを量産するための仕組み

Page 34: 最強オブジェクト指向言語 JavaScript 再入門!

Class (型) クラスクラスという「型」を元にして、オブジェクトを生成するイメージクラスから生成されたオブジェクトはクラスの特性(属性や機能)を受け継ぐ

Object(実体)

new

Object(実体)

new

Object(実体)

new

Page 35: 最強オブジェクト指向言語 JavaScript 再入門!

でも、クラスを使わなくても、同じ機能や属性(性質)を持ったオブジェクトを量産できればOKですよね。

Page 36: 最強オブジェクト指向言語 JavaScript 再入門!

では、JavaScript では?

Page 37: 最強オブジェクト指向言語 JavaScript 再入門!

Object (実体)(prototype)

プロトタイプオブジェクトは、自分自身が備えていない特性(機能や属性)を、別のオブジェクトにお願い(委譲)するイメージ。この時、お願いする先を「プロトタイプ」と言ったりします。

Object(実体)

delegate

Object(実体)

delegate

Object(実体)

delegate

Page 38: 最強オブジェクト指向言語 JavaScript 再入門!

…な、感じで実現します。

Page 39: 最強オブジェクト指向言語 JavaScript 再入門!

コードで見てみる。

Page 40: 最強オブジェクト指向言語 JavaScript 再入門!

3つのオブジェクトが登場しています。ここで、3つ目の、objC は __proto__ 属性以外何も持っていませんが、I Love Nicole と表示されます。I Love Nicole

var objA = { name : 'Yome', say : function () { alert('I Love ' + this.name); }};

var objB = { name : 'Nikole' };objB.__proto__ = objA;

var objC = { };objC.__proto__ = objB;

objC.say();

Page 41: 最強オブジェクト指向言語 JavaScript 再入門!

ここでポイントになるのは、__proto__という属性。この__proto__を介して、objC が objB を経て objA までの参照を保持できていることを確認してください。

所有

所有

var objA = { name : 'Yome', say : function () { alert('I Love ' + this.name); }};

var objB = { name : 'Nikole' };objB.__proto__ = objA;

var objC = { };objC.__proto__ = objB;

objC.say();

Page 42: 最強オブジェクト指向言語 JavaScript 再入門!

I Love Nicoleが表示される仕組み

Page 43: 最強オブジェクト指向言語 JavaScript 再入門!

objC.say() メソッドのコール

(objB)

objC.say

無い

アッタ!

無い

objC.__proto__.say

(objA)(objB)objC.__proto__.__proto__.say

objC に対して say() がコールされた時、JavaScript は、まず objC 自身が「say」というキーの値を持っているか調べます。しかし、見つからないので、次にその__proto__ …つまり objB を検索します。また見つからないので、objB の __proto__ = objA を検索し、say を見つけます。

Page 44: 最強オブジェクト指向言語 JavaScript 再入門!

objC.name 属性の参照

objC.name

アッタ!

無い

(objB)objC.__proto__.name

(objA)(objB)objC.__proto__.__proto__.say 使われ

ない

同様に、objC の name を参照した時、JavaScript は objC 自身が name を持っているか確認します。しかし、見つからないので、次にその__proto__ …つまり objB を検索し、name を見つけました。必要な名前が見つかった時点で、検索は終了します。

Page 45: 最強オブジェクト指向言語 JavaScript 再入門!

このように、自分に無い機能や属性を、__proto__ に入っている別のオブジェクトから

連鎖的に検索して探す仕組みが…

obj.__proto__.__proto__.property

Page 46: 最強オブジェクト指向言語 JavaScript 再入門!

obj.__proto__.__proto__.property

プロトタイプチェイン

Page 47: 最強オブジェクト指向言語 JavaScript 再入門!

では、同じ特性を持ったオブジェクトを量産するには?

Page 48: 最強オブジェクト指向言語 JavaScript 再入門!

同じプロトタイプを所有すればOK

var objA = { name : 'Yome', say : function () { alert('I Love ' + this.name); }};

var objB = { name : 'Nikole' };objB.__proto__ = objA;

var objC = { name : 'Gyu-Ri' };objC.__proto__ = objA;

objB.say(); // I Love NikoleobjC.say(); // I Love Gyu-Ri

Page 49: 最強オブジェクト指向言語 JavaScript 再入門!

クラスベースと較べてみる。

Page 50: 最強オブジェクト指向言語 JavaScript 再入門!

‣クラスベース ‣プロトタイプベース

class A

class B

class C

obj A

obj B

obj C

obj A of B

obj B of Cobj C of C

obj Eobj F

extends

extends

(delegete)

new

new

(delegete)

オブジェクトだけの世界

クラスからオブジェクト

を作成

obj D

(delegete)

new(delegete)

(delegete)

クラスベースではクラスという型を拡張し、そこからインスタンスを作成するイメージです。一方プロトタイプベースでは、必要な特性を持った他のオブジェクトを利用するイメージです。

Page 51: 最強オブジェクト指向言語 JavaScript 再入門!

プロトタイプチェインは、以上です。

Page 52: 最強オブジェクト指向言語 JavaScript 再入門!

あれ?

Page 53: 最強オブジェクト指向言語 JavaScript 再入門!

prototype 忘れてない?

Page 54: 最強オブジェクト指向言語 JavaScript 再入門!

いえいえ、以上っすぅ。だって prototype 無くても

プロトタイプチェインできたし (・∀・)

Page 55: 最強オブジェクト指向言語 JavaScript 再入門!

実は、prototype 属性は、プロトタイプチェインではなく、オブジェクトの生成で使われるもの。ネット上の情報で、ここを一緒に解説している例を見掛けますが、それが「ちょっと分かり難いなー」と個人的には思っています。プロトタイプチェインはあくまでも__proto__の連鎖的検索であって、prototype は検索対象では無いからです。

分けて考えるとイイらしい

Page 56: 最強オブジェクト指向言語 JavaScript 再入門!

では…

Page 57: 最強オブジェクト指向言語 JavaScript 再入門!

オブジェクトの生成

Page 58: 最強オブジェクト指向言語 JavaScript 再入門!

とはいえ…

Page 59: 最強オブジェクト指向言語 JavaScript 再入門!

実は __proto__は標準仕様ではありません。つまり、__proto__ が利用できない環境もあり、だから通常、このようなことはしません。ここまでは、プロトタイプチェインの概念を分かり易くするために __proto__ を使って説明していましたが、そういうことなので、実際のプログラミングではこんなことしないでくださいねー。 (・∀・)/

では、逆に、良く見かけるのは…

obj.__proto__ = otherObj

あまり見たコトない…

Page 60: 最強オブジェクト指向言語 JavaScript 再入門!

これは new 演算子とコンストラクタ関数によるオブジェクトの生成です。JavaScript におけるオブジェクトの生成で、よく見られるコードです。

var o = new Person('Nicole')

このあたりの記法が、クラスベースの言語を学んだ方を惑わしますね♪

こっちのが、 よく見る感じ!

Page 61: 最強オブジェクト指向言語 JavaScript 再入門!

この手法によるオブジェクト生成について見てみます。

Page 62: 最強オブジェクト指向言語 JavaScript 再入門!

準備

利用準備して、利用しているのは、間違いありません。

よく見るコードの例

var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}

var person = new Person('Nicole');

Page 63: 最強オブジェクト指向言語 JavaScript 再入門!

利用

クラス 定義?

よく見るコードの意味

var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}

var person = new Person('Nicole');

クラスは存在しないので、もちろん「クラス定義」ではありません。

Page 64: 最強オブジェクト指向言語 JavaScript 再入門!

prototypeの拡張

コンストラクタ関数の定義

よく見るコードの意味

利用とこんな感じで、ちゃんと分けて理解しておくのが良いと思います。

var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}

var person = new Person('Nicole');

Page 65: 最強オブジェクト指向言語 JavaScript 再入門!

コンストラクタ関数とは?

Page 66: 最強オブジェクト指向言語 JavaScript 再入門!

オブジェクトの初期化に使われる関数。new 演算子と組み合わせて関数をコールすることで、関数はコンストラクタ関数として実行され、オブジェクトの生成に利用されます。

Page 67: 最強オブジェクト指向言語 JavaScript 再入門!

new 演算子は?

Page 68: 最強オブジェクト指向言語 JavaScript 再入門!

オブジェクトの生成・継承・初期化を行う指示をしてます。

Page 69: 最強オブジェクト指向言語 JavaScript 再入門!

このようなコードを実行した時、実際にはどんな意味合いになるか?

var o = new Person('Nicole')

こんなふうに new した時は…

Page 70: 最強オブジェクト指向言語 JavaScript 再入門!

だいたいこんな意味

var newObj = {};

newObj.__proto__ = Person.prototype;

Person.apply(newObj, arguments);

return newObj;

※分かり易さの為に詳細を割愛しています。

擬似コード

Page 71: 最強オブジェクト指向言語 JavaScript 再入門!

だいたいこんな意味

var newObj = {};

newObj.__proto__ = Person.prototype;

Person.apply(newObj, arguments);

return newObj;

①新しい Object が生成される

new する度に、新しい個別のオブジェクトが生成されます。

Page 72: 最強オブジェクト指向言語 JavaScript 再入門!

だいたいこんな意味

var newObj = {};

newObj.__proto__ = Person.prototype;

Person.apply(newObj, arguments);

return newObj; ②プロトタイプのオブジェクトの参照を代入

コンストラクタ関数の Person.prototype を、新しいオブジェクトの __proto__ に参照を代入し、プロトタイプチェインの仕組みで、その特性を継承します。

Page 73: 最強オブジェクト指向言語 JavaScript 再入門!

だいたいこんな意味

var newObj = {};

newObj.__proto__ = Person.prototype;

Person.apply(newObj, arguments);

return newObj;

③ newObj を this に、コンストラクタ

関数を実行

これによって、コンストラクタ関数の中で、生成される新しいオブジェクトを this として参照し、その属性をセットしたりできるようになります。

Page 74: 最強オブジェクト指向言語 JavaScript 再入門!

だいたいこんな意味

var newObj = {};

newObj.__proto__ = Person.prototype;

Person.apply(newObj, arguments);

return newObj;

④完成したオブジェクトを返す

Person.prototype の特性を継承し、コンストラクタ関数によって初期化済みの、新しいオブジェクトが返され、プログラムで利用できるようになります。

Page 75: 最強オブジェクト指向言語 JavaScript 再入門!

ポイントはココ

newObj.__proto__ = Person.prototype;

Person.prototype オブジェクトの機能が、newObj で利用できるようになる!(プロトタイプチェインの仕組み)

Page 76: 最強オブジェクト指向言語 JavaScript 再入門!

整理すると…‣ __proto__

● プロトタイプチェインで検索されるプロトタイプオブジェクトが入ってる

‣prototype● プロトタイプオブジェクトの控え室

● new とコンストラクタ関数でオブジェクトを生成する時に、__proto__に代入される

プロトタイプチェインで使われるもの

オブジェクト生成で使われるもの

Page 77: 最強オブジェクト指向言語 JavaScript 再入門!

コードで見てみる。余計分かり難くなったらごめんなさいですが、__proto__ と prototype の動きをなるべく丁寧に書いてみました。ゆっくりじっくり読んでみてください。

Page 78: 最強オブジェクト指向言語 JavaScript 再入門!

(function() { var Person = function (name){ this.name = name; }; Person.prototype.name = 'nanashi'; Person.prototype.say = function () { alert('I Love ' + this.name); };

var p = new Person('Nicole');

alert( p.__proto__ === Person.prototype ); // true p.say(); // I Love Nicole

p.name = 'Gyu-Ri'; p.say(); // I Love Gyu-Ri

Person.prototype.name = 'Ha-Ra'; p.say(); // I Love Gyu-Ri

delete p.name; p.say(); // I Love Ha-Ra })();

SAMPLECODE

Page 79: 最強オブジェクト指向言語 JavaScript 再入門!

(function() { var Person = function (name){ this.name = name; }; Person.prototype.name = 'nanashi'; Person.prototype.say = function () { alert('I Love ' + this.name); };

var p = new Person('Nicole');

alert( p.__proto__ === Person.prototype ); p.say();

p.name = 'Gyu-Ri'; p.say();

Person.prototype.name = 'Ha-Ra'; p.say();

delete p.name; p.say(); })();

Person: {prototype: {name:'nanashi'say: functon () {…}

}}

この準備で、右側のようなオブジェクトが出来ます(コンストラクタ関数の実行部は省略)。

ここで、Person.prototype に入っているオブジェクトは、name と say の2つの属性を持ちます。

Page 80: 最強オブジェクト指向言語 JavaScript 再入門!

(function() { var Person = function (name){ this.name = name; }; Person.prototype.name = 'nanashi'; Person.prototype.say = function () { alert('I Love ' + this.name); };

var p = new Person('Nicole');

alert( p.__proto__ === Person.prototype ); p.say();

p.name = 'Gyu-Ri'; p.say();

Person.prototype.name = 'Ha-Ra'; p.say();

delete p.name; p.say(); })();

Person: {prototype: {name:'nanashi'say: functon () {…}

}}

new した時の擬似コード

var newObj = {};

newObj.__proto__ =

Person.apply(newObj, ['Nicole']);

return newObj;

Person を newすると、擬似コードにあるような初期化が行われ、新しいオブジェクトの __proto__ に Person.prototype のオブジェクトが代入されます。

代入

Page 81: 最強オブジェクト指向言語 JavaScript 再入門!

p: {name:'Nicole'__proto__:

}

(function() { var Person = function (name){ this.name = name; }; Person.prototype.name = 'nanashi'; Person.prototype.say = function () { alert('I Love ' + this.name); };

var p = new Person('Nicole');

alert( p.__proto__ === Person.prototype ); p.say();

p.name = 'Gyu-Ri'; p.say();

Person.prototype.name = 'Ha-Ra'; p.say();

delete p.name; p.say(); })();

Person: {prototype: {name:'nanashi'say: functon () {…}

}}

参照

結果、新しいオブジェクト p の __proto__ は、Person.prototype に入っているオブジェクトへの参照を持ちます。

Page 82: 最強オブジェクト指向言語 JavaScript 再入門!

p: {name:'Nicole'__proto__:

}

(function() { var Person = function (name){ this.name = name; }; Person.prototype.name = 'nanashi'; Person.prototype.say = function () { alert('I Love ' + this.name); };

var p = new Person('Nicole');

alert( p.__proto__ === Person.prototype ); p.say();

p.name = 'Gyu-Ri'; p.say();

Person.prototype.name = 'Ha-Ra'; p.say();

delete p.name; p.say(); })();

Person: {prototype: {name:'nanashi'say: functon () {…}

}}

True同じ

Person.prototype が p.__proto__ に代入された直後なので、当然ですが、同一性比較は true になります。

Page 83: 最強オブジェクト指向言語 JavaScript 再入門!

p: {name:'Nicole'__proto__:

}

(function() { var Person = function (name){ this.name = name; }; Person.prototype.name = 'nanashi'; Person.prototype.say = function () { alert('I Love ' + this.name); };

var p = new Person('Nicole');

alert( p.__proto__ === Person.prototype ); p.say();

p.name = 'Gyu-Ri'; p.say();

Person.prototype.name = 'Ha-Ra'; p.say();

delete p.name; p.say(); })();

Person: {prototype: {name:'nanashi'say: functon () {…}

}}

I Love Nicole参照

p.say() がコールされると、p 上に say を探すが見つかりません。__proto__を辿って、say を見つけます。name は p 上で見つかります。

Page 84: 最強オブジェクト指向言語 JavaScript 再入門!

p: {name:'Gyu-Ri'__proto__:

}

(function() { var Person = function (name){ this.name = name; }; Person.prototype.name = 'nanashi'; Person.prototype.say = function () { alert('I Love ' + this.name); };

var p = new Person('Nicole');

alert( p.__proto__ === Person.prototype ); p.say();

p.name = 'Gyu-Ri'; p.say();

Person.prototype.name = 'Ha-Ra'; p.say();

delete p.name; p.say(); })();

Person: {prototype: {name:'nanashi'say: functon () {…}

}}

I Love Gyu-Ri参照

先ほどと同じですが、p 自身が持つ name が変更されたため、当然、表示される内容は変化します。

Page 85: 最強オブジェクト指向言語 JavaScript 再入門!

p: {name:'Gyu-Ri'__proto__:

}

(function() { var Person = function (name){ this.name = name; }; Person.prototype.name = 'nanashi'; Person.prototype.say = function () { alert('I Love ' + this.name); };

var p = new Person('Nicole');

alert( p.__proto__ === Person.prototype ); p.say();

p.name = 'Gyu-Ri'; p.say();

Person.prototype.name = 'Ha-Ra'; p.say();

delete p.name; p.say(); })();

Person: {prototype: {name:'Ha-Ra'say: functon () {…}

}}

I Love Gyu-Ri参照

Person.prototype.name を変更しましたが、name は p 自身で見つかるので、結果に変化はありません。

Page 86: 最強オブジェクト指向言語 JavaScript 再入門!

p: {name:'Gyu-Ri'__proto__:

}

(function() { var Person = function (name){ this.name = name; }; Person.prototype.name = 'nanashi'; Person.prototype.say = function () { alert('I Love ' + this.name); };

var p = new Person('Nicole');

alert( p.__proto__ === Person.prototype ); p.say();

p.name = 'Gyu-Ri'; p.say();

Person.prototype.name = 'Ha-Ra'; p.say();

delete p.name; p.say(); })();

Person: {prototype: {name:'Ha-Ra'say: functon () {…}

}}

I Love Ha-Ra参照

p 自身の name を削除すると、p 自身は name を持たなくなるので、say も name も __proto__ から検索されて、結果、表示内容が変わります。

削除されて無くなった

Page 87: 最強オブジェクト指向言語 JavaScript 再入門!

こんな感じです。この解説で prototype 属性と __proto__ 属性それぞれの役割や位置づけ、またその原理などがしっくりと理解できたら嬉しいです。

Page 88: 最強オブジェクト指向言語 JavaScript 再入門!

それでは、次。

Page 89: 最強オブジェクト指向言語 JavaScript 再入門!

JavaScriptのもう一つの鎖などについて。

(チェイン)

Page 90: 最強オブジェクト指向言語 JavaScript 再入門!

スコープチェイン

Page 91: 最強オブジェクト指向言語 JavaScript 再入門!

スコープとは?

Page 92: 最強オブジェクト指向言語 JavaScript 再入門!

任意の変数にアクセスできる範囲。…で、いいか。 (;゚∀゚)

Page 93: 最強オブジェクト指向言語 JavaScript 再入門!

JavaScriptの2つのスコープ

‣グローバルスコープ● 文字通り「グローバル」● プログラム全体からアクセスできる

‣ローカルスコープ● ある特定の範囲でだけでアクセスできる

● JSでは基本的に、個々の関数の中がローカルスコープになる

● ある関数の中(=ローカルスコープ)で作成された変数は、その関数の内側でのみ参照できる

● 関数の引数もその関数の内側でのみで参照できる

Page 94: 最強オブジェクト指向言語 JavaScript 再入門!

例を見てみます。

Page 95: 最強オブジェクト指向言語 JavaScript 再入門!

外からは見えないからエラー

ローカル変数

function myfunc() { var name = 'Gyu-Ri';}

myfunc();

alert(name); //ReferenceError

Page 96: 最強オブジェクト指向言語 JavaScript 再入門!

でも逆に…

Page 97: 最強オブジェクト指向言語 JavaScript 再入門!

期待通り計算される

var a = 123;

function func1() { var b = 3;

function func2() { var c = 2; alert(a * b * c); //738 }

func2();}

func1();

外側の変数は見える

Page 98: 最強オブジェクト指向言語 JavaScript 再入門!

JavaScriptのスコープは、外から内は見えなくて、内から外は見える。

ポイント

「自分より外側は見える」ぐらいの、とてもシンプルな概念です。

Page 99: 最強オブジェクト指向言語 JavaScript 再入門!

もう少し見てみます。

Page 100: 最強オブジェクト指向言語 JavaScript 再入門!

名前が同じでもスコープが違えば

別の変数

var name = 'Nicole';

function myfunc() { var name = 'Gyu-Ri';}

myfunc();

alert(name); //Nicole別の変数なので、関数内での代入は外側の name に影響しない。

Page 101: 最強オブジェクト指向言語 JavaScript 再入門!

じゃ、これは?var name = 'Nicole';

function myfunc() { name = 'Gyu-Ri';}

myfunc();

alert(name); //???

Page 102: 最強オブジェクト指向言語 JavaScript 再入門!

var name = 'Nicole';

function myfunc() { name = 'Gyu-Ri';}

myfunc();

alert(name); //Gyu-Ri

同じ変数!!

同じ変数なので、関数内で 代 入 し た ら 外 側 の name も変わる。

Page 103: 最強オブジェクト指向言語 JavaScript 再入門!

なにが違った?

Page 104: 最強オブジェクト指向言語 JavaScript 再入門!

var name = 'Nicole';

function myfunc() { var name = 'Gyu-Ri';}

Before

Page 105: 最強オブジェクト指向言語 JavaScript 再入門!

var name = 'Nicole';

function myfunc() { name = 'Gyu-Ri';}

After

Page 106: 最強オブジェクト指向言語 JavaScript 再入門!

var name = 'Nicole';

function myfunc() { var name = 'Gyu-Ri';}

var が無い!!

Page 107: 最強オブジェクト指向言語 JavaScript 再入門!

var は、変数宣言。「新しく作るよ」宣言。

Page 108: 最強オブジェクト指向言語 JavaScript 再入門!

var a = 123

新しく変数を作る時は必ず必要です。

Page 109: 最強オブジェクト指向言語 JavaScript 再入門!

言い換えると、宣言してない時は、「既に有るよ」的な意味になる。

Page 110: 最強オブジェクト指向言語 JavaScript 再入門!

外側の変数は見える

var a = 123;

function func1() { var b = 3;

function func2() { var c = 2; alert(a * b * c); }

func2();}

func1(); //738と表示

さっきの例の変数 a の場合

Page 111: 最強オブジェクト指向言語 JavaScript 再入門!

このローカルスコープで、宣言されているのは c だけなので、 a と b は 既にあると解釈される

…でも、func2 のローカルスコープには、a と b は見つからない。

var a = 123;

function func1() { var b = 3;

function func2() { var c = 2; alert(a * b * c); }

func2();}

func1(); //738と表示

Page 112: 最強オブジェクト指向言語 JavaScript 再入門!

var a = 123;

function func1() { var b = 3;

function func2() { var c = 2; alert(a * b * c); }

func2();}

func1(); //738と表示

そこで JavaScript は、一つ外側の func1 のスコープで a と b を検索する。

そして、b を見つけるが、まだ a は見つからない。

Page 113: 最強オブジェクト指向言語 JavaScript 再入門!

var a = 123;

function func1() { var b = 3;

function func2() { var c = 2; alert(a * b * c); }

func2();}

func1(); //738と表示

そこで JavaScript は、さらに外側のスコープで a を検索し、そして a を発見する。

Page 114: 最強オブジェクト指向言語 JavaScript 再入門!

こんな感じで、順繰りに内側から外側へと探して行く。なんとなく…

Page 115: 最強オブジェクト指向言語 JavaScript 再入門!

プロトタイプチェインに似てなくない?

Page 116: 最強オブジェクト指向言語 JavaScript 再入門!

(func2)

変数 a への参照をちょっとオブジェクトっぽく書いてみた

scope.a

無い

無い

(func2) (func1)

scope.__scope__.a

アッタ!

(func2) (global)(func1)

scope.__scope__.__scope__.a

Page 117: 最強オブジェクト指向言語 JavaScript 再入門!

やっぱり、プロトタイプチェインにそっくり。

Page 118: 最強オブジェクト指向言語 JavaScript 再入門!

このように、今のスコープに無い識別子を、より外側のスコープから連鎖的に検索して探す仕組みが…

scope.__scope__.__scope__.identifier

Page 119: 最強オブジェクト指向言語 JavaScript 再入門!

スコープチェイン

scope.__scope__.__scope__.identifier

この事から、「グローバルスコープ」も、何も特別なものではなくて、単に「最も外側にあるローカルスコープ」という解釈もできます。実際のところ、グローバルスコープには幾つかの特別な役割も課せられていますが、感覚的なその理解は概ね正しいです。

Page 120: 最強オブジェクト指向言語 JavaScript 再入門!

難しく考えないことがポイント。

原理的には内から外への連鎖的なスコープの検索ですが、利用上は単に、「関数が定義された環境(ソースコード上の見かけ)において、その外側は見える」ということに過ぎません。プログラマにとっては、とても直感的な仕様です。

Page 121: 最強オブジェクト指向言語 JavaScript 再入門!

余談ですが、実はJavaScriptでは、変数のスコープでさえも、内部的にはオブジェクトで構成されています(=変数オブジェクト)。つまり、つまるところ、「スコープチェイン」も「プロトタイプチェイン」も、オブジェクトの特殊なプロパティによる連結リストによるデータ構造と、それを終端に向かって連鎖的に検索するという、よく似たシンプルな仕組みに過ぎません。またこれは、JavaScriptにおけるスコープの実体が、グローバルスコープ(グローバル変数オブジェクト)をrootとする、変数オブジェクトが連なった巨大なオブジェクトのツリー構造だということでもあります。興味深いですね。

残念ながら、それらのスコープを構成するオブジェクトのツリーを、プログラマが直接参照することは出来ません。しかし、プロトタイプチェインを構成する__proto__属性については、ECMA Script標準では無いものの、幾つかのブラウザ実装では実際に目にしてその仕組みを確認することが出来ます。これを良く観察することで、「スコープチェイン」と「プロトタイプチェイン」両方の理解を深めることが出来るはずです。

Page 122: 最強オブジェクト指向言語 JavaScript 再入門!

さて、JavaScript のスコープにはもうひとつ大事な概念があります。

Page 123: 最強オブジェクト指向言語 JavaScript 再入門!

クロージャ

Page 124: 最強オブジェクト指向言語 JavaScript 再入門!

早速のクロージャのサンプルコード。

Page 125: 最強オブジェクト指向言語 JavaScript 再入門!

var a = 123;

function func1() { var b = 3;

function func2() { var c = 2; alert(a * b * c); }

func2();}

func1(); //738と表示

(・∀・)?サッキト オナシ ジ ャ゙ネ?

Page 126: 最強オブジェクト指向言語 JavaScript 再入門!

そうです。さっきのもクロージャ。クロージャという言葉には広義なものと狭義なものとあります。そして「広義」にはこれもクロージャです。

Page 128: 最強オブジェクト指向言語 JavaScript 再入門!

ようするに、

Page 129: 最強オブジェクト指向言語 JavaScript 再入門!

var a = 123;

function func1() { var b = 3;

function func2() { var c = 2; alert(a * b * c); }

func2();}

func1(); //738と表示

この関数が定義された環境とは…

Page 130: 最強オブジェクト指向言語 JavaScript 再入門!

var a = 123;

function func1() { var b = 3;

function func2() { var c = 2; alert(a * b * c); }

func2();}

func1(); //738と表示

この関数を含む全てのスコー

プのこと

スコープチェインによって、関数定義の外側の変数まで参照できましたよね!

Page 131: 最強オブジェクト指向言語 JavaScript 再入門!

スコープチェインによって、関数定義の外側の変数まで参照できましたよね!

さっきの内側から外側は見えるってコト!

var a = 123;

function func1() { var b = 3;

function func2() { var c = 2; alert(a * b * c); }

func2();}

func1(); //738と表示

Page 132: 最強オブジェクト指向言語 JavaScript 再入門!

スコープチェイン => クロージャつまり JavaScript では、スコープチェインの仕組みが、そのままクロージャとして機能することになります。

JavaScript を使っていると、ごくごく当たり前かも知れませんが…、これが出来る汎用プログラミング言語は少し前までそう多くはありませんでした。PHPでは 5.3 から、Java でも Java 8 から利用できるようになります。

Page 133: 最強オブジェクト指向言語 JavaScript 再入門!

では、どんなふうに使えるか?

Page 134: 最強オブジェクト指向言語 JavaScript 再入門!

変数の隠蔽、別名の利用。みんなもう普通に使ってるよ。 (*'-'*)

Page 135: 最強オブジェクト指向言語 JavaScript 再入門!

即時関数でラップしてローカルスコープを作成

スコープの外からは見えない。=隠蔽されてる

引数を利用してオブジェクトの別名を利用

ここで、変数 privateValue や $ は、即時関数の外からは見えない変数になりますが、このスコープの内側で定義される関数からは参照することができます。

即時関数は文字通り即時実行されてその処理を抜けますが、privateValue や $ といった変数が、引き続きその中で定義された関数から参照できることがポイントです。

var Person = (function($) {

var privateValue = 'Hogeta';

function Person(name) { ... }

Person.prototype.xxxx = ...

return Person;

})(jQuery);

Page 136: 最強オブジェクト指向言語 JavaScript 再入門!

変数の永続化。とても重要でパワフルな概念。

Page 137: 最強オブジェクト指向言語 JavaScript 再入門!

返されたクロージャはi をずっと参照

※コードはWikipediaのクロージャのページからの引用です。

呼び出す毎に i が1ずつ

増える

newCounter は、新しい関数オブジェクトを生成して返却します。newCounter が実行されるたび、変数 i が初期化され、その i を参照するクロージャが返却されます。

newCounter が返却するクロージャを変数 c1 に受け取って実行すると、実行毎に1ずつ増えた値が得られます。

これは、newCounter が返した関数オブジェクトが、変数 i を参照し続けていることで実現されています。

このようにクロージャは、定義された時点の環境を束縛しています。

function newCounter() { var i = 0; return function() { i = i + 1; return i; }} var c1 = newCounter();alert(c1()); // 1alert(c1()); // 2alert(c1()); // 3

Page 138: 最強オブジェクト指向言語 JavaScript 再入門!

クロージャを使いこなすには?

Page 139: 最強オブジェクト指向言語 JavaScript 再入門!

とりあえず、書く。たくさんコードを書いて慣れるのが一番です。 (*'-'*)とてもシンプルで直感的な仕様なのですが、上手く利用するには訓練が必要です。クロージャの利用シーンはとても広範囲なので、たくさん書いて少しずつ用法を身につけていくと良いと思います。

Page 140: 最強オブジェクト指向言語 JavaScript 再入門!

では、最後に、

Page 141: 最強オブジェクト指向言語 JavaScript 再入門!

例のややこしいやつですよ。

Page 142: 最強オブジェクト指向言語 JavaScript 再入門!

this

Page 143: 最強オブジェクト指向言語 JavaScript 再入門!

this も、ワリと簡単。これこそ、クラスベース言語によくある考え方で理解しようとすると、落とし穴にはまります。一旦、頭を真っ白してください。

Page 144: 最強オブジェクト指向言語 JavaScript 再入門!

this を使った例。

Page 145: 最強オブジェクト指向言語 JavaScript 再入門!

これはOK

var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}

var person = new Person('Nicole');var btn = $('button#say-hello');

btn.on('click', function() { person.sayHello();});

よくあるパターンです。イベントにコールバック関数をバインドしています。ここで、btn.on に渡している関数はクロージャで、クロージャ変数として person を参照しています。

Page 146: 最強オブジェクト指向言語 JavaScript 再入門!

これはNG

var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}

var person = new Person('Nicole');var btn = $('button');

btn.on('click', person.sayHello);

前の例では、呼び出したい関数をコールバックとして登録しているだけだったので、sayHello 関数を直接バインドしたらどうだろう?とやってみると NG です…。結果として、(多くの場合)「Hello undefined」と表示されます。

Page 147: 最強オブジェクト指向言語 JavaScript 再入門!

なぜか?

Page 148: 最強オブジェクト指向言語 JavaScript 再入門!

関数はオブジェクトに束縛されない

ポイント常識!

Page 149: 最強オブジェクト指向言語 JavaScript 再入門!

繰り返しになりますが、オブジェクトのメソッドはそれを持つオブジェクトに束縛されているのではなく、その時そのオブジェクトによってただ参照されているだけです。この意味に注意してください。

var obj = { key: function() {...}}

Page 150: 最強オブジェクト指向言語 JavaScript 再入門!

オブジェクトのメソッドは、「オブジェクトによってただ参照されているだけ」つまり…

Page 151: 最強オブジェクト指向言語 JavaScript 再入門!

btn.on('click', person.sayHello);

person の sayHello メソッドを

渡してる

「person の sayHello」を渡しているのではない。

Page 152: 最強オブジェクト指向言語 JavaScript 再入門!

btn.on('click', person.sayHello);

「sayHello」に入っている、関数オブジェクトを渡している、が正解。関数オブジェクトだけが渡されている、という理解が大切です。

sayHelloの中の関数オブジェクトを渡してる

Page 153: 最強オブジェクト指向言語 JavaScript 再入門!

では、this ってなに?

Page 154: 最強オブジェクト指向言語 JavaScript 再入門!

ポイント

関数コール時にその関数が所属していたオブジェクト。= this

Page 155: 最強オブジェクト指向言語 JavaScript 再入門!

this

呼び出し時に、所属していたオブジェクトが、関数内での this になる

person.sayHello();

所属

Page 156: 最強オブジェクト指向言語 JavaScript 再入門!

では、ただの関数呼び出しの時は?

Page 157: 最強オブジェクト指向言語 JavaScript 再入門!

所属

sayHello();...nothing...???

ただの関数呼び出しで、関数がオブジェクトに所属していない時、関数内の this は何になるのか?

Page 158: 最強オブジェクト指向言語 JavaScript 再入門!

関数のコール時にレシーバーが無い時、this はグローバルオブジェクトになります。ブラウザ実装の場合、これは通常 window オブジェクトです。

globalobject = window

function sayHello() {    alert('Hello ' + this.name);}

sayHello();

Page 159: 最強オブジェクト指向言語 JavaScript 再入門!

つまり

Page 160: 最強オブジェクト指向言語 JavaScript 再入門!

ポイント

this は、呼び出し時に決定される

Page 161: 最強オブジェクト指向言語 JavaScript 再入門!

ところで、

Page 162: 最強オブジェクト指向言語 JavaScript 再入門!

this が呼び出し元で決定されるなら、

Page 163: 最強オブジェクト指向言語 JavaScript 再入門!

実は、呼び出し元で、thisを操ることもできます。

Page 164: 最強オブジェクト指向言語 JavaScript 再入門!

this を操る

Page 165: 最強オブジェクト指向言語 JavaScript 再入門!

call apply bind

thisを操るメソッド

関数オブジェクトには、this をコントロールできる3つのメソッドがあります。(関数オブジェクトだけに存在する)

Page 166: 最強オブジェクト指向言語 JavaScript 再入門!

関数に渡す引数

call(object, arg1, arg2, ...)

apply(object, Array)

bind(object, arg1, arg2, ...)

これらのメソッドの第1引数に与えた object が、関数内での this になります。また、その後の引数は、それぞれ関数呼び出し時に関数に与える引数になります。

this

this

this

Page 167: 最強オブジェクト指向言語 JavaScript 再入門!

3つのメソッドの利用法。

Page 168: 最強オブジェクト指向言語 JavaScript 再入門!

call と apply は関数を実行する

Page 169: 最強オブジェクト指向言語 JavaScript 再入門!

person を thisとして実行

call の第1引数が this に、第2引数以降の引数が、say関数の引数に。

function say(arg1, arg2) {    alert(arg1 + this.name + arg2);}var person = new Person('Nicole');

say.call(person, 'Hello ', ' chan');

call の例

Page 170: 最強オブジェクト指向言語 JavaScript 再入門!

person を thisとして実行

apply の例

call の第1引数が this に、第2引数の配列の内容が、say関数の引数になる。

引数の渡し方以外は call と同じ

function say(arg1, arg2) {    alert(arg1 + this.name + arg2);}var person = new Person('Nicole');

say.apply(person, ['Hello ', ' chan']);

Page 171: 最強オブジェクト指向言語 JavaScript 再入門!

他のオブジェクトのメンバだったら?

var p1 = { name: 'Gyu-Ri', say: function (arg1, arg2) {     alert(arg1 + this.name + arg2); }};var person = new Person('Nicole');

p1.say.call(person, 'Hello ', ' chan');

Page 172: 最強オブジェクト指向言語 JavaScript 再入門!

他のオブジェクトのメンバでも関係ない

関数はオブジェクトに「束縛されていない」ことを思い出してください。ここで、関数 say が p1 に属していても、指定した person が this になります。

var p1 = { name: 'Gyu-Ri', say: function (arg1, arg2) {     alert(arg1 + this.name + arg2); }};var person = new Person('Nicole');

p1.say.call(person, 'Hello ', ' chan');

Page 173: 最強オブジェクト指向言語 JavaScript 再入門!

bind は関数に値を束縛する

Page 174: 最強オブジェクト指向言語 JavaScript 再入門!

personをthisに束縛した新しい関数オブジェクトを返す

function say(arg1, arg2) {    alert(arg1 + this.name + arg2);}var person = new Person('Nicole');

var say2 = say.bind(person);say2('Hello ', ' chan');

結果:Hello Nicole chan と表示される

say2 関数の呼び出しでは、常に person が this となる

Page 175: 最強オブジェクト指向言語 JavaScript 再入門!

bind の利用例JavaScript OOP では非常に便利。

Page 176: 最強オブジェクト指向言語 JavaScript 再入門!

これはNGでした

さきほど NG だった例ですが...

var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}

var person = new Person('Nicole');var btn = $('button');

btn.on('click', person.sayHello);

Page 177: 最強オブジェクト指向言語 JavaScript 再入門!

こうすれば OK

bind で関数に this を束縛できるので、そのまま渡せるようになる。person を2回使ってるように見えるけど、そういう意味でないことに注意。

var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}

var person = new Person('Nicole');var btn = $('button');

btn.on('click', person.sayHello.bind(person));

Page 178: 最強オブジェクト指向言語 JavaScript 再入門!

apply とクロージャの利用例すこし長いし、元ネタは…だけど。

Page 179: 最強オブジェクト指向言語 JavaScript 再入門!

元のオブジェクト(self)と関数(func)をクロージャで保持し、必ず self に対して関数が適用されるようにしている。引数の数はまちまちなので、apply を使って実行する

コンストラクタ関数の中で、__bind を実行し、返された新しい関数をオブジェクトのメンバーとして保持する(関数の差し替え)

say には prefix も渡したいので、bind を使っているが、第1引数に person でなく null を渡しても、this は変更されない

// 絶対 this を離さないユーティリティメソッドfunction __bind (self, func) { return function () { return func.apply(self, arguments); };}

// コンストラクタ関数とプロトタイプを用意function Person (name) { this.name = name; this.say = __bind(this, this.say);}Person.prototype.say = function (prefix) { alert(prefix + this.name);}

// オブジェクト生成var person = new Person('Nicole');// 普通に利用nicole.say('I Love '); // I Love Nicole// 他の値をバインドしてもOKsetTimeout(person.say.bind(null, 'I Just Realy Love to '), 2000);

Page 180: 最強オブジェクト指向言語 JavaScript 再入門!

ということで…

Page 181: 最強オブジェクト指向言語 JavaScript 再入門!

JavaScript でオブジェクト指向プログラミングを行う際に備えておくことが望ましい、基礎知識や概念について解説してきました。

Page 182: 最強オブジェクト指向言語 JavaScript 再入門!

ちょっと欲張り過ぎましたが、どれも一度理解したらとても簡単な概念です。

Page 183: 最強オブジェクト指向言語 JavaScript 再入門!

JavaScript にはクラスが無いこと、

Page 184: 最強オブジェクト指向言語 JavaScript 再入門!

オブジェクトが単純なハッシュテーブルであること。

Page 185: 最強オブジェクト指向言語 JavaScript 再入門!

この2つの理解を深めると、たとえば this の挙動も納得できます。

Page 186: 最強オブジェクト指向言語 JavaScript 再入門!

JavaScript では、このように単純なデータ構造を幾つかのルールに沿って組み合わせることで、とても柔軟で強力なオブジェクト指向プログラミングを実現しています。

Page 187: 最強オブジェクト指向言語 JavaScript 再入門!

JavaScript が強力なのは、このシンプルさの所以です。

Page 188: 最強オブジェクト指向言語 JavaScript 再入門!

しかしある場面では、そのシンプルさが冗長なソースコードの記述を要求するかも知れません。

Page 189: 最強オブジェクト指向言語 JavaScript 再入門!

それらの問題は、例えば CoffeeScript や TypeScript といった、JavaScript を基本とする別の技術で解決できるかも知れません。

Page 190: 最強オブジェクト指向言語 JavaScript 再入門!

ただ、そういった新しい技術を利用するにあたっても、そのベースとなる JavaScript そのものの基礎理解は、あなたの開発を大いに助けてくれるはずだと、僕は信じています。

Page 191: 最強オブジェクト指向言語 JavaScript 再入門!

var obj = {}

JavaScript はオブジェクトが全てです。

Page 192: 最強オブジェクト指向言語 JavaScript 再入門!

ご清聴、ありがとうございました!

Page 193: 最強オブジェクト指向言語 JavaScript 再入門!

@yuka2py

書籍を執筆しました。JavaScript についても基礎から応用・発展まで詳しく書かれています。良かったら書店で手に取ってください。

http://www.amazon.co.jp/dp/4798129682

Page 194: 最強オブジェクト指向言語 JavaScript 再入門!

この文書は クリエイティブ・コモンズ 表示 - 継承 2.1 日本 ライセンスの下に提供されています。