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 - Number
var 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