2013/4/27 @ HC社内勉強会
JavaScript
の落とし穴
今日話すこと
普通のOOPL経験者から見た
コアJSのハマりどころ
→ 基礎的な話
→ イディオムの理解
基礎編
JSのオブジェクトは
連想配列みたいなもの
1 // 空のオブジェクトを作成
2 var dog = {};
3
4 // プロパティをひとつ追加
5 dog.name = "Pochi";
6
7 // ブラケットでもアクセスできる
8 dog['breed'] = "Shih Tzu";
9
10 // 関数をひとつ追加 -> メソッド
11 dog.getBreed = function () {
12 return this.breed;
13 }
JSのオブジェクトは
連想配列みたいなもの
1 // 同じものをオブジェクトリテラルで表記
2 var dog = {
3 name: "Pochi",
4 breed: "Shih Tzu",
5 getBreed: function () {
6 return this.breed;
7 }
8 };
クラスっぽいものと
コンストラクタ関数
1 // Stringはコンストラクタなのか?
2 var str1 = new String(123);
3 console.log(str1); // "123"
4
5 // 関数? それともキャスト???
6 var str2 = String(456);
7 console.log(str2); // "456"
クラスっぽいものと
コンストラクタ関数
1 // クラスっぽいものを作るコンストラクタ
2 var Person = function (name) {
3 this.name = name;
4 this.say = function () {
5 return "I am " + this.name;
6 };
7 };
8
9 // new をつけて呼び出す
10 var adam = new Person("Adam");
11 console.log(adam.say()); //"I am Adam"
12
13 // new をつけずに呼び出す
14 var eve = Person("Eve");
15 console.log(eve); //undefined!
オブジェクト
this
name : Adam
say : {...}
adam
クラスっぽいものと
コンストラクタ関数
1 // クラスっぽいものを作るコンストラクタ
2 var Person = function (name) {
3 this.name = name;
4 this.say = function () {
5 return "I am " + this.name;
6 };
7 };
8
9 // new をつけて呼び出す
10 var adam = new Person("Adam");
11 console.log(adam.say()); //"I am Adam"
12
13 // new をつけずに呼び出す
14 var eve = Person("Eve");
15 console.log(eve); //undefined!
オブジェクト
this
name : Adam
say : {...}
adam
クラスっぽいものと
コンストラクタ関数
1 // クラスっぽいものを作るコンストラクタ
2 var Person = function (name) {
3 this.name = name;
4 this.say = function () {
5 return "I am " + this.name;
6 };
7 };
8
9 // new をつけて呼び出す
10 var adam = new Person("Adam");
11 console.log(adam.say()); //"I am Adam"
12
13 // new をつけずに呼び出す
14 var eve = Person("Eve");
15 console.log(eve); //undefined!
オブジェクト
this
name : Adam
say : {...}
adam
クラスっぽいものと
コンストラクタ関数
1 // クラスっぽいものを作るコンストラクタ
2 var Person = function (name) {
3 this.name = name;
4 this.say = function () {
5 return "I am " + this.name;
6 };
7 };
8
9 // new をつけて呼び出す
10 var adam = new Person("Adam");
11 console.log(adam.say()); //"I am Adam"
12
13 // new をつけずに呼び出す
14 var eve = Person("Eve");
15 console.log(eve); //undefined!
オブジェクト
this
name : Adam
say : {...}
adam
クラスっぽいものと
コンストラクタ関数
1 // クラスっぽいものを作るコンストラクタ
2 var Person = function (name) {
3 this.name = name;
4 this.say = function () {
5 return "I am " + this.name;
6 };
7 };
8
9 // new をつけて呼び出す
10 var adam = new Person("Adam");
11 console.log(adam.say()); //"I am Adam"
12
13 // new をつけずに呼び出す
14 var eve = Person("Eve");
15 console.log(eve); //undefined!
オブジェクト
this
name : Adam
say : {...}
adam
クラスっぽいものと
コンストラクタ関数
1 // クラスっぽいものを作るコンストラクタ
2 var Person = function (name) {
3 this.name = name;
4 this.say = function () {
5 return "I am " + this.name;
6 };
7 };
8
9 // new をつけて呼び出す
10 var adam = new Person("Adam");
11 console.log(adam.say()); //"I am Adam"
12
13 // new をつけずに呼び出す
14 var eve = Person("Eve");
15 console.log(eve); //undefined!
オブジェクト
this
name : Adam
say : {...}
adam
クラスっぽいものと
コンストラクタ関数
1 // クラスっぽいものを作るコンストラクタ
2 var Person = function (name) {
3 this.name = name;
4 this.say = function () {
5 return "I am " + this.name;
6 };
7 };
8
9 // new をつけて呼び出す
10 var adam = new Person("Adam");
11 console.log(adam.say()); //"I am Adam"
12
13 // new をつけずに呼び出す
14 var eve = Person("Eve");
15 console.log(eve); //undefined!
オブジェクト
this
name : Adam
say : {...}
adam
関数のnew呼び出し
明示的な指定呼び出し
メソッド呼び出し
それ以外(グローバル)
第一の鬼門、
this
明示的な指定呼び出し
1 var prop = "gProp";
2 var obj = {prop : "rProp"};
3
4 var func = function (str) {
5 console.log(this.prop + "::" + str);
6 };
7
8 func("normal"); // gProp::normal
9 func.call(obj, "call"); // rProp::call
10 func.apply(obj, ["apply"]); // rProp::apply
メソッド呼び出し
1 var prop = "gProp";
2 var obj = {
3 prop : "rProp",
4 func : function (str) {
5 console.log(this.prop + "::" + str);
6 }
7 };
8
9 obj.func("dot"); // rProp::dot
10 obj['func']("bracket"); // rProp::bracket
11
12 var func2 = obj.func;
13 func2("func2"); // gProp::func2
第二の鬼門、
暗黙の型変換
1 '100' - 1; // 99
2 '100' - '1'; // 99
3 '100' + 1; // “1001”
4 1 + '100'; // “1100”
5 typeof +'100'; // “number”
6
7 // null,undefined,0,-0,NaN,"" はfalse扱い
8 var b = new Boolean(false);
9 if (b) {/* 実行される */}
10
11 var n = new Number(0);
12 if (n) {/* 実行される */}
第二の鬼門、
暗黙の型変換
1 function Person (name, age) {
2 this.name = name || "Guest";
3 this.age = age || 20;
4 }
5
6 // {name:"Guest", age:20}
7 var p1 = new Person();
8
9 // {name:"Baby", age:20} になってしまう
10 var p2 = new Person("Baby", 0);
1 "Str" == "Str"; // true. ★型が同じ場合
2 null == undefined; // true.
3 10 == "1e+1"; // true. ★数値と文字列
4 true == 1; // true. ★Booleanと数値。数値で比較される!
5 true == 10; // false.
6 false == 0; // true.
7 true == "0x01"; // true. ★Booleanと文字列。数値比較
8 false == "0e+0"; // true.
9 100 == {}; // false. ★数値とオブジェクト。数値比較
10 123 == { // true.
valueOf:function(){return 123}};
11 "Str" == {}; // false. ★文字列とオブジェクト
12 "Str" == { // true
toString:function(){return "Str"}};
13 {} == true; // false. ★その他 if ({}) {実行される}
14 {} == false; // false.
同値演算子 == と ===
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
問題2:
c1は、
prototypeというプロパティを持つ。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
第三の鬼門、
プロトタイプチェーン
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
というコードがあるとき、
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
問題2:
c1は、
prototypeというプロパティを持つ。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
第三の鬼門、
プロトタイプチェーン
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
というコードがあるとき、
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
問題2:
c1は、
prototypeというプロパティを持つ。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
第三の鬼門、
プロトタイプチェーン
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
というコードがあるとき、
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
問題2:
c1は、
prototypeというプロパティを持つ。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
第三の鬼門、
プロトタイプチェーン
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
というコードがあるとき、
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
問題2:
c1は、
prototypeというプロパティを持つ。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
第三の鬼門、
プロトタイプチェーン
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
というコードがあるとき、
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
問題2:
c1は、
prototypeというプロパティを持つ。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
第三の鬼門、
プロトタイプチェーン
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
というコードがあるとき、
Function
Child
prototype:
Object
無名
constructor:
Object
c1
name: Cain
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
3 c1.constructor === Child; // true
Function
Child
prototype:
Object
無名
constructor:
Object
c1
name: Cain
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
3 c1.constructor === Child; // true
Function
Child
prototype:
Object
無名
constructor:
Object
c1
name: Cain
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
3 c1.constructor === Child; // true
Function
Child
prototype:
Object
無名
constructor:
Object
c1
name: Cain
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
3 c1.constructor === Child; // true
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
1 var Child = function (name) {this.name = name;};
2 var Parent = function (name) {this.name = name;};
3 Child.prototype = new Parent("Adam");
4
5 var c1 = new Child("Cain");
6 Parent.prototype.getName = function () {return this.name;};
7 c1.getName(); // “Cain”.
Child
Child
proto
Parent
Parent
proto
AdamCain
メソッド
getName
Object
Object
proto
toString
valueOf
etc...
メソッドはprototypeに
1 // クラスっぽいものを作るコンストラクタ(修正前)
2 var Person = function (name) {
3 this.name = name;
4 this.say = function () {
5 return "I am " + this.name;
6 };
7 };
8
9 // 修正後
10 var Person2 = function (name) {
11 this.name = name;
12 };
13
14 Person2.prototype.say = function () {
15 return "I am " + this.name;
16 };
暗黙じゃない環境もある
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
3
4 c1.__proto__ === Child.prototype; // 環境依存でtrue
Function
Child
prototype:
Object
無名
constructor:
Object
c1
name: Cain
Object
c1
__proto__:
name: Cain
暗黙じゃない環境もある
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
3
4 c1.__proto__ === Child.prototype; // 環境依存でtrue
Function
Child
prototype:
Object
無名
constructor:
Object
c1
name: Cain
Object
c1
__proto__:
name: Cain
Child
AdamCain
Parent
Parent
proto
あくまでオブジェクトの
チェーンである
EveAbel
Seth
Child
AdamCain
Parent
Parent
proto
あくまでオブジェクトの
チェーンである
EveAbel
Seth
Child
AdamCain
Parent
Parent
proto
あくまでオブジェクトの
チェーンである
EveAbel
Seth
Child
AdamCain
Parent
Parent
proto
あくまでオブジェクトの
チェーンである
EveAbel
Seth
Child
AdamCain
Parent
Parent
proto
あくまでオブジェクトの
チェーンである
EveAbel
Seth
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
×
Child
prototype
無名
constructor
c1
__proto__
1 var Child = function (name) {this.name = name;};
2 var c1 = new Child("Cain");
問題1:
c1のプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
○
問題2:
c1はprototype
というプロパティをもつか。
○か×か?
問題3:
Child.prototypeと
c1.__proto__は
同じオブジェクトを参照する。
○か×か?
(ただし環境に依る)
無名
constructor
Function
prototype
call()
apply()
etc...
問題4:
Childのプロトタイプオブジェクトは
Child.prototypeが
参照するオブジェクトである。
○か×か?
継承は手段のひとつ
コードの再利用こそが目的
継承にはいくつも方法がある
Object.create();
委譲、ミックスイン
最後の鬼門、
スコープチェーン
1 var temp1 = "grobal1";
2 var temp2 = "grobal2"
3 console.log(temp1); // "grobal1"
4 console.log(temp2); // "grobal2"
5
6 func();
7 function func () {
8 console.log(temp2); // "grobal2"
9 var temp1 = "local";
10 console.log(temp1); // "local"
11
12 if (true) {
13 console.log(temp1); // "local"
14 var temp1 = "if";
15 console.log(temp1); // "if"
16 }
17 console.log(temp1); // "if"
18 }
19
20 console.log(temp1); // "grobal1"
1 var temp1 = "grobal1";
2 var temp2 = "grobal2"
3 console.log(temp1); // "grobal1"
4 console.log(temp2); // "grobal2"
5
6 func();
7 function func () {
8 console.log(temp1); // undefined
9 console.log(temp2); // "grobal2"
10 var temp1 = "local";
11 console.log(temp1); // "local"
12 }
13
14 console.log(temp1); // "grobal1"
15 console.log(temp2); // "grobal2"
変数の巻き上げ
1 var func1 = function () {
2 console.log(arg); // undefined
3 var arg = "local";
4 };
5
6 var func2 = function () {
7 var arg = undefined;
8 console.log(arg); // undefined
9 arg = "local";
10 };
変数の巻き上げ
1 func("one"); // "one"
2 func(); // undefined
3 func("one", "two", "three"); // "one"
4
5 function func (arg1) {
6 console.log(arg1);
7 }
もう少し詳しい理解
1 func("one"); // "one"
2 func(); // undefined
3 func("one", "two", "three"); // "one two three"
4
5 function func (arg1) {
6 console.log(arg1);
7
8 for (i = 1; i < arguments.length; i++) {
9 console.log(arguments[i]);
10 }
11 }
もう少し詳しい理解
globalオブジェクト
f : function{...}
x : xxx1 var x = "xxx";
2 f(100, 200, 300);
3
4 function f(a1) {
5 var y = "yyy";
6 g(200);
7
8 function g(a1) {
9 console.log(z); // undefined
10 console.log(y); // "yyy"
11 console.log(x); // "xxx"
12 var z = "zzz";
13 }
14 }
Callオブジェクト
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : undefined
g : function{...}
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : yyy
g : function{...}
gのCallオブジェクト
arguments : [...]
a1 : arguments[0]
z : undefined
globalオブジェクト
f : function{...}
x : xxx1 var x = "xxx";
2 f(100, 200, 300);
3
4 function f(a1) {
5 var y = "yyy";
6 g(200);
7
8 function g(a1) {
9 console.log(z); // undefined
10 console.log(y); // "yyy"
11 console.log(x); // "xxx"
12 var z = "zzz";
13 }
14 }
Callオブジェクト
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : undefined
g : function{...}
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : yyy
g : function{...}
gのCallオブジェクト
arguments : [...]
a1 : arguments[0]
z : undefined
globalオブジェクト
f : function{...}
x : xxx1 var x = "xxx";
2 f(100, 200, 300);
3
4 function f(a1) {
5 var y = "yyy";
6 g(200);
7
8 function g(a1) {
9 console.log(z); // undefined
10 console.log(y); // "yyy"
11 console.log(x); // "xxx"
12 var z = "zzz";
13 }
14 }
Callオブジェクト
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : undefined
g : function{...}
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : yyy
g : function{...}
gのCallオブジェクト
arguments : [...]
a1 : arguments[0]
z : undefined
globalオブジェクト
f : function{...}
x : xxx1 var x = "xxx";
2 f(100, 200, 300);
3
4 function f(a1) {
5 var y = "yyy";
6 g(200);
7
8 function g(a1) {
9 console.log(z); // undefined
10 console.log(y); // "yyy"
11 console.log(x); // "xxx"
12 var z = "zzz";
13 }
14 }
Callオブジェクト
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : undefined
g : function{...}
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : yyy
g : function{...}
gのCallオブジェクト
arguments : [...]
a1 : arguments[0]
z : undefined
globalオブジェクト
f : function{...}
x : xxx1 var x = "xxx";
2 f(100, 200, 300);
3
4 function f(a1) {
5 var y = "yyy";
6 g(200);
7
8 function g(a1) {
9 console.log(z); // undefined
10 console.log(y); // "yyy"
11 console.log(x); // "xxx"
12 var z = "zzz";
13 }
14 }
Callオブジェクト
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : undefined
g : function{...}
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : yyy
g : function{...}
gのCallオブジェクト
arguments : [...]
a1 : arguments[0]
z : undefined
globalオブジェクト
f : function{...}
x : xxx1 var x = "xxx";
2 f(100, 200, 300);
3
4 function f(a1) {
5 var y = "yyy";
6 g(200);
7
8 function g(a1) {
9 console.log(z); // undefined
10 console.log(y); // "yyy"
11 console.log(x); // "xxx"
12 var z = "zzz";
13 }
14 }
Callオブジェクト
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : undefined
g : function{...}
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : yyy
g : function{...}
gのCallオブジェクト
arguments : [...]
a1 : arguments[0]
z : undefined
globalオブジェクト
f : function{...}
x : xxx1 var x = "xxx";
2 f(100, 200, 300);
3
4 function f(a1) {
5 var y = "yyy";
6 g(200);
7
8 function g(a1) {
9 console.log(z); // undefined
10 console.log(y); // "yyy"
11 console.log(x); // "xxx"
12 var z = "zzz";
13 }
14 }
Callオブジェクト
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : undefined
g : function{...}
fのCallオブジェクト
arguments : [...]
a1 : arguments[0]
y : yyy
g : function{...}
gのCallオブジェクト
arguments : [...]
a1 : arguments[0]
z : undefined
レキシカル(字句的)スコープ
1 var x = 100;
2 var y = 200;
3
4 f();
5
6 function f () {
7 var y = 20;
8 g();
9 }
10
11 function g () {
12 var z = 3;
13 console.log(x); // 100
14 console.log(y); // ???
15 console.log(z); // 3
16 }
globalオブジェクト
プロパティは省略
fのCallオブジェクト
プロパティは省略
gのCallオブジェクト
プロパティは省略
関数fの
スコープチェーン↓
関数gの
スコープチェーン↓
レキシカル(字句的)スコープ
1 var x = 100;
2 var y = 200;
3
4 f();
5
6 function f () {
7 var y = 20;
8 g();
9 }
10
11 function g () {
12 var z = 3;
13 console.log(x); // 100
14 console.log(y); // ???
15 console.log(z); // 3
16 }
globalオブジェクト
プロパティは省略
fのCallオブジェクト
プロパティは省略
gのCallオブジェクト
プロパティは省略
関数fの
スコープチェーン↓
関数gの
スコープチェーン↓
レキシカル(字句的)スコープ
1 var x = 100;
2 var y = 200;
3
4 f();
5
6 function f () {
7 var y = 20;
8 g();
9 }
10
11 function g () {
12 var z = 3;
13 console.log(x); // 100
14 console.log(y); // ???
15 console.log(z); // 3
16 }
globalオブジェクト
プロパティは省略
fのCallオブジェクト
プロパティは省略
gのCallオブジェクト
プロパティは省略
関数fの
スコープチェーン↓
関数gの
スコープチェーン↓
レキシカル(字句的)スコープ
1 var x = 100;
2 var y = 200;
3
4 f();
5
6 function f () {
7 var y = 20;
8 g();
9 }
10
11 function g () {
12 var z = 3;
13 console.log(x); // 100
14 console.log(y); // ???
15 console.log(z); // 3
16 }
globalオブジェクト
プロパティは省略
fのCallオブジェクト
プロパティは省略
gのCallオブジェクト
プロパティは省略
関数fの
スコープチェーン↓
関数gの
スコープチェーン↓
スコープチェーンまとめ
スコープは2種類存在する
→ letってのもあるけど割愛
変数の巻き上げに注意する
関数呼び出しで
Callオブジェクトが生成される
関数のスコープチェーンは
関数の定義位置で決まる
ちょっとだけ
イディオム編
JSには以下の機能を
実装するための構文がない
名前空間
モジュール、パッケージ
アクセス修飾子(private)
即時関数パターン
1 (function () {
2
3 var days = ['日','月','火','水','木','金','土'];
4 var day = new Date();
5 console.log(days[day.getDay()] + ',' + day.getDate());
6
7 })(); // "土,27"
1 var func = function () { // 関数の宣言
2 /* 関数の中身 */
3 };
4
5 func(); // 関数の実行
クロージャ
クロージャ(クロージャー、closure、閉包)はプログ
ラミング言語における関数オブジェクトの一種。いくつ
かの言語ではラムダ式 (Lambda Expression) や無名関
数 (Anonymous function) で実現している。引数以外
の変数を実行時の環境ではなく、自身が定義された環境
(静的スコープ)において解決することを特徴とする。
関数とそれを評価する環境のペアであるともいえる。
クロージャ
クロージャ(クロージャー、closure、閉包)はプログ
ラミング言語における関数オブジェクトの一種。いくつ
かの言語ではラムダ式 (Lambda Expression) や無名関
数 (Anonymous function) で実現している。引数以外
の変数を実行時の環境ではなく、自身が定義された環境
(静的スコープ)において解決することを特徴とする。
関数とそれを評価する環境のペアであるともいえる。
1 var makeFunc = function (base) {
2 var step = 10;
3 var count = 0;
4
5 return function (arg) {
6 var result
7 = base + step * count + arg;
8 count++;
9 return result;
10 }
11 }
12
13 var c1 = makeFunc(500);
14 console.log(c1(3)); // 503
15 console.log(c1(6)); // 516
16 console.log(c1(9)); // 529
globalオブジェクト
プロパティは省略
makeFuncのCO
base : 500
step : 10
count : 0
c1のCO
まだ生成されてない!
c1のCO 一回目
arg : 3
makeFuncのCO
base : 500
step : 10
count : 1
c1のCO 二回目
arg : 6
1 var makeFunc = function (base) {
2 var step = 10;
3 var count = 0;
4
5 return function (arg) {
6 var result
7 = base + step * count + arg;
8 count++;
9 return result;
10 }
11 }
12
13 var c1 = makeFunc(500);
14 console.log(c1(3)); // 503
15 console.log(c1(6)); // 516
16 console.log(c1(9)); // 529
globalオブジェクト
プロパティは省略
makeFuncのCO
base : 500
step : 10
count : 0
c1のCO
まだ生成されてない!
c1のCO 一回目
arg : 3
makeFuncのCO
base : 500
step : 10
count : 1
c1のCO 二回目
arg : 6
1 var makeFunc = function (base) {
2 var step = 10;
3 var count = 0;
4
5 return function (arg) {
6 var result
7 = base + step * count + arg;
8 count++;
9 return result;
10 }
11 }
12
13 var c1 = makeFunc(500);
14 console.log(c1(3)); // 503
15 console.log(c1(6)); // 516
16 console.log(c1(9)); // 529
globalオブジェクト
プロパティは省略
makeFuncのCO
base : 500
step : 10
count : 0
c1のCO
まだ生成されてない!
c1のCO 一回目
arg : 3
makeFuncのCO
base : 500
step : 10
count : 1
c1のCO 二回目
arg : 6
1 var makeFunc = function (base) {
2 var step = 10;
3 var count = 0;
4
5 return function (arg) {
6 var result
7 = base + step * count + arg;
8 count++;
9 return result;
10 }
11 }
12
13 var c1 = makeFunc(500);
14 console.log(c1(3)); // 503
15 console.log(c1(6)); // 516
16 console.log(c1(9)); // 529
globalオブジェクト
プロパティは省略
makeFuncのCO
base : 500
step : 10
count : 0
c1のCO
まだ生成されてない!
c1のCO 一回目
arg : 3
makeFuncのCO
base : 500
step : 10
count : 1
c1のCO 二回目
arg : 6
1 var makeFunc = function (base) {
2 var step = 10;
3 var count = 0;
4
5 return function (arg) {
6 var result
7 = base + step * count + arg;
8 count++;
9 return result;
10 }
11 }
12
13 var c1 = makeFunc(500);
14 console.log(c1(3)); // 503
15 console.log(c1(6)); // 516
16 console.log(c1(9)); // 529
globalオブジェクト
プロパティは省略
makeFuncのCO
base : 500
step : 10
count : 0
c1のCO
まだ生成されてない!
c1のCO 一回目
arg : 3
makeFuncのCO
base : 500
step : 10
count : 1
c1のCO 二回目
arg : 6
1 var makeFunc = function (base) {
2 var step = 10;
3 var count = 0;
4
5 return function (arg) {
6 var result
7 = base + step * count + arg;
8 count++;
9 return result;
10 }
11 }
12
13 var c1 = makeFunc(500);
14 console.log(c1(3)); // 503
15 console.log(c1(6)); // 516
16 console.log(c1(9)); // 529
globalオブジェクト
プロパティは省略
makeFuncのCO
base : 500
step : 10
count : 0
c1のCO
まだ生成されてない!
c1のCO 一回目
arg : 3
makeFuncのCO
base : 500
step : 10
count : 1
c1のCO 二回目
arg : 6
privateの実現
1 function Animal(arg) {
2 // 以下、プライベート
3 var name = arg;
4
5 // 以下、パブリック
6 this.getName = function () {
7 return name;
8 };
9 }
10
11 var dog = new Animal("dog");
12
13 console.log(dog.name); // undefined
14 console.log(dog.getName()); // "dog"
Callオブジェクトが分かれば
大体のイディオムは分かる
即時関数パターン
→ 一時的な変数をCallオブジェクトに閉じ込める
クロージャ
→ 関数定義時の環境(状態)をSCに閉じ込める
privateメンバ
→ 隠蔽したい変数をCallオブジェクトに閉じ込める
名前空間、モジュール等は
以下の書籍で
おまけ
その他、良さげな理由
静的型付け + 型推論
ECMAScript6準拠
IDEとの連携
開発が活発
というわけで、
TypeScriptやろうぜ!
ご清聴ありがとうございました

JavaScriptの落とし穴