Function classFunction.prototype.method = function (methodName, f) {
return this .prototype[methodName] = f;
}
* This source code was highlighted with Source Code Highlighter .
Function class ).method(...) to the prototype of the Function class , all instances of the Function class have a new method(...) (but remember: there are no methods in JavaScript, Neo).Object , Array , Number , YourClassName - is an instance of the Function class , i.e. just a function. So we got: Object.method(...) , Array.method(...) , YourClassNam.method(...)Function.method( "decorate" , function (f) {
var oldMe = this ;
var newMe = f;
newMe.old = oldMe;
return newMe;
})
* This source code was highlighted with Source Code Highlighter .Function class itself is a function, or an instance of the Function class (aaa :-))Function.prototype.method = function (...) {}
* This source code was highlighted with Source Code Highlighter .Function. method (...) Function. method (...) (no longer in the prototype, but in an instance of the Function class )Function.prototype. decorate (...) Function.prototype. decorate (...) . And again, the method appeared in the prototype Function , and therefore in all-all-all classes . But here it’s just not important to me, and what matters is the presence of the decorate(...) method for all functions.decorate (...) method do?//
var oldMe = this ;
// , " " .
var newMe = f;
newMe.old = oldMe;
return newMe;
* This source code was highlighted with Source Code Highlighter .// -,
function MyCoolNumber(initNumber) {
this .value = initNumber;
}
* This source code was highlighted with Source Code Highlighter .new MyCoolNumber( ' ' ) // " "
* This source code was highlighted with Source Code Highlighter .function strictArgs() { // ,
var types = arguments; //
return function () {
var params = arguments;
if ( params .length != types.length)
throw "! " + types.length + " (), " + params .length;
for ( var i=0, l= params .length; i < l; i++) {
if (!( params [i] instanceof types[i]) && !( params [i].constructor == types[i]))
throw "! #" + (i+1) + " " + types[i].name;
}
arguments.callee.old.apply( this , arguments); // , ""
}
}
* This source code was highlighted with Source Code Highlighter .function MyCoolNumber(initNumber) {
this .value = initNumber;
}
MyCoolNumber = MyCoolNumber.decorate(strictArgs(Number))
new MyCoolNumber(); // ! 1 (), 0
new MyCoolNumber(1, 2, 3); // ! 1 (), 3
new MyCoolNumber( "" ); // ! #1 Number
var x = new MyCoolNumber(6); // OK!
alert(x.value) // 6, , .
* This source code was highlighted with Source Code Highlighter .strictArgs with one argument is called - Numbervar types = arguments; // strictArgs(...) types, [Number] - 1 -: Number. Arguments - , ,strictArgs(...) returns a new strictArgs(...) , inside of which:var params = arguments; // , , MyCoolNumber;MyCoolNumber that returned from strictArgs(...)arguments.callee.old.apply(this, arguments) :arguments - the standard object for describing the arguments of the function being called.arguments.callee - the decorator function itselfarguments.callee.old - remember, what is - old? When we pass a decoder function to the decorate (...) method, it adds the old attribute to this function, which refers to the “old” function.arguments.callee.old.apply(...) is the standard method of the Function class. I will not be about him, let me just say that he calls the function with the given scope and argumentsarguments.callee.old.apply(this, arguments) - actually, a confirmation of the aboveFunction.method( "recover" , function () {
return this .old || this ;
})
* This source code was highlighted with Source Code Highlighter .Object.method( 'before' , function (methodName, f){
var method = listenerInit.call( this , methodName);
if (method)
method.listenersBefore.push(f);
})
Object.method( 'after' , function (methodName, f){
var method = listenerInit.call( this , methodName);
if (method)
method.listenersAfter.push(f);
})
* This source code was highlighted with Source Code Highlighter .listenerInit(...) , but about it later. For now, just believe that she makes all the necessary preparations.Object.method( 'removeBefore' , function (methodName, f){
var method = listenerInit.call( this , methodName);
if (method) {
var _nl = [];
while (method.listenersBefore.length) {
var _f = method.listenersBefore.shift();
if (_f != f)
_nl.push(_f);
}
method.listenersBefore = _nl;
}
})
Object.method( 'removeAfter' , function (methodName, f){
var method = listenerInit.call( this , methodName);
if (method) {
var _nl = [];
while (method.listenersAfter.length) {
var _f = method.listenersAfter.shift();
if (_f != f)
_nl.push(_f);
}
method.listenersAfter = _nl;
}
})
* This source code was highlighted with Source Code Highlighter .listenerInit :function listenerInit(methodName) {
var method = this [methodName];
if ( typeof method != "function" )
return false ;
// , ?
if (!method.listenable) {
this [methodName] = method.decorate( function (){
var decorator = arguments.callee;
decorator.listenable = true ;
var list = decorator.listenersBefore;
for ( var i = 0, l = list.length; i < l; i++) {
if ( typeof list[i] == "function" && list[i].apply( this , arguments) === false )
return ;
}
var ret = decorator.old.apply( this , arguments);
list = decorator.listenersAfter;
for ( var i = 0, l = list.length; i < l; i++)
list[i].apply( this , arguments);
return ret;
});
method = this [methodName];
}
method.listenersBefore = method.listenersBefore instanceof Array ? method.listenersBefore : [];
method.listenersAfter = method.listenersAfter instanceof Array ? method.listenersAfter : [];
return method;
}
* This source code was highlighted with Source Code Highlighter .var method = this [methodName];
if ( typeof method != "function" )
return false ;
* This source code was highlighted with Source Code Highlighter .return method , i.e. listenerInit(...) returns either false or the already “decorated” method.listenersBefore array. If at least 1 of them returns a Boolean false , stop execution.listenersAfter arraymethod.listenersBefore and method.listenersAfter .listenerInit out of sight. To do this, use the JavaScript closure:( function (){
// listenerInit(...) --
// .....
})()
* This source code was highlighted with Source Code Highlighter .Object is very bad, so you can modify your particular class:YourClass.method( 'before' , function (methodName, f){
var method = listenerInit.call( this , methodName);
if (method)
method.listenersBefore.push(f);
})
* This source code was highlighted with Source Code Highlighter .//
var Num = function (x) {
this .x = x;
}
//
Num.prototype.x = null ;
Num.prototype.getX = function () {
return this .x;
};
Num.prototype.setX = function (x) {
return this .x = x;
}
//
var t = new Num(6);
// after
t.after( "getX" , function (){
alert( '! X == ' + this .x + '!' );
})
// after
t.after( "getX" , function (){
alert( ' !' );
})
// before,
var f = function (x){
if (x < 0 || x > 10) {
alert( '! [0, 10]' );
return false ;
}
}
t.before( "setX" , f)
// :
t.getX(); // ! X == 6! -> ' ! -> getX(...)
t.setX(100); // ! [0, 10] -> setX(100) -
alert(tx); // 6
t.setX(4); // , setX(4)
alert(tx); // 4
t.removeBefore( "setX" , f) // f(...)
t.setX(100); // , setX(100)
alert(tx); // 100
* This source code was highlighted with Source Code Highlighter .Function.method(...)// ,
Function.prototype.method = function (methodName, f) {
if ( typeof f != "undefined" )
this .prototype[methodName] = f;
return this .prototype[methodName];
}
* This source code was highlighted with Source Code Highlighter .restore(...) method// "" -,
Function.method( "restore" , function (fullRestore){
var ret = this .old || this ;
while (fullRestore && ret.old) {
ret = ret.old;
}
return ret;
})
* This source code was highlighted with Source Code Highlighter .decorateMethod(...) method//
Function.method( "decorateMethod" , function (methodName, decorator){
var f = this .method(methodName);
if (!f)
return null ;
f.name = methodName;
f = f.decorate(decorator);
return this .method(methodName, f);
})
* This source code was highlighted with Source Code Highlighter .decorate(...)
Function.method( "decorate" , function (decorator){
//
var oldFunc = this ;
// ! - .
// , -.
// ,
// -- original: oldFunc () decoratorInstance: f ( )
var f = function (){
return decorator.apply( this , [{original: oldFunc, decoratorInstance: f}].concat([].slice.apply(arguments)))
}
// - - decoratorInstance f
f.old = oldFunc;
// -.
// - .
f.prototype = this .prototype;
f.prototype.constructor = f;
// -. ? .
// . , decorateMethod: .
f.name = oldFunc.name;
//
return f;
})
* This source code was highlighted with Source Code Highlighter .
( decorate(...) ), .
:
// -
function strictArgs() {
var types = arguments;
return function () {
var params = arguments;
//...
return arguments.callee.old.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
:
// -
function strictArgs() {
var types = arguments;
return function (dScope) {
var original = arguments[0].original; // dScope.original
var arguments = Array.prototype.slice.call(arguments, 1);
var params = arguments;
//...
return original.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
, :)
decorate(...)
Function.method( "decorate" , function (decorator){
//
var oldFunc = this ;
// ! - .
// , -.
// ,
// -- original: oldFunc () decoratorInstance: f ( )
var f = function (){
return decorator.apply( this , [{original: oldFunc, decoratorInstance: f}].concat([].slice.apply(arguments)))
}
// - - decoratorInstance f
f.old = oldFunc;
// -.
// - .
f.prototype = this .prototype;
f.prototype.constructor = f;
// -. ? .
// . , decorateMethod: .
f.name = oldFunc.name;
//
return f;
})
* This source code was highlighted with Source Code Highlighter .
( decorate(...) ), .
:
// -
function strictArgs() {
var types = arguments;
return function () {
var params = arguments;
//...
return arguments.callee.old.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
:
// -
function strictArgs() {
var types = arguments;
return function (dScope) {
var original = arguments[0].original; // dScope.original
var arguments = Array.prototype.slice.call(arguments, 1);
var params = arguments;
//...
return original.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
, :)
decorate(...)
Function.method( "decorate" , function (decorator){
//
var oldFunc = this ;
// ! - .
// , -.
// ,
// -- original: oldFunc () decoratorInstance: f ( )
var f = function (){
return decorator.apply( this , [{original: oldFunc, decoratorInstance: f}].concat([].slice.apply(arguments)))
}
// - - decoratorInstance f
f.old = oldFunc;
// -.
// - .
f.prototype = this .prototype;
f.prototype.constructor = f;
// -. ? .
// . , decorateMethod: .
f.name = oldFunc.name;
//
return f;
})
* This source code was highlighted with Source Code Highlighter .
( decorate(...) ), .
:
// -
function strictArgs() {
var types = arguments;
return function () {
var params = arguments;
//...
return arguments.callee.old.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
:
// -
function strictArgs() {
var types = arguments;
return function (dScope) {
var original = arguments[0].original; // dScope.original
var arguments = Array.prototype.slice.call(arguments, 1);
var params = arguments;
//...
return original.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
, :)
decorate(...)
Function.method( "decorate" , function (decorator){
//
var oldFunc = this ;
// ! - .
// , -.
// ,
// -- original: oldFunc () decoratorInstance: f ( )
var f = function (){
return decorator.apply( this , [{original: oldFunc, decoratorInstance: f}].concat([].slice.apply(arguments)))
}
// - - decoratorInstance f
f.old = oldFunc;
// -.
// - .
f.prototype = this .prototype;
f.prototype.constructor = f;
// -. ? .
// . , decorateMethod: .
f.name = oldFunc.name;
//
return f;
})
* This source code was highlighted with Source Code Highlighter .
( decorate(...) ), .
:
// -
function strictArgs() {
var types = arguments;
return function () {
var params = arguments;
//...
return arguments.callee.old.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
:
// -
function strictArgs() {
var types = arguments;
return function (dScope) {
var original = arguments[0].original; // dScope.original
var arguments = Array.prototype.slice.call(arguments, 1);
var params = arguments;
//...
return original.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
, :)
decorate(...)
Function.method( "decorate" , function (decorator){
//
var oldFunc = this ;
// ! - .
// , -.
// ,
// -- original: oldFunc () decoratorInstance: f ( )
var f = function (){
return decorator.apply( this , [{original: oldFunc, decoratorInstance: f}].concat([].slice.apply(arguments)))
}
// - - decoratorInstance f
f.old = oldFunc;
// -.
// - .
f.prototype = this .prototype;
f.prototype.constructor = f;
// -. ? .
// . , decorateMethod: .
f.name = oldFunc.name;
//
return f;
})
* This source code was highlighted with Source Code Highlighter .
( decorate(...) ), .
:
// -
function strictArgs() {
var types = arguments;
return function () {
var params = arguments;
//...
return arguments.callee.old.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
:
// -
function strictArgs() {
var types = arguments;
return function (dScope) {
var original = arguments[0].original; // dScope.original
var arguments = Array.prototype.slice.call(arguments, 1);
var params = arguments;
//...
return original.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
, :)
decorate(...)
Function.method( "decorate" , function (decorator){
//
var oldFunc = this ;
// ! - .
// , -.
// ,
// -- original: oldFunc () decoratorInstance: f ( )
var f = function (){
return decorator.apply( this , [{original: oldFunc, decoratorInstance: f}].concat([].slice.apply(arguments)))
}
// - - decoratorInstance f
f.old = oldFunc;
// -.
// - .
f.prototype = this .prototype;
f.prototype.constructor = f;
// -. ? .
// . , decorateMethod: .
f.name = oldFunc.name;
//
return f;
})
* This source code was highlighted with Source Code Highlighter .
( decorate(...) ), .
:
// -
function strictArgs() {
var types = arguments;
return function () {
var params = arguments;
//...
return arguments.callee.old.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
:
// -
function strictArgs() {
var types = arguments;
return function (dScope) {
var original = arguments[0].original; // dScope.original
var arguments = Array.prototype.slice.call(arguments, 1);
var params = arguments;
//...
return original.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
, :)
decorate(...)
Function.method( "decorate" , function (decorator){
//
var oldFunc = this ;
// ! - .
// , -.
// ,
// -- original: oldFunc () decoratorInstance: f ( )
var f = function (){
return decorator.apply( this , [{original: oldFunc, decoratorInstance: f}].concat([].slice.apply(arguments)))
}
// - - decoratorInstance f
f.old = oldFunc;
// -.
// - .
f.prototype = this .prototype;
f.prototype.constructor = f;
// -. ? .
// . , decorateMethod: .
f.name = oldFunc.name;
//
return f;
})
* This source code was highlighted with Source Code Highlighter .
( decorate(...) ), .
:
// -
function strictArgs() {
var types = arguments;
return function () {
var params = arguments;
//...
return arguments.callee.old.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
:
// -
function strictArgs() {
var types = arguments;
return function (dScope) {
var original = arguments[0].original; // dScope.original
var arguments = Array.prototype.slice.call(arguments, 1);
var params = arguments;
//...
return original.apply( this , arguments);
}
}
* This source code was highlighted with Source Code Highlighter .
, :)
Source: https://habr.com/ru/post/59761/
All Articles