JavaScriptにはこのようなフレームワークはそれほど多くありません。関数を展開するときに見つけたものは、通常のイベントサブスクリプションのようでした。 一般的に、構文はあまり好きではありませんでした。シンプルで、.NETとJavaの「重要事項」に近いものを望んでいました。
典型的なタスクを設定します。 ロジックを追加する必要があります:
•機能を実行する前
•機能を実行した後
•例外の場合
.NET属性は私に近いですし、そのような構文の実装はそれ自体を示唆しているので、C#の小さな例から進みます。
[AttributeName(Params)] [AttributeName(Params), AttributeName(Params)] public void Foo() { … }
JavaScriptで有効になるようにコードを少し変更します
AOP( [AttributeName(Params)], [AttributeName(Params) , AttributeName(Params)], function Foo() { … } );
原則として、複雑なものは何も記述していません。すべてが非常に実行可能です。 AOP機能を実装し、ロジックの拡張を有能に整理することが残っています。
function AOP() { var advices = []; // for (var i = 0; i < arguments.length; i++) { var arg = arguments[i]; // , , // if (Object.prototype.toString.call( arg ) === "[object Array]") { for (var j = 0, advice = arg[j]; j < arg.length; j++) { advices.push(advice); } } else { if (typeof arg === "function") { name = getFunctionName(arg); // // .. for (var j = 0; j < advices.length; j++) { var advice = advices[j]; arg = advice.apply(arg); } // , // , // . . // FunctionName window[name] = arg; } // advices.length = 0; } } } function getFunctionName(fn) { var source = fn.toString(); var head = source.split("(")[0]; var fnName = head.split(" ")[1]; return fnName; }
機能の拡張を整理します
function Advice(implementation) { this.implementation = implementation; } // fn - Advice.prototype.apply = function(fn) { if (typeof fn !== "function") { throw "You can apply an advice only to a function"; } // return this.implementation(fn); }
そして、必要な属性を追加します
function OnBeforeAdvice(onBeforeHandler) { return new Advice(function(fn) { return function() { onBeforeHandler(fn, arguments); return fn.apply(this, arguments); } }); } function OnAfterAdvice(onAfterHandler) { return new Advice(function(fn) { return function() { var result = fn.apply(this, arguments); onAfterHandler(fn, arguments, result); return result; } }); } function OnErrorAdvice(onErrorHandler) { return new Advice(function(fn) { return function() { try { return fn.apply(this, arguments); } catch (e) { onErrorHandler(fn, arguments, e); } } }); } // // "Pet.prototype.getName" function FunctionName(fnName) { return new Advice(function(fn) { var root = window, objs = fnName.split("."), i, oName; for (i = 0; i < objs.length - 1; i++) { oName = objs[i]; if (!root.oName) { root[oName] = {}; } root = root[oName]; } oName = objs[i]; root[oName] = fn; return fn; }); }
すべての準備が整いました。メソッドを作成して拡張できます
<script type="text/javascript"> AOP( [OnBeforeAdvice(onBeforeHandler)], [OnAfterAdvice(onAfterHandler)], function sqr(x) { return x * x; }, [OnAfterAdvice(onBeforeHandler)], [FunctionName("AliasA")], function A() { }, [OnErrorAdvice(onErrorHandler)], function throwsException() { throw "Exception"; } ); function onBeforeHandler(fn, args) { console.log("I know that somebody calls " + fn.toString().split("(")[0]); } function onAfterHandler(fn, args, result) { console.log("Returns " + result + " from " + args[0]); } function onErrorHandler(fn, args, e) { console.log(e + " was thrown"); } onload = function () { sqr(10); A(); AliasA(); throwsException(); } </script>
そして今、あなたは「優雅に」機能に従うことができ、それらを1行でマークします。 AOP()関数を改良し、オブジェクトにも属性を適用できますが、これはわずかに異なるタスクになります。
ウィキペディアの記事には、JavaScriptのAOP実装へのリンクがあり、比較できます。 そして別のアスペクトJSプロジェクト
PS:evalについて公正な指摘をしました。 彼は、この記事で冗長と見なしたコードを返しました。