AngularJSでよく見かける書き方
var myModule = angular.module('myModule', []);
とか、
myModule.factory('greeter', function($window) {
return {
greet: function(text) {
$window.alert(text);
}
};
});
というようにAngularJSでは独特の書き方をします。
このような書き方はDependency Injection(DI)という書き方だそうです。
AngularJSでのDIに関するドキュメント
https://docs.angularjs.org/guide/di
AngularJSでのDI部分のコード
https://github.com/angular/angular.js/blob/master/src/auto/injector.js
DIについて
AngularJSリファレンスという本でもDIについて解説がされています(DIとは、P.129)。
DI(Dependency Injection)とは、あるコンポーネントから別のコンポーネントを利用する際に直接コンポーネントを呼び出すコードを記述するのではなく、設定ファイルやアノテーション機能を使ってコンポーネント間の依存関係を記述し、実行時に依存関係を解決するというデザインパターンです。
DIについて色々と詳しく書かれているので、興味がある人は是非読むのをオススメします。
普通書くときにコンポーネントを直接呼び出すのに慣れています。
1 - 依存関係を記述し、 2 - 実行時に依存関係を記述するという2段感あると一気に複雑に思えます。
簡易版AngularJSでDenpendency Injectionを体験する
AngularJS式Injectionを解説しているブログがありましたので、実際試し、メモしました。
var WelcomeController = function (Greeter) {
/** I want a different Greeter injected dynamically. **/
Greeter.greet();
};
AngularJSでは引数の名前がdependencyの名前であります。
引数の名前は重要で、実際のdependencyとdepencyの名前が関連付けられます。
WelocomControlleが動くようにDIを作ってみます。
DIの機能として、1 - 依存関係を記述するメソッドと 2 - 依存関係を実行するメソッドが必要となります。
1 - 依存関係を記述するメソッド
var Injector = {
depnedencies : {},
register : function(name, dependency){
this.depnedencies[name] = dependency;
}
}
var RobotGreeter = {
greet: function() {
return 'Domo Arigato';
}
};
Injector.register('Greeter', RobotGreeter);
RobertGreeterというオブジェクトを'greeter'として依存関係を登録する。
2 - 依存関係を実行するメソッド
var Injector = {
depnedencies : {},
register : function(name, dependency){
this.depnedencies[name] = dependency;
},
process : function(target){
}
}
Injector.register('Greeter', RobotGreeter);
Injector.process(WelcomeController);
WelcomeControllerを実行します。
どのように実行するか、、、という問題が出てきます。
var Injector = {
dependencies: {},
process: function(target) {
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var text = target.toString();
var args = text.match(FN_ARGS)[1].split(',');
target.apply(target, this.getDependencies(args));
},
getDependencies: function(arr) {
var self = this;
return arr.map(function(value) {
return self.dependencies[value];
});
},
register: function(name, dependency) {
this.dependencies[name] = dependency;
}
};
processでは、正規表現をつかって関数の引数を取ります。
applyで関数に引数を代入します。
サンプルはこんな感じでした。
DIを利用してCanvasを描画する。
// DI
var Injector = {
dependencies: {},
process: function(target) {
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var text = target.toString();
var args = text.match(FN_ARGS)[1].split(',');
var a = this.getDependencies(args);
console.log(target);
console.log("-----\n");
console.log(a);
target.apply(this, a);
},
getDependencies: function(arr) {
var self = this;
return arr.map(function(value) {
return self.dependencies[value];
});
},
register: function(name, dependency) {
this.dependencies[name] = dependency;
}
};
// ============================
// Canvasアプリ
// ============================
var CanvasApp = {
width : null,
height : null,
canvas : null,
ctx : null,
setup : function(){
this.width = window.innerWidth;
this.height = window.innerHeight;
this.canvas = document.getElementById('c');
this.canvas.width = this.width;
this.canvas.height = this.height;
this.ctx = this.canvas.getContext('2d');
},
draw : function(){
this.ctx.fillStyle = '#ff0000';
this.ctx.fillRect(100, 100, 100, 100);
}
};
// ============================
// コントローラ
// ============================
var CanvasAppController = function (paintApp) {
paintApp.setup();
paintApp.draw();
};
// 1.dependencyをに'paintApp'としてCanvasAppを登録
Injector.register('paintApp', CanvasApp);
// 2.実行する
Injector.process(CanvasAppController);
結果は下のリンクから見ることができます。
http://codepen.io/kenjiSpecial/pen/GBpnE
DIを知ったつもりになりましたー
AngularJS色々と学ぶことが多いです。。