ECMAScript 5 時代のオブジェクト・プロトタイプ継承入門
Click here to load reader
-
Upload
yu-nobuoka -
Category
Documents
-
view
4.428 -
download
3
Transcript of ECMAScript 5 時代のオブジェクト・プロトタイプ継承入門
ECMAScript 5 時代のオブジェクト・プロトタイプ継承入門
id:nobuoka(@nobuoka)
2012-11-29 Kyoto.js #2
自己紹介と概要
● id:nobuoka - はてなブックマークチーム
● Java, JavaScript, Ruby あたりの言語が好き
● 仕事では Perl と JavaScript
● 今日は初心者向けの話
– オブジェクト?
– プロトタイプ継承?● ECMA-262 5.1th ベース
ECMAScript とは?
● JavaScript の言語コア部分に相当する言語
● ECMA International による仕様 : ECMA-262
● 最新のバージョンは 5.1
– ECMAScript Language Specification (5.1th)
– 古い IE では 5.1 の機能が使えなかったりする
– プロトタイプ継承などを 5.1 的に説明してみる(本資料中の節番号は ECMA-262 5.1th の節)
JavaScript におけるオブジェクト
● 値の一種 : Object 型の値
● Object 型の他には String 型とか Number 型とか
● JavaScript には C++ や Smalltalk のようなクラスはない
● オブジェクトリテラルによってやコンストラクタによってなど、様々な方法で生成される
var obj1 = { name : “Hanako”, age : 18};
var obj2 = new Object();
var obj1 = { name : “Hanako”, age : 18};
var obj2 = new Object();
オブジェクトはプロパティの集合体
● “An Object is a collection of properties.” (8.6 節)
● プロパティ : 名前と値の結合物 (association)
– Named data property : プロパティといえばこれ
– Named accessor property
– Internal property : 仕様説明のための内部的なもの
var obj1 = { name : “Hanako”, age : 18};
名前は age, 値は数値18 であるプロパティ
オブジェクトの同値性 (概念上の話)
● もっているプロパティの名前が全て同じで、名前に対応する値も同じ、という 2 つのオブジェクトがあっても、それらのオブジェクトは同じ値ではない
● JavaScript ではオブジェクトそのものが値だから (同じオブジェクトでなければ同じ値ではない)
// 2 つのオブジェクトは同じ値ではない{ p: “y” } !== { p: “y” }
当たり前といえば当たり前。C から来た人などは戸惑うかも。
オブジェクトの同値性 (概念上の話)
● 引数として渡されたオブジェクトに対する操作は、もとのオブジェクトに影響する (同じ値なので当然)
// 引数として渡されたオブジェクトの val プロパティの// 値をインクリメントする関数function incVal(o) { o.val += 1 }
var obj = { val: 10 };incVal(obj); // incVal 呼び出し後の obj.val の値は 11
『JavaScript 第 5 版』 では 「参照によるデータ操作」 などと説明されている。 実践的にはそれでいいが、仕様を読むにはここで説明したこと (オブジェクトそのものが値) の理解が必要。
Accessor property
● いわゆる setter / getter
● 最近のブラウザなら (IE10 含め) 基本的に使える
var obj = { _val: 0, get val() { return this._val }, set val(v) { this._val = v }};
obj.val = obj.val + 10;
Property Attributes (8.6.1 節)
● プロパティの属性
– [[Value]] : データプロパティの値
– [[Writable]] : 書き換えできるか
– [[Set]], [[Get]] : setter / getter
– [[Configurable]] : 変更できるかどうか
– [[Enumerable]] : for-in ループで列挙されるかどうか● Object.getOwnPropertyDescriptor (15.2.3.3 節)
Object.defineProperty (15.2.3.6 節)
● Property Attributes を指定してプロパティを定義
● Object.defineProperties もあるよ (15.2.3.7 節)
var obj = {};Object.defineProperty(obj, “newProp”, { value: 200, writable: false});obj.newProp = 10; // writable : false なので書きこまれない
Object.defineProperties(obj, { newProp2: { get: function () { return 200 } }}); 他には __defineGetter__, __defineSetter__ とか
いよいよプロトタイプ継承の話
● ECMA-262 5.1th には以下の画像がある
● よくわからん
プロトタイプ継承
● プロパティの探索を、継承先も (さらにその先祖も) 含めて行う
– クラスベースの言語でのクラスの継承でメソッドの探索を継承先クラスまで含めるのと同じ
● Internal property : [[Prototype]]
– 継承先のオブジェクト obj1- prop1- prop2
obj2- [[Prototype]]- prop3
// 右図の継承構造があるならobj1.prop1 = 100;console.log( obj2.prop1 ); // 100obj1.prop1 = 200;console.log( obj2.prop1 ); // 200
Object.create メソッド
● 指定したオブジェクトを継承した新しいオブジェクトを生成
// 右図の継承構造をつくるvar obj1 = { prop1: 100, prop2: 200};
// obj2 は obj1 を継承var obj2 = Object.create(obj1, { prop3: { value: 300 }});
obj1- prop1- prop2
obj2- [[Prototype]]- prop3
Object.getPrototypeOf メソッド
● 指定したオブジェクトのプロトタイプ継承先を取得
// 右図の継承構造をつくるvar obj1 = { /* … */ };var obj2 = Object.create(obj1, { prop3: { value: 300 }});
// プロトタイプ取得Object.getPrototypeOf(obj2) === obj1; // true
obj1- prop1- prop2
obj2- [[Prototype]]- prop3
ブラウザの JavaScript 処理系だと大体 __proto__ ってプロパティがある
コンストラクタによるオブジェクト生成
● “constructor : function object that creates and initialises objects” (4.3.4 節)
● new 演算子
function Cons() { this.prop = 200;}var obj = new Cons();
console.log( obj.prop ); // 200
コンストラクタの prototype プロパティ
● “When a constructor creates an object, that object implicitly references the constructor’s “prototype” property for the purpose of resolving property references.” (4.3.5 節)
– コンストラクタの prototype プロパティの値が新たなオブジェクトの [[Prototype]] に設定される
Cons- prototype
obj2- [[Prototype]]- prop3
Cons.prototype- prop1- prop2
おわり