ウズラ本 第5章「オブジェクト作成のパターン」 復習編


勉強の進捗により、随時更新。

◆名前空間
名前空間とは、JavaScriptで書くと次の例のようなもので、Javaでいうところのpackageか。
ライブラリを組むとなったら必須の知識だ。(そして僕はライブラリを組むのが夢だ。)

var MYAPP = MYAPP || {};
MYAPP.jp = MYAPP.jp || {};
MYAPP.jp.exblog = MYAPP.jp.exblog || {};
MYAPP.jp.exblog.redchant = MYAPP.jp.exblog.redchant || {};


見てのとおり冗長だが、汎用の名前空間作成関数の例がある。
上記と同じことをする。

var MYAPP = MYAPP || {};

MYAPP.namespace = function(ns_string) {
var parts = ns_string.split("."),
parent = MYAPP,
i;

if (parts[0] === "MYAPP") {
parts = parts.slice(1);
}

for (i = 0; i < parts.length; i++) {
if (typeof parent[parts[i]] === "undefined") {
parent[parts[i]] = {};
}
parent = parent[parts[i]];
}

return parent;
};

var module = MYAPP.namespace("jp.exblog.redchant");
console.log(module === MYAPP.jp.exblog.redchant); // true


とってもスマートだ。


◆プライベートなプロパティとメソッド
Javaではprivateやらpublicやらでデータを公開するしないを決められる。
JavaScriptでこれを実現するとなると少し手間がかかる。(それも慣れの問題かと思われる)
その手間っていうのはクロージャで実現するということからだ。
次の例はJavaScriptの単純な例、すべてパブリックだ。

var Data = function(name) {
this.name = name;
this.getName = function() {
return this.name;
};
};

var redchant = new Data("redchant");
console.log(redchant.name); // redchant
console.log(redchant.getName()); // redchant


nameプロパティをプライベートにしたい。

var Data = function(name) {
this.getName = function() {
return name;
};
};

var redchant = new Data("redchant");
console.log(redchant.name); // undefined
console.log(redchant.getName()); // redchant


nameプロパティが非公開になりました。
getNameメソッドのようにプライベートなメンバにアクセスできるメソッドを、この本では特権メソッドと呼んでいる。

・プライバシーの侵犯
次の場合、オブジェクトを返す、つまり参照を返すのでプライベートにならない。
JavaScriptでは、数値、真偽値、文字列の3つのプリミティブは値渡し、
オブジェクト(もちろん関数含む)は参照渡しだ。

function Gadget() {
var specs = {
x: 100,
y: 200
};

this.getSpecs = function() {
return specs;
}
}

var g = new Gadget(),
specs = g.getSpecs();

// gの内部を変えるつもりじゃなかったのに!
specs.x = 300;
specs.y = 400;

// 変わってしまった!
console.dir(g.getSpecs()); // x = 300, y = 400


この解決には、オブジェクトの複製を行うことでできるらしい。次の章でやるらしい。

・プロトタイプ
サイ本で散々勉強したのでprototypeについては大丈夫なんだけど、一応。
上の例でGadgetのインスタンスを10000個作成した場合、
(specsオブジェクトは個々のデータなのでともかく、)
getSpecsメソッドもメモリに10000個ロードしてしまう。
これはあまりに非効率であるのでprototypeに作成するべき。

function Gadget() {
var specs = {
x: 100,
y: 200
};
}
Gadget.prototype.getSpec = function() {
return this.spec;
};


詳しくは「サイ本」、もしくは「Java開発者のための Ajax実践開発入門」が良い。


◆モジュールパターン
名前空間オブジェクトを作ってその中にメソッドを格納する、ということでよいのかな?

var MYAPP = MYAPP || {};
MYAPP.util = MYAPP.util || {};
MYAPP.util.array = MYAPP.util.array || {};

MYAPP.util.array = (function() {

// 1回だけ行ういろんな初期化処理
// ・・・

var inArray = function() {
console.log("inArray was called");
};
var isArray = function() {
console.log("isArray was called");
};

return {
inArray: inArray,
isArray: isArray
};
}());

MYAPP.util.array.inArray(); // inArray was called
MYAPP.util.array.isArray(); // isArray was called




◆サンドボックスパターン
やっぱり難しい。ここまでするか、と思った。
まあ、グローバル空間を汚さないための1つの例として受け止めました。


◆静的メンバ
・プライベートな静的メンバ
パブリックな静的メンバには興味は湧かず。
プライベートな静的メンバとは、クロージャで実現する。
この本によると定義は次のようになる。
●同じコンストラクタ関数で作成されたすべてのオブジェクトで共有される。
●コンストラクタの外部からはアクセス出来ない。

var Gadget = (function() {

// counterが静的変数
var counter = 0,
NewGadget;

NewGadget = function() {
counter += 1;
};

NewGadget.prototype.getLastId = function() {
return counter;
};

return NewGadget;

}());

var iphone = new Gadget();
console.log(iphone.getLastId()); // 1

var ipod = new Gadget();
console.log(ipod.getLastId()); // 2

var ipad = new Gadget();
console.log(ipad.getLastId()); // 3


難しいなあ、クロージャ。
つまりは、関数ローカルスコープでデータを管理することと理解しているが。


◆オブジェクト定数
「オブジェクト定数」というより、「定数オブジェクト」だと思う。

var constant = (function(

var constants = {},
ownProp = Object.prototype.hasOwnProperty,
allowed = {
string: 1,
number: 1,
boolean: 1
};

return {
// 定数定義、セット関数
set: function(name, value) {
if (this.isDefined(name)) {
return false;
}
if (!ownProp.call(allowed, typeof value)) {
return false;
}
constants[name] = value;
},
// 定数が定義されているか関数
isDefined: function(name) {
ownProp.call(constants, name);
},
// 定数ゲット関数
get: function(name) {
if (this.isDefined(name)) {
return constants[name];
}
return null;
};
};

) {}());

constant.isDefined("max_width"); // false

constant.set("max_width", 480); // false

constant.isDefined("max_width"); // true

constant.get("max_width"); // 480


callについては要復習だ。
でも、なんでわざわざcallを使うのかなあ。

[疑問]
コンストラクタ関数がなんなのか、よくわからなくなった。。。

おお、第3章がまさにそういう内容だったような。復習だあ。

次の例がほぼ同義。

// オブジェクトリテラル
var o1 = {
name: "redchant",
getName: function() { return this.name; }
};

console.log(o1.getName()) // redchant

// コンストラクタ
function Func() {
this.name = "redchant";
this.getName = function() { return this.name; };
}
var o2 = new Func();

console.log(o2.getName()) // redchant




(了)
[PR]
by redchant | 2011-03-01 22:17 | Computer
<< 2011年03月02日のつぶや... 2011年03月01日のつぶや... >>