Шаблоны проектирования

Javascript. Design patterns. Reuse software code. – The Media Image

The writer: Valery Sestov Publication date: 03/10/2014

In follow, conditions typically come up when it’s a must to develop functionality that could be very comparable in its primary features to the already present developments of earlier tasks, typically such things are pop-up windows, drop-down lists, menus, galleries, and so forth.

The use of earlier developments in new tasks isn’t all the time potential, as a result of certain distinctive variations in performance, so all the things typically needs to be rewritten, virtually from scratch.

Proper use of object-oriented approaches in the improvement, provides us the opportunity to avoid the constant rewriting and processing of once-written packages, and makes it potential to complement present objects with essential functionality by way of the inheritance of primary (father or mother) objects.

We’ll think about numerous methods to implement inheritance in JavaScript and concepts reminiscent of classical inheritance and non-classical inheritance. By classical inheritance we mean the state of affairs that the objects created by the Youngster () constructor perform acquire properties inherent in another Father or mother () constructor.

Right here is an example implementation of the Mother or father () and Baby () constructors:

perform Dad or mum (identify)
    this.identify = identify || “Adam”;

Father or mother.prototype.say = perform ()
    return this.identify;
;

perform Youngster (identify)

inherit (Youngster, Father or mother);

Here we’ve got the mum or dad and baby constructors, the say () technique added to the prototype of the mother or father constructor, and a name to the inherit () perform, which sets the inheritance dependency.

Basic Template # 1: Default Template

The most commonly used and easy to implement template, the essence of which is to assign the properties and strategies of the Mum or dad () object to the Baby () object.

It’s finished as follows:

perform inherit (C, P)
    C.prototype = new P ();

When an object is created utilizing the brand new Baby () expression, this object will inherit the functionality of the Mum or dad () instance by way of prototype.

var youngster = new Youngster ();
youngster.say (); // “Adam”

Thus, an instance of the kid object could have properties and methods added by means of the prototype of the Mother or father () object.

Advantages and drawbacks

The benefits of this template are that the Baby () object will get all the properties and methods of the Father or mother () object, and the convenience of implementation.

The drawback of this template is that it isn’t potential to transfer incoming parameters from the child object to the constructor perform of the mum or dad object, which may be essential for the right initialization of the dad or mum.

Example:

var button = doc.getElementById (“button”);

button.addEventListener (“click”, perform ()
    check ();
, false);

perform inherit (C, P)
    C.prototype = new P ();

/ **
 * Telephone
 * /
perform Telephone (identify, measurement)
    this.identify = identify || “Phone”;
    this.measurement = measurement ||
        w: 50,
        h: 50
    ;

Telephone.prototype.getName = perform ()
    alert (this.identify);
;

Telephone.prototype.getSize = perform ()
    var measurement = this.measurement;
    alert (“width:” + measurement.w + “; height:” + measurement.h);
;

/ **
 * Nokia
 * /
perform Nokia (identify, measurement)
    if (identify)
        this.identify = identify;
    
    if (measurement)
        this.measurement = measurement;
    
;

perform check ()
    
    inherit (Nokia, Telephone);

    var nokia_1 = new Nokia (),
        nokia_2 = new Nokia (“Nokia 6600”, w: 100, h: 200);

    nokia_1.getName ();
    nokia_1.getSize ();
    nokia_2.getName ();
    nokia_2.getSize ();
    

In action:
http://jsfiddle.net/valsie / G8uWG/4/

As you’ll be able to see from the instance, the Youngster () object inherited the methods and properties of the Dad or mum () object.

Basic template quantity 2: Borrowing designer

This template eliminates the shortage of a basic template number one, the switch of parameters via the child to the mother or father. This template binds a toddler object with a this link.

perform Youngster (a, b, c, d)
    Mum or dad.apply (this, arguments);

With this strategy, only the properties added contained in the constructor shall be inherited, and the properties of the prototype won’t be inherited.

Contemplate the following instance:

var button = document.getElementById (“button”);

button.addEventListener (“click”, perform ()
    check ();
, false);

/ **
 * Telephone
 * /
perform Telephone (identify, measurement)
    this.identify = identify || “Phone”;
    this.measurement = measurement ||
        w: 50,
        h: 50
    ;
    
    this.showNameAndSize = perform ()
        var measurement = this.measurement;
        alert (identify + “- width:” + measurement.w + “, height:” + measurement.h);
    ;

Telephone.prototype.getName = perform ()
    alert (this.identify);
;

Telephone.prototype.getSize = perform ()
    var measurement = this.measurement;
    alert (“width:” + measurement.w + “; height:” + measurement.h);
;

/ **
 * Nokia
 * /
perform Nokia (identify, measurement)
    Telephone.apply (this, arguments);
;

perform check ()
    
    var nokia_1 = new Nokia (),
        nokia_2 = new Nokia (“Nokia 6600”, w: 100, h: 200);

    if (nokia_1.hasOwnProperty (“getName”))
        nokia_1.getName ();
     else
        console.log (“getName is undefined”);
    
    
    if (nokia_1.hasOwnProperty (“getSize”))
        nokia_1.getSize ();
     else
        console.log (“getSize is undefined”);
    
    
    if (nokia_1.hasOwnProperty (“showNameAndSize”))
        nokia_1.showNameAndSize ();
     else
        console.log (“showNameAndSize is undefined”);
    
    
    if (nokia_2.hasOwnProperty (“getName”))
        nokia_2.getName ();
     else
        console.log (“getName is undefined”);
    
    
    if (nokia_2.hasOwnProperty (“getSize”))
        nokia_2.getSize ();
     else
        console.log (“getSize is undefined”);
    
    
    if (nokia_2.hasOwnProperty (“showNameAndSize”))
        nokia_2.showNameAndSize ();
     else
        console.log (“showNameAndSize is undefined”);
    

In motion:
http://jsfiddle.net/valsie/nnhQ2/1/

Advantages and drawbacks

The disadvantage of this template is that it does not provide inheritance of the properties of the prototype.

The benefit is that the kid objects receive actual copies of the properties of the mother or father objects, thus eliminating the danger of unintentional modifications in the worth of the properties of the dad or mum.

Basic template number 3: Borrowing and set up of the prototype

This template aims to enhance the earlier one, specifically so as to add the power to inherit the features of the prototype

perform Baby (a, b, c, d)
    Dad or mum.apply (this, arguments);

Youngster.prototype = new Dad or mum ();

Advantage – the child object is obtained copies of its own mother or father members and a link to the features of the prototype.

Disadvantages – the need to name the father or mother constructor twice, which reduces effectivity, since some properties are inherited twice.

Basic Template # four: Prototype Sharing

perform inherit (C, P)
    C.prototype = P.prototype;

In this case, the whole lot that ought to be inherited ought to be within the mother or father prototype, through which case the thing inherits all of the properties and strategies and the call to the mother or father constructor is executed only as soon as.

The disadvantage of this technique is that the child and mother or father objects confer with the identical perform of the prototype, and modifications within the properties of one object, will entail modifications within the properties of another, which makes it inconceivable to carry out redefinition of strategies or properties.

Basic Template No. 5: Short-term Designer

This pattern solves the problem of the previous one, breaking the direct connection between the prototypes, so now modifications in one object won’t entail modifications in another.

perform inherit (C, P)
    var F = perform () ;
    F.prototype = P.prototype;
    C.prototype = new F ();

It is very important keep in mind that with this mode of inheritance, the properties and strategies of the dad or mum object itself will not be inherited, only the properties and strategies of the prototype are inherited.

To increase the capabilities of the inherit perform, you’ll be able to add a reference to the dad or mum class.

perform inherit (C, P)
    var F = perform () ;
    F.prototype = P.prototype;
    C.prototype = new F ();
    C.superClass = P.prototype;

The final thing you are able to do to make this perform approximate to the perfect is to remove the constant creation of an empty perform F when accessing the inherit perform.

var inherit = (perform ()
    var F = perform () ;
    return perform (C, P)
        F.prototype = P.prototype;
        C.prototype = new F ();
        C.superClass = P.prototype;
    ;
());

Instance:

var button = doc.getElementById (“button”);

button.addEventListener (“click”, perform ()
    check ();
, false);

var inherit = (perform ()
    var F = perform () ;
    return perform (C, P)
        F.prototype = P.prototype;
        C.prototype = new F ();
        C.superClass = P.prototype;
    ;
());

/ **
 * Telephone
 * /
perform Telephone ()

Telephone.prototype =
    
    init: perform (identify, measurement)
        
        this.identify = identify || “Phone”;
        this.measurement = measurement ||
            w: 50,
            h: 50
        ;
    ,
    
    getName: perform ()
        alert (this.identify);
    ,
    
    getSize: perform ()
        var measurement = this.measurement;
        alert (“width:” + measurement.w + “; height:” + measurement.h);
    
;

/ **
 * Nokia
 * /
perform Nokia ()
    this.identify = null;
    this.measurement = null;
;

perform check ()
    
    inherit (Nokia, Telephone);
    
    var nokia_1 = new Nokia (),
        nokia_2 = new nokia ();

    nokia_1.init ();
    nokia_2.init (“Nokia 6600”, w: 100, h: 200);
        
    nokia_1.getName ();
    nokia_1.getSize ();
    nokia_2.getName ();
    nokia_2.getSize ();

In motion:
http://jsfiddle.net/valsie / LVH5F/

Class Simulation Template

Many JavaScript libraries try and emit courses, but all implementations have comparable options:

  • There’s a technique that’s thought-about a constructor, and is known as mechanically.
  • There’s the inheritance of some courses by others
  • There’s entry to the mother or father class (superclass) of the kid.

Think about the following development of the class description:

var Telephone = jClass (null,
    init: perform (variable)
        console.log (“constructor”);
        this.identify = variable;
    ,
    getName: perform ()
        return this.identify;
    
);

This perform performs the class declaration and takes two parameters, the first is the mum or dad class, the second is the properties and methods of the class being created. On this instance, the init perform was chosen because the constructor perform.

The first parameter of the perform is null, this indicates that no inheritance is carried out, the category may have only its personal properties and methods.

Increase this class and create a new one:

var Nokia = jClass (Telephone,
    init: perform (variable)
        console.log (“Nokia constructor”);
    ,
    getName: perform ()
        var identify = Nokia.superClass.getName.name (this);
        return “I am” + identify;
    
);

Here is the inheritance of the class Telephone, and the creation of latest Nokia. As you’ll be able to see, within the new class such features are declared as in the father or mother class, thus a redefinition of the features of the dad or mum is obtained, however because the reference to the superclass is retained, we will seek advice from the features of the mother or father class.

Let's proceed to the jClass perform implementation:

var jClass = perform (Father or mother, properties)
    var Youngster, F, i;

    // 1. New constructor
    Youngster = perform ()
        if (Baby.superClass && baby.superClass.hasOwnProperty (“init”))
            Youngster.superClass.init.apply (this, arguments);
        

        if (Baby.prototype.hasOwnProperty (“init”))
            Youngster.prototype.init.apply (this, arguments);
        
    

    // 2. Inheritance

    Mum or dad = Mother or father || Object;
    F = perform () ;
    F.prototype = Mum or dad.prototype;
    Youngster.prototype = new F ();
    Baby.superClass = Dad or mum.prototype;
    Youngster.prototype.constructor = Baby;

    // three. Add technique implementation

    for (i in properties)
        if (properties.hasOwnProperty (i))
            Youngster.prototype[i] = properties[i];
        
    

    return Baby;
;

In action:
http://jsfiddle.net/valsie/pK58m/6/

Prototype inheritance

This template has nothing to do with courses, right here some objects inherit others.

One of these inheritance might be represented as follows: there’s some object that can be reused, and you have to create a second object that makes use of the capabilities of the first one.

// object that’s inherited
var father or mother =
    identify: “Papa”
;
// new object
var baby = object (father or mother);
// examine
alert (youngster.identify); // “Papa”

The implementation of the thing perform is as follows:

perform object (o)
    perform F ()
    F.prototype = o;
    return new F ();

On this template, the kid object is all the time created as an empty object, which doesn’t have its own properties, but which has entry to all of the performance of the mother or father mum or dad object because of the __proto__ hyperlink.

Within the template, the mother or father object does not should be created utilizing a literal (though this technique is the most common). With the identical success, the creation of the mother or father object may be completed utilizing the constructor perform.

Nevertheless, it is necessary to consider that within the latter case not solely the properties of the prototype of the constructor shall be inherited, but in addition the “own” properties of the item:

// dad or mum constructor
perform PersonO
    // “own” property
    this.identify = “Adam”;

// property added to prototype
Individual.prototype.getName = perform ()
    return this.identify;
;
// create a new object of sort Individual
var papa = new PersonO;
// heir
var kid = object (papa);
// ensure that it isn’t solely inherited
// property of the prototype, but in addition its own property
child.getName (); // “Adam”

ECMAScript5 Extensions

In ECMAScript 5 commonplace, the inheritance inheritance sample has grow to be an official a part of the language. This template is carried out as an Object.create () technique. In different phrases, you do not want to create your personal perform, just like object (); it’ll already be constructed into the language:
var youngster = Object.create (mother or father);

The Object.create () technique takes a further parameter – an object. The properties of this object can be added to the newly created youngster object as its personal properties. This lets you create baby objects and outline inheritance ratios with a single technique name.

For example:

var youngster = Object.create (dad or mum,
    age:
        value: 2
    
);

baby.hasOwnPorperty (“age”); // true

Inheritance by way of prototype in motion:
http://jsfiddle.net/valsie / ZrLA7/

Inheritance by copying properties

Let's contemplate one other method of inheritance – inheritance by copying properties. In this template, one object accesses the functionality of one other object by merely copying properties. Under is an example implementation:

perform prolong (father or mother, youngster)
    var i;
    baby – youngster || ;
    for (i in dad or mum)
        if (mother or father.hasOwnProperty (i))
            baby[i] = father or mother[i];
        
    
    return baby;

This instance crawls and copies the members of the father or mother object.
On this implementation of copying, so-called “surface copying” of properties is carried out. On this case, such properties as arrays and objects can be transferred to new objects by reference, and a change in them will entail modifications in the mum or dad parts.

In case it is essential to carry out a full copy, making an allowance for arrays and objects, the prolong perform should seem like this:

perform extendDeep (dad or mum, baby)
    var i,
          toStr = Object.prototype.toString,
          astr = “[object Array]”;

    youngster = youngster || ;
    for (i in dad or mum)
        if (father or mother.hasOwnProperty (i))
            if (typeof father or mother[i] === “object”)
                baby[i] = (toStr.call (father or mother[i]) === astr)? [] : ;
                extendDeep (mother or father[i]youngster[i]);
             else
                youngster[i] = mum or dad[i];
            
        
    
    return youngster;

Now, utilizing this perform, you possibly can carry out a full copy of the thing properties.