Button
from Rectangle
, and Rectangle
can inherit from Control
... so, stop ... ").call
or apply
. This is an effective feature, and I use it extensively. Anyway, delegation is so convenient that sometimes it starts working against structural code discipline; moreover, the syntax may become slightly verbose. Impurities are a great compromise that allows you to borrow and have access to whole functional units using minimalistic syntax, and they work fine in the same team with prototypes. They offer the descriptive power of hierarchical inheritance without the brain problems associated with high-rise, single-root inheritance.Person
, Circle
, Observer
). Impurity classes are usually considered abstract in the sense that they do not have instances on their own — instead, their methods are copied (or “borrowed”) by concrete classes as “inheritance” of behavior without entering into formal relationships with the supplier of behavior. var Circle = function() {}; Circle.prototype = { area: function() { return Math.PI * this.radius * this.radius; }, grow: function() { this.radius++; }, shrink: function() { this.radius--; } };
var circleFns = { area: function() { return Math.PI * this.radius * this.radius; }, grow: function() { this.radius++; }, shrink: function() { this.radius--; } };
extend
function (sometimes called augment
). In general, extend
simply copies (but does not clone) the impurity functions to the receiving object. A quick overview shows several small variations of this implementation. For example, Prototype.js skips the hasOwnProperty
check (assuming the impurity does not have enumerated properties in the prototype chain), while other versions assume that you only want to copy properties from the impurity prototype. Here is a safe and flexible option ... function extend(destination, source) { for (var k in source) { if (source.hasOwnProperty(k)) { destination[k] = source[k]; } } return destination; }
var RoundButton = function(radius, label) { this.radius = radius; this.label = label; }; extend(RoundButton.prototype, circleFns); extend(RoundButton.prototype, buttonFns); //etc. ...
extend
function. var asCircle = function() { this.area = function() { return Math.PI * this.radius * this.radius; }; this.grow = function() { this.radius++; }; this.shrink = function() { this.radius--; }; return this; }; var Circle = function(radius) { this.radius = radius; }; asCircle.call(Circle.prototype); var circle1 = new Circle(5); circle1.area(); //78.54
this
always points to the recipient of the function sets, and not to an abstract object that we do not need and which we do not use; moreover, in contrast to the traditional approach, we do not need protection against unintentional copying of inherited properties, and (whatever that means) functions are now cloned, not copied. var asButton = function() { this.hover = function(bool) { bool ? mylib.appendClass('hover') : mylib.removeClass('hover'); }; this.press = function(bool) { bool ? mylib.appendClass('pressed') : mylib.removeClass('pressed'); }; this.fire = function() { return this.action(); }; return this; };
var RoundButton = function(radius, label, action) { this.radius = radius; this.label = label; this.action = action; }; asButton.call(RoundButton.prototype); asCircle.call(RoundButton.prototype); var button1 = new RoundButton(4, 'yes!', function() {return 'you said yes!'}); button1.fire(); //'you said yes!'
asOval
impurity with custom grow
and shrink
parameters: var asOval = function(options) { this.area = function() { return Math.PI * this.longRadius * this.shortRadius; }; this.ratio = function() { return this.longRadius/this.shortRadius; }; this.grow = function() { this.shortRadius += (options.growBy/this.ratio()); this.longRadius += options.growBy; }; this.shrink = function() { this.shortRadius -= (options.shrinkBy/this.ratio()); this.longRadius -= options.shrinkBy; }; return this; } var OvalButton = function(longRadius, shortRadius, label, action) { this.longRadius = longRadius; this.shortRadius = shortRadius; this.label = label; this.action = action; }; asButton.call(OvalButton.prototype); asOval.call(OvalButton.prototype, {growBy: 2, shrinkBy: 2}); var button2 = new OvalButton(3, 2, 'send', function() {return 'message sent'}); button2.area(); //18.84955592153876 button2.grow(); button2.area(); //52.35987755982988 button2.fire(); //'message sent'
asRectangle
with the addition of caching ... var asRectangle = (function() { function area() { return this.length * this.width; } function grow() { this.length++, this.width++; } function shrink() { this.length--, this.width--; } return function() { this.area = area; this.grow = grow; this.shrink = shrink; return this; }; })(); var RectangularButton = function(length, width, label, action) { this.length = length; this.width = width; this.label = label; this.action = action; } asButton.call(RectangularButton.prototype); asRectangle.call(RectangularButton.prototype); var button3 = new RectangularButton(4, 2, 'delete', function() {return 'deleted'}); button3.area(); //8 button3.grow(); button3.area(); //15 button3.fire(); //'deleted'
asRectangle
admixture with correctly asRectangle
functions that allow parameterization of grow
and shrink
. Function.prototype.curry = function() { var fn = this; var args = [].slice.call(arguments, 0); return function() { return fn.apply(this, args.concat([].slice.call(arguments, 0))); }; } var asRectangle = (function() { function area() { return this.length * this.width; } function grow(growBy) { this.length += growBy, this.width +=growBy; } function shrink(shrinkBy) { this.length -= shrinkBy, this.width -= shrinkBy; } return function(options) { this.area = area; this.grow = grow.curry(options['growBy']); this.shrink = shrink.curry(options['shrinkBy']); return this; }; })(); asButton.call(RectangularButton.prototype); asRectangle.call(RectangularButton.prototype, {growBy: 2, shrinkBy: 2}); var button4 = new RectangularButton(2, 1, 'add', function() {return 'added'}); button4.area(); //2 button4.grow(); button4.area(); //12 button4.fire(); //'added'
var myCircle = asCircle.call({radius:25}); myCircle.area(); //1963.50
Source: https://habr.com/ru/post/147901/
All Articles