Movatterモバイル変換


[0]ホーム

URL:


Yuji Nojima, profile picture
Uploaded byYuji Nojima
PDF, PPTX375,539 views

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

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

Embed presentation

Download as PDF, PPTX
最強オブジェクト指向言語JavaScript 再入門!
自己紹介‣ ノジマユウジ @yuka2py‣ 株式会社フォーエンキー代表取締役‣ システム開発、グラフィックデザイン、DTPや印刷なども‣ PythonとJavaScriptが大好き(Dartに興味深々)‣ 様々なWebアプリケーション設計・構築・運用。またWPによるシステム開発、プラグイン開発などが主なお仕事‣ おしゃれも大好き☆リボンやお花が好き☆‣ 参加コミュニティ●WordBench 神戸●HTML5-WEST.jp●日本Androidの会 神戸支部絶賛お仕事募集中
去年のボクPython1%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 n2012年11月2日株式会社フォーエンキー調べ
最近のボクPython1%Design5%Android5%Windows15%Web/WordPress25%お嫁50%お 嫁W e b / W o 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 n2013年6月1日株式会社フォーエンキー調べ愛恐
はじめに本セッションでは、JavaScript でオブジェクト指向プログラミングを行う際に備えておくことが望ましい、基礎知識や概念について解説します。対象者・JavaScript でアプリケーションを構築できる方・JavaScript におけるオブジェクト指向プログラミングの 実現手法や原理への理解を深めたい方・Java 的なクラスベースの言語との違いに違和感や混乱を 感じてらっしゃる方
Simple and PowerfullJavaScript はとてもシンプルな言語仕様でありながらも、とても強力にオブジェクト指向プログラミングをサポートしています。
var obj = {}JavaScript はオブジェクトが基本です。
オブジェクトの構造は、単純なキーと値の組み合わせによるハッシュテーブルのようなものです。とても大切な概念です。難しく考え過ぎないでください。var obj = {key: value}
関数は、JavaScript において「第一級オブジェクト」…簡単に言うと「値」です。値ですから、変数に代入したり、取り出したり、受け渡しが制約なく行えます。var f = function() {...}
もちろん、関数をオブジェクトのプロパティに格納する事もできます。オブジェクトが単純なハッシュテーブルで、関数も値であるならば、それはとても自然なことですね。var obj = {key: function() {...}}
言い換えると、オブジェクトのメソッドはそれをメソッドとして持つオブジェクトに束縛されているのではなく、 オブジェクトによってただ参照されているだけです。var obj = {key: function() {...}}
おしながき‣ クラスはあるか?‣ プロトタイプチェイン●JSでのオブジェクト指向プログラミングの基礎概念‣ オブジェクトの生成●newとコンストラクタ関数●プロトタイプチェインとの関連‣ スコープチェイン●var の意味●スコープチェインの正体‣ クロージャ●定義された環境を束縛する‣ this●thisの決定●thisのコントロール
クラスはあるか?追記。本資料では、いわゆる「Java言語的なクラス」を「クラス」と定義してお話しています。それは、このスライドを書きはじめた動機が、Web上でJava言語的OOPで解釈しようとする記事が多くあり、それがJSを学ぼうとされる方の理解を混乱させているように思えたので、その混乱を解消したかったからです。また、ES.next の class 構文も説明するには早そうなこと、かつさらに理解を難しくするものとして割愛。なお、これらの省略や定義付けに違和感を覚えられる方は既に本資料の内容は理解済みとの認識です! (*'-'*)
QJavaScript でクラスは作れますか?(?_?)
A無理ポ。
Qでは、クラスっぽいものは作れますか?(?_?)
Aだから、無理ポ。
だって「オブジェクト」しか無いんだもん。
「クラス」って何それ?
おいしいの?
(・ ・)
クラスっぽいものは出来るっていう方もいらっしゃると思いますが…
それが理解を難しくすると僕は思うクラスが無いのに、クラスの概念を持ち込んで理解しようとしたら、メンドクサクなりそうでないっすか?
そもそも…
オブジェクト指向に
クラスなんて要らない。クラスや型は、オブジェクト指向を扱い易くするためのテクニックのひとつに過ぎません。
必要なのはオブジェクト。だって「オブジェクト指向」だしぃ∼
だから JavaScript は代わりに、
もっと面白い方法を選んだ。(↑あくまでも個人的主観)
それが…
プロトタイプチェイン
 「クラス」とは?の前に
似たオブジェクトを量産するための仕組み
Class (型) クラスクラスという「型」を元にして、オブジェクトを生成するイメージクラスから生成されたオブジェクトはクラスの特性(属性や機能)を受け継ぐObject(実体)newObject(実体)newObject(実体)new
でも、クラスを使わなくても、同じ機能や属性(性質)を持ったオブジェクトを量産できればOKですよね。
では、JavaScript では?
Object (実体)(prototype)プロトタイプオブジェクトは、自分自身が備えていない特性(機能や属性)を、別のオブジェクトにお願い(委譲)するイメージ。この時、お願いする先を「プロトタイプ」と言ったりします。Object(実体)delegateObject(実体)delegateObject(実体)delegate
…な、感じで実現します。
コードで見てみる。
3つのオブジェクトが登場しています。ここで、3つ目の、objC は__proto__ 属性以外何も持っていませんが、I Love Nicoleと表示されます。I Love Nicolevar objA = {name : 'Yome',say : function () {alert('I Love ' + this.name);}};var objB = { name : 'Nikole' };objB.__proto__ = objA;var objC = { };objC.__proto__ = objB;objC.say();
ここでポイントになるのは、__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();
I Love Nicoleが表示される仕組み
objC.say() メソッドのコール(objB)objC.say無いアッタ!無いobjC.__proto__.say(objA)(objB)objC.__proto__.__proto__.sayobjC に対して say() がコールされた時、JavaScript は、まず objC 自身が「say」というキーの値を持っているか調べます。しかし、見つからないので、次にその__proto__ …つまり objB を検索します。また見つからないので、objB の __proto__ = objA を検索し、say を見つけます。
objC.name 属性の参照objC.nameアッタ!無い(objB)objC.__proto__.name(objA)(objB)objC.__proto__.__proto__.say 使われない同様に、objC の name を参照した時、JavaScript は objC 自身が name を持っているか確認します。しかし、見つからないので、次にその__proto__ …つまり objB を検索し、name を見つけました。必要な名前が見つかった時点で、検索は終了します。
このように、自分に無い機能や属性を、__proto__ に入っている別のオブジェクトから連鎖的に検索して探す仕組みが…obj.__proto__.__proto__.property
obj.__proto__.__proto__.propertyプロトタイプチェイン
では、同じ特性を持ったオブジェクトを量産するには?
同じプロトタイプを所有すればOKvar 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
クラスベースと較べてみる。
‣ クラスベース ‣ プロトタイプベースclass Aclass Bclass Cobj Aobj Bobj Cobj A of Bobj B of Cobj C of Cobj Eobj Fextendsextends(delegete)newnew(delegete)オブジェクトだけの世界クラスからオブジェクトを作成obj D(delegete)new(delegete)(delegete)クラスベースではクラスという型を拡張し、そこからインスタンスを作成するイメージです。一方プロトタイプベースでは、必要な特性を持った他のオブジェクトを利用するイメージです。
プロトタイプチェインは、以上です。
あれ?
prototype 忘れてない?
いえいえ、以上っすぅ。だって prototype 無くてもプロトタイプチェインできたし (・ ・)
実は、prototype 属性は、プロトタイプチェインではなく、オブジェクトの生成で使われるもの。ネット上の情報で、ここを一緒に解説している例を見掛けますが、それが「ちょっと分かり難いなー」と個人的には思っています。プロトタイプチェインはあくまでも__proto__の連鎖的検索であって、prototype は検索対象では無いからです。分けて考えるとイイらしい
では…
オブジェクトの生成
とはいえ…
実は __proto__は標準仕様ではありません。つまり、__proto__ が利用できない環境もあり、だから通常、このようなことはしません。ここまでは、プロトタイプチェインの概念を分かり易くするために __proto__ を使って説明していましたが、そういうことなので、実際のプログラミングではこんなことしないでくださいねー。 (・ ・)/では、逆に、良く見かけるのは…obj.__proto__ = otherObjあまり見たコトない…
これは new 演算子とコンストラクタ関数によるオブジェクトの生成です。JavaScript におけるオブジェクトの生成で、よく見られるコードです。var o = new Person('Nicole')このあたりの記法が、クラスベースの言語を学んだ方を惑わしますね♪こっちのが、よく見る感じ!
この手法によるオブジェクト生成について見てみます。
準備利用準備して、利用しているのは、間違いありません。よく見るコードの例var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}var person = new Person('Nicole');
利用クラス定義?よく見るコードの意味var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}var person = new Person('Nicole');クラスは存在しないので、もちろん「クラス定義」ではありません。
prototypeの拡張コンストラクタ関数の定義よく見るコードの意味利用とこんな感じで、ちゃんと分けて理解しておくのが良いと思います。var Person = function (name) {    this.name = name;}Person.prototype.sayHello = function() {    alert('Hello ' + this.name);}var person = new Person('Nicole');
コンストラクタ関数とは?
オブジェクトの初期化に使われる関数。new 演算子と組み合わせて関数をコールすることで、関数はコンストラクタ関数として実行され、オブジェクトの生成に利用されます。
new 演算子は?
オブジェクトの生成・継承・初期化を行う指示をしてます。
このようなコードを実行した時、実際にはどんな意味合いになるか?var o = new Person('Nicole')こんなふうに new した時は…
だいたいこんな意味var newObj = {};newObj.__proto__ = Person.prototype;Person.apply(newObj, arguments);return newObj;※分かり易さの為に詳細を割愛しています。擬似コード
だいたいこんな意味var newObj = {};newObj.__proto__ = Person.prototype;Person.apply(newObj, arguments);return newObj;①新しい Object が生成されるnew する度に、新しい個別のオブジェクトが生成されます。
だいたいこんな意味var newObj = {};newObj.__proto__ = Person.prototype;Person.apply(newObj, arguments);return newObj;②プロトタイプのオブジェクトの参照を代入コンストラクタ関数の Person.prototype を、新しいオブジェクトの __proto__ に参照を代入し、プロトタイプチェインの仕組みで、その特性を継承します。
だいたいこんな意味var newObj = {};newObj.__proto__ = Person.prototype;Person.apply(newObj, arguments);return newObj;③ newObj をthis に、コンストラクタ関数を実行これによって、コンストラクタ関数の中で、生成される新しいオブジェクトを this として参照し、その属性をセットしたりできるようになります。
だいたいこんな意味var newObj = {};newObj.__proto__ = Person.prototype;Person.apply(newObj, arguments);return newObj;④完成したオブジェクトを返すPerson.prototype の特性を継承し、コンストラクタ関数によって初期化済みの、新しいオブジェクトが返され、プログラムで利用できるようになります。
ポイントはココnewObj.__proto__ = Person.prototype;Person.prototype オブジェクトの機能が、newObj で利用できるようになる!(プロトタイプチェインの仕組み)
整理すると…‣ __proto__●プロトタイプチェインで検索されるプロトタイプオブジェクトが入ってる‣ prototype●プロトタイプオブジェクトの控え室●new とコンストラクタ関数でオブジェクトを生成する時に、__proto__に代入されるプロトタイプチェインで使われるものオブジェクト生成で使われるもの
コードで見てみる。余計分かり難くなったらごめんなさいですが、__proto__ と prototype の動きをなるべく丁寧に書いてみました。ゆっくりじっくり読んでみてください。
(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
(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つの属性を持ちます。
(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 のオブジェクトが代入されます。代入
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 に入っているオブジェクトへの参照を持ちます。
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 になります。
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 上で見つかります。
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 が変更されたため、当然、表示される内容は変化します。
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 自身で見つかるので、結果に変化はありません。
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__ から検索されて、結果、表示内容が変わります。削除されて無くなった
こんな感じです。この解説で prototype 属性と __proto__ 属性それぞれの役割や位置づけ、またその原理などがしっくりと理解できたら嬉しいです。
それでは、次。
JavaScriptのもう一つの鎖などについて。(チェイン)
スコープチェイン
スコープとは?
任意の変数にアクセスできる範囲。…で、いいか。 (;゚ ゚)
JavaScriptの2つのスコープ‣ グローバルスコープ●文字通り「グローバル」●プログラム全体からアクセスできる‣ ローカルスコープ●ある特定の範囲でだけでアクセスできる●JSでは基本的に、個々の関数の中がローカルスコープになる●ある関数の中(=ローカルスコープ)で作成された変数は、その関数の内側でのみ参照できる●関数の引数もその関数の内側でのみで参照できる
例を見てみます。
外からは見えないからエラーローカル変数function myfunc() {var name = 'Gyu-Ri';}myfunc();alert(name); //ReferenceError
でも逆に…
期待通り計算されるvar a = 123;function func1() { var b = 3; function func2() {  var c = 2;  alert(a * b * c); //738 } func2();}func1();外側の変数は見える
JavaScriptのスコープは、外から内は見えなくて、内から外は見える。ポイント「自分より外側は見える」ぐらいの、とてもシンプルな概念です。
もう少し見てみます。
名前が同じでもスコープが違えば別の変数var name = 'Nicole';function myfunc() {var name = 'Gyu-Ri';}myfunc();alert(name); //Nicole別の変数なので、関数内での代入は外側の nameに影響しない。
じゃ、これは?var name = 'Nicole';function myfunc() {name = 'Gyu-Ri';}myfunc();alert(name); //???
var name = 'Nicole';function myfunc() {name = 'Gyu-Ri';}myfunc();alert(name); //Gyu-Ri同じ変数!!同じ変数なので、関数内で 代 入 し た ら 外 側 のname も変わる。
なにが違った?
var name = 'Nicole';function myfunc() {var name = 'Gyu-Ri';}Before
var name = 'Nicole';function myfunc() {name = 'Gyu-Ri';}After
var name = 'Nicole';function myfunc() {var name = 'Gyu-Ri';}varが無い!!
var は、変数宣言。「新しく作るよ」宣言。
var a = 123新しく変数を作る時は必ず必要です。
言い換えると、宣言してない時は、「既に有るよ」的な意味になる。
外側の変数は見えるvar a = 123;function func1() { var b = 3; function func2() {  var c = 2;  alert(a * b * c); } func2();}func1(); //738と表示さっきの例の変数 a の場合
このローカルスコープで、宣言されているのは 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と表示
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 は見つからない。
var a = 123;function func1() { var b = 3; function func2() {  var c = 2;  alert(a * b * c); } func2();}func1(); //738と表示そこで JavaScript は、さらに外側のスコープで a を検索し、そして a を発見する。
こんな感じで、順繰りに内側から外側へと探して行く。なんとなく…
プロトタイプチェインに似てなくない?
(func2)変数 a への参照をちょっとオブジェクトっぽく書いてみたscope.a無い無い(func2) (func1)scope.__scope__.aアッタ!(func2) (global)(func1)scope.__scope__.__scope__.a
やっぱり、プロトタイプチェインにそっくり。
このように、今のスコープに無い識別子を、より外側のスコープから連鎖的に検索して探す仕組みが…scope.__scope__.__scope__.identifier
スコープチェインscope.__scope__.__scope__.identifierこの事から、「グローバルスコープ」も、何も特別なものではなくて、単に「最も外側にあるローカルスコープ」という解釈もできます。実際のところ、グローバルスコープには幾つかの特別な役割も課せられていますが、感覚的なその理解は概ね正しいです。
難しく考えないことがポイント。原理的には内から外への連鎖的なスコープの検索ですが、利用上は単に、「関数が定義された環境(ソースコード上の見かけ)において、その外側は見える」ということに過ぎません。プログラマにとっては、とても直感的な仕様です。
余談ですが、実はJavaScriptでは、変数のスコープでさえも、内部的にはオブジェクトで構成されています(=変数オブジェクト)。つまり、つまるところ、「スコープチェイン」も「プロトタイプチェイン」も、オブジェクトの特殊なプロパティによる連結リストによるデータ構造と、それを終端に向かって連鎖的に検索するという、よく似たシンプルな仕組みに過ぎません。またこれは、JavaScriptにおけるスコープの実体が、グローバルスコープ(グローバル変数オブジェクト)をrootとする、変数オブジェクトが連なった巨大なオブジェクトのツリー構造だということでもあります。興味深いですね。残念ながら、それらのスコープを構成するオブジェクトのツリーを、プログラマが直接参照することは出来ません。しかし、プロトタイプチェインを構成する__proto__属性については、ECMA Script標準では無いものの、幾つかのブラウザ実装では実際に目にしてその仕組みを確認することが出来ます。これを良く観察することで、「スコープチェイン」と「プロトタイプチェイン」両方の理解を深めることが出来るはずです。
さて、JavaScript のスコープにはもうひとつ大事な概念があります。
クロージャ
早速のクロージャのサンプルコード。
var a = 123;function func1() { var b = 3; function func2() {  var c = 2;  alert(a * b * c); } func2();}func1(); //738と表示(・∀・)?サッキト オナジジャネ?
そうです。さっきのもクロージャ。クロージャという言葉には広義なものと狭義なものとあります。そして「広義」にはこれもクロージャです。
引数以外の変数を実行時の環境ではなく、自身が定義された環境(静的スコープ)において解決することを特徴とする。by Wikipedia(いつもありがとう)クロージャの意味
ようするに、
var a = 123;function func1() { var b = 3; function func2() {  var c = 2;  alert(a * b * c); } func2();}func1(); //738と表示この関数が定義された環境とは…
var a = 123;function func1() { var b = 3; function func2() {  var c = 2;  alert(a * b * c); } func2();}func1(); //738と表示この関数を含む全てのスコープのことスコープチェインによって、関数定義の外側の変数まで参照できましたよね!
スコープチェインによって、関数定義の外側の変数まで参照できましたよね!さっきの内側から外側は見えるってコト!var a = 123;function func1() { var b = 3; function func2() {  var c = 2;  alert(a * b * c); } func2();}func1(); //738と表示
スコープチェイン => クロージャつまり JavaScript では、スコープチェインの仕組みが、そのままクロージャとして機能することになります。JavaScript を使っていると、ごくごく当たり前かも知れませんが…、これが出来る汎用プログラミング言語は少し前までそう多くはありませんでした。PHPでは 5.3 から、Java でも Java 8 から利用できるようになります。
では、どんなふうに使えるか?
変数の隠 、別名の利用。みんなもう普通に使ってるよ。 (*'-'*)
即時関数でラップしてローカルスコープを作成スコープの外からは見えない。=隠 されてる引数を利用してオブジェクトの別名を利用ここで、変数 privateValue や$ は、即時関数の外からは見えない変数になりますが、このスコープの内側で定義される関数からは参照することができます。即時関数は文字通り即時実行されてその処理を抜けますが、privateValue や $ といった変数が、引き続きその中で定義された関数から参照できることがポイントです。var Person = (function($) { var privateValue = 'Hogeta'; function Person(name) { ... } Person.prototype.xxxx = ... return Person;})(jQuery);
変数の永続化。とても重要でパワフルな概念。
返されたクロージャは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
クロージャを使いこなすには?
とりあえず、書く。たくさんコードを書いて慣れるのが一番です。 (*'-'*)とてもシンプルで直感的な仕様なのですが、上手く利用するには訓練が必要です。クロージャの利用シーンはとても広範囲なので、たくさん書いて少しずつ用法を身につけていくと良いと思います。
では、最後に、
例のややこしいやつですよ。
this
this も、ワリと簡単。これこそ、クラスベース言語によくある考え方で理解しようとすると、落とし穴にはまります。一旦、頭を真っ白してください。
this を使った例。
これはOKvar 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 を参照しています。
これはNGvar 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」と表示されます。
なぜか?
関数はオブジェクトに束縛されないポイント常識!
繰り返しになりますが、オブジェクトのメソッドはそれを持つオブジェクトに束縛されているのではなく、その時そのオブジェクトによってただ参照されているだけです。この意味に注意してください。var obj = {key: function() {...}}
オブジェクトのメソッドは、「オブジェクトによってただ参照されているだけ」つまり…
btn.on('click', person.sayHello);person のsayHello メソッドを渡してる「person の sayHello」を渡しているのではない。
btn.on('click', person.sayHello);「sayHello」に入っている、関数オブジェクトを渡している、が正解。関数オブジェクトだけが渡されている、という理解が大切です。sayHelloの中の関数オブジェクトを渡してる
では、this ってなに?
ポイント関数コール時にその関数が所属していたオブジェクト。= this
this呼び出し時に、所属していたオブジェクトが、関数内での this になるperson.sayHello();所属
では、ただの関数呼び出しの時は?
所属sayHello();...nothing...???ただの関数呼び出しで、関数がオブジェクトに所属していない時、関数内の this は何になるのか?
関数のコール時にレシーバーが無い時、this はグローバルオブジェクトになります。ブラウザ実装の場合、これは通常 window オブジェクトです。globalobject= windowfunction sayHello() {    alert('Hello ' + this.name);}sayHello();
つまり
ポイントthis は、呼び出し時に決定される
ところで、
this が呼び出し元で決定されるなら、
実は、呼び出し元で、thisを操ることもできます。
this を操る
call apply bindthisを操るメソッド関数オブジェクトには、this をコントロールできる3つのメソッドがあります。(関数オブジェクトだけに存在する)
関数に渡す引数call(object, arg1, arg2, ...)apply(object, Array)bind(object, arg1, arg2, ...)これらのメソッドの第1引数に与えた object が、関数内での this になります。また、その後の引数は、それぞれ関数呼び出し時に関数に与える引数になります。thisthisthis
3つのメソッドの利用法。
call と apply は関数を実行する
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 の例
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']);
他のオブジェクトのメンバだったら?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');
他のオブジェクトのメンバでも関係ない関数はオブジェクトに「束縛されていない」ことを思い出してください。ここで、関数 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');
bind は関数に値を束縛する
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 となる
bind の利用例JavaScript OOP では非常に便利。
これは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);
こうすればOKbind で関数に 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));
apply とクロージャの利用例すこし長いし、元ネタは…だけど。
元のオブジェクト(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);
ということで…
JavaScript でオブジェクト指向プログラミングを行う際に備えておくことが望ましい、基礎知識や概念について解説してきました。
ちょっと欲張り過ぎましたが、どれも一度理解したらとても簡単な概念です。
JavaScript にはクラスが無いこと、
オブジェクトが単純なハッシュテーブルであること。
この2つの理解を深めると、たとえば this の挙動も納得できます。
JavaScript では、このように単純なデータ構造を幾つかのルールに沿って組み合わせることで、とても柔軟で強力なオブジェクト指向プログラミングを実現しています。
JavaScript が強力なのは、このシンプルさの所以です。
しかしある場面では、そのシンプルさが冗長なソースコードの記述を要求するかも知れません。
それらの問題は、例えば CoffeeScript やTypeScript といった、JavaScript を基本とする別の技術で解決できるかも知れません。
ただ、そういった新しい技術を利用するにあたっても、そのベースとなる JavaScript そのものの基礎理解は、あなたの開発を大いに助けてくれるはずだと、僕は信じています。
var obj = {}JavaScript はオブジェクトが全てです。
ご清聴、ありがとうございました!
@yuka2py書籍を執筆しました。JavaScript についても基礎から応用・発展まで詳しく書かれています。良かったら書店で手に取ってください。http://www.amazon.co.jp/dp/4798129682
この文書は クリエイティブ・コモンズ 表示 - 継承 2.1 日本 ライセンスの下に提供されています。

Recommended

PDF
オブジェクト指向できていますか?
PDF
オブジェクト指向の設計と実装の学び方のコツ
PDF
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
PDF
ドメイン駆動設計 ( DDD ) をやってみよう
ODP
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
PDF
オブジェクト指向プログラミングのためのモデリング入門
PPTX
Redisの特徴と活用方法について
PPTX
概念モデリング再入門 + DDD
PDF
【Unite Tokyo 2019】Understanding C# Struct All Things
PDF
こわくない Git
PDF
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
PDF
ソーシャルゲームのためのデータベース設計
PDF
ドメイン駆動設計 本格入門
PDF
Pythonによる黒魔術入門
KEY
やはりお前らのMVCは間違っている
PDF
20分くらいでわかった気分になれるC++20コルーチン
 
PDF
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
PPTX
世界一わかりやすいClean Architecture
PDF
オブジェクト指向エクササイズのススメ
PDF
それはYAGNIか? それとも思考停止か?
PPTX
ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発
PDF
いつやるの?Git入門
PDF
PlaySQLAlchemy: SQLAlchemy入門
PPTX
C# 8.0 null許容参照型
PPTX
async/await のしくみ
PPTX
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
PPTX
PyTorchLightning ベース Hydra+MLFlow+Optuna による機械学習開発環境の構築
PDF
怖くないSpring Bootのオートコンフィグレーション
PDF
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
PPTX
モテる JavaScript

More Related Content

PDF
オブジェクト指向できていますか?
PDF
オブジェクト指向の設計と実装の学び方のコツ
PDF
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
PDF
ドメイン駆動設計 ( DDD ) をやってみよう
ODP
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
PDF
オブジェクト指向プログラミングのためのモデリング入門
PPTX
Redisの特徴と活用方法について
PPTX
概念モデリング再入門 + DDD
オブジェクト指向できていますか?
オブジェクト指向の設計と実装の学び方のコツ
DDD x CQRS 更新系と参照系で異なるORMを併用して上手くいった話
ドメイン駆動設計 ( DDD ) をやってみよう
Goのサーバサイド実装におけるレイヤ設計とレイヤ内実装について考える
オブジェクト指向プログラミングのためのモデリング入門
Redisの特徴と活用方法について
概念モデリング再入門 + DDD

What's hot

PDF
【Unite Tokyo 2019】Understanding C# Struct All Things
PDF
こわくない Git
PDF
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
PDF
ソーシャルゲームのためのデータベース設計
PDF
ドメイン駆動設計 本格入門
PDF
Pythonによる黒魔術入門
KEY
やはりお前らのMVCは間違っている
PDF
20分くらいでわかった気分になれるC++20コルーチン
 
PDF
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
PPTX
世界一わかりやすいClean Architecture
PDF
オブジェクト指向エクササイズのススメ
PDF
それはYAGNIか? それとも思考停止か?
PPTX
ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発
PDF
いつやるの?Git入門
PDF
PlaySQLAlchemy: SQLAlchemy入門
PPTX
C# 8.0 null許容参照型
PPTX
async/await のしくみ
PPTX
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
PPTX
PyTorchLightning ベース Hydra+MLFlow+Optuna による機械学習開発環境の構築
PDF
怖くないSpring Bootのオートコンフィグレーション
【Unite Tokyo 2019】Understanding C# Struct All Things
こわくない Git
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
ソーシャルゲームのためのデータベース設計
ドメイン駆動設計 本格入門
Pythonによる黒魔術入門
やはりお前らのMVCは間違っている
20分くらいでわかった気分になれるC++20コルーチン
 
DDDのモデリングとは何なのか、 そしてどうコードに落とすのか
世界一わかりやすいClean Architecture
オブジェクト指向エクササイズのススメ
それはYAGNIか? それとも思考停止か?
ちゃんとした C# プログラムを書けるようになる実践的な方法~ Visual Studio を使った 高品質・低コスト・保守性の高い開発
いつやるの?Git入門
PlaySQLAlchemy: SQLAlchemy入門
C# 8.0 null許容参照型
async/await のしくみ
「関心の分離」と「疎結合」 ソフトウェアアーキテクチャのひとかけら
PyTorchLightning ベース Hydra+MLFlow+Optuna による機械学習開発環境の構築
怖くないSpring Bootのオートコンフィグレーション

Viewers also liked

PDF
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
PPTX
モテる JavaScript
PDF
モダンJavaScript環境構築一歩目
PDF
Alt01-LT
PDF
JavaScript基礎勉強会
PPTX
初心者 × AngularJS × TypeScript
PDF
AngularJSで業務システムUI部品化
PDF
⑯jQueryをおぼえよう!その2
PDF
JavaScript/CSS 2015 Autumn
PDF
はじめよう Backbone.js
PDF
"今" 使えるJavaScriptのトレンド
PDF
Javascriptのあれやこれやをまとめて説明してみる
PDF
Angularモダンweb開発セミナー紹介 20170923
PDF
⑮jQueryをおぼえよう!その1
PPTX
忙しい人のためのBackbone.jsとAngular.js入門
PDF
デザイナーとの協業を本気で考える
 
PDF
angular X designer - デザイナからみたAngularJS #ten1club
PDF
JS初心者だけど3ヶ月でこんだけ書けるようになりました
PDF
3分でわかるangular js
PDF
Angularを利用しよう
ノンプログラマーでも明日から使えるJavaScript簡単プログラム 先生:柳井 政和
モテる JavaScript
モダンJavaScript環境構築一歩目
Alt01-LT
JavaScript基礎勉強会
初心者 × AngularJS × TypeScript
AngularJSで業務システムUI部品化
⑯jQueryをおぼえよう!その2
JavaScript/CSS 2015 Autumn
はじめよう Backbone.js
"今" 使えるJavaScriptのトレンド
Javascriptのあれやこれやをまとめて説明してみる
Angularモダンweb開発セミナー紹介 20170923
⑮jQueryをおぼえよう!その1
忙しい人のためのBackbone.jsとAngular.js入門
デザイナーとの協業を本気で考える
 
angular X designer - デザイナからみたAngularJS #ten1club
JS初心者だけど3ヶ月でこんだけ書けるようになりました
3分でわかるangular js
Angularを利用しよう

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

PDF
JavaScriptの落とし穴
PPT
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
PDF
ちょっと詳しくJavaScript 第3回【prototype】
PDF
JavaScript入門
PPTX
Javascript勉強会資料1
PDF
JavaScriptおよびXPages Vote技術解説
PDF
Javascripでオブジェクト指向
PDF
クライアントサイドjavascript簡単紹介
PDF
JSクラス定義
PPTX
Javascriptのデザインパターン【勉強会資料】
KEY
いまさらJavaScript
PDF
Kanazawa.js.Next
PDF
「エクストリームエンジニアへの道(Swift編)」
PDF
JSの基本的なことをちょっと掘り下げてみる話シリーズ Chapter04. 〜 prototype編(やっと..!) 〜
PPTX
Javascript3
PDF
JavaScript.Next
PPTX
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
PPT
20090121 J QueryからはじめるJava Script~初級編~
PDF
JavaScript (ECMAScript) 2013
PDF
JSの基本的なことをちょっと掘り下げてみる話シリーズ Chapter03. 〜 prototype?編 〜
JavaScriptの落とし穴
[A 3]SSJSでも使える!Javascriptでオブジェクト指向プログラミング入門
ちょっと詳しくJavaScript 第3回【prototype】
JavaScript入門
Javascript勉強会資料1
JavaScriptおよびXPages Vote技術解説
Javascripでオブジェクト指向
クライアントサイドjavascript簡単紹介
JSクラス定義
Javascriptのデザインパターン【勉強会資料】
いまさらJavaScript
Kanazawa.js.Next
「エクストリームエンジニアへの道(Swift編)」
JSの基本的なことをちょっと掘り下げてみる話シリーズ Chapter04. 〜 prototype編(やっと..!) 〜
Javascript3
JavaScript.Next
jQueryの先に行こう!最先端のWeb開発トレンドを学ぶ
20090121 J QueryからはじめるJava Script~初級編~
JavaScript (ECMAScript) 2013
JSの基本的なことをちょっと掘り下げてみる話シリーズ Chapter03. 〜 prototype?編 〜

More from Yuji Nojima

KEY
エンジニアの為のWordPress入門 〜WordPressはWebAppプラットフォームです〜
PDF
Chromeでjavascriptデバッグ!まず半歩♪
PDF
Wp プラグインapiから理解するword press.share
KEY
WordPress プラグイン Infinite Scroll を試してみた
PDF
今日から使える! Sass/compass ゆるめ勉強会
KEY
WordPressプラグイン作成入門
PDF
簡単!低コスト!楽しい!レスポンシブ デザイン ディレクション
KEY
WordPressプラグイン Jetpack って何だ?!
エンジニアの為のWordPress入門 〜WordPressはWebAppプラットフォームです〜
Chromeでjavascriptデバッグ!まず半歩♪
Wp プラグインapiから理解するword press.share
WordPress プラグイン Infinite Scroll を試してみた
今日から使える! Sass/compass ゆるめ勉強会
WordPressプラグイン作成入門
簡単!低コスト!楽しい!レスポンシブ デザイン ディレクション
WordPressプラグイン Jetpack って何だ?!

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


[8]ページ先頭

©2009-2025 Movatter.jp