Prototype/Pattern


This is a thread of interest started in Zoho by Andre Dublin.

I'll be talking about prototype here, and trying to remake these patterns using ecmascript 5

----

Basic Object

http://jsfiddle.net/dublinan/dLhsV/

Basic Object with ecmascript 5

http://jsfiddle.net/dublinan/XhqHL/

----

Strange when I open this with IE, I get undefined instead of Andre, Andre. But I get the correct function on firefox.

----

Only IE9 and other modern browsers have support for ecmascript 5.  Thats why you get undefined for the returned value.

ecmascript 5 support link
http://kangax.github.com/es5-compat-table/

----

There are two links towards the bottom of the Week 1 material that lead to tables showing what is compatible where.

----

Classical inheritance using a constructor function

http://jsfiddle.net/dublinan/mQbn8/

I'll have a ECMAScript 5 version up shortly

----

Diskutera uppgift


  • Anonym   3 juni 2011 13:27
  • Anonym   25 maj 2011 13:19

    I think it is useful to say why this whole business is an issue at all.

    Because js is being used in bigger apps and more like a "proper" programming language (growing up, if you like), the need arises for things that are already present in other languages but not in js.

    One of these things is object inheritance and is the subject of a lot of discussion (what is the "most desirable" pattern?)

    Object.create() of ES5 is one response to this; you can also implement your own version of it for use in non-ES5 browsers. Crockford's original implementation (at http://javascript.crockford.com/prototypal.html):

    Object.create = function (o) {
            function F() {}
            F.prototype = o;
            return new F();
        };

  • Anonym   26 maj 2011 09:48
    Som Svar På:   Anonym   25 maj 2011 13:19

    Inhertitance is one of my favorite little "syntactic sugar" areas to add to Javascript, creating a "Class" mechanism.  The debates for and against creating classes in JS are numerous, some argue that inheritance should be done in a prototypital fashion, that classes are a relic from times past.  Personally, I find it extremely useful as well as a huge simplification to think in terms of classes, even in Javascript.  While not everything from C++ and Java can be implemented in Javascript, by combining the module pattern with prototypital inheritance, you can get pretty close.

    The idea to define a class is to be able to declaratively say what the superclass is as well as what your classes methods and public properties are, or at least as many as you possibly can.

    My favorite "Class" creator is based on an old Crockford bit as well - here is a modified version that I use as the basis of one I use in AFrameJS:

    var Class = function(super, extensions) {
        // Check if there is a super class, if not,
        // set the extensions to the prototype
        // will be in the super position.
        if ('object' === typeof(super)) {
            extensions = super;
            super = null;
        }

        // Make sure there is at least an extensions object.
        extensions = extensions || {};

        // Set up our prototype chain.  Set the prototype
        // of the new class to be an instance of the superclass.
        function F() {};
        F.prototype = super && new super || {};
        
        // not strictly needed, but recommended.
        F.constructor = F;

        // Copy any "extensions" to our new classes prototype.
        for (var key in extensions) {
            if (extensions.hasOwnProperty(key)) {
                F.prototype[key] = extensions[key];
            }
        }

        return F;
    }

    To use it to define a class is pretty straight forward

    // This class has no superclass
    var Base = Class({
        message: 'Base has no superclass',     // this is a public property
        toString: function() {                               // this is a public method
            alert(this.message);
        }
    });

    var Sub = Class(Base, {                          // Base is the superclass
        message: 'Sub has a superclass'       //  this is a public method
    });

    I have this all written up and working on JSFiddle.

    This can get quite a bit more complex, you can even create classes that have private variables and methods.  Doing so requires use of the "Module Pattern", which is beyond this topic, but is shown below.


    // privateVariable and privateFunction are not accessabe from out here    
    var ClassWithPrivate = (function() {
        var privateVariable = 'This variable is private';

        var privateFunction = function() {
            return 2 + 3;
        }

        var ClassWithPrivate = Class({
            toString: function() {
                alert(privateVariable);
            },
            doAddition: function() {
                alert(privateFunction());
            }
        });

        return ClassWithPrivate;
    }());
     

    An example showing this is also found on JSFiddle

  • Andre Dublin   24 maj 2011 18:36

    Prototypes and Inheritance

    Our base function constructor which we will be working with in this example

    function Person(n,a) {

         this.name = n;

         this.age = a;

    }

    var person = new Person('Andre', 30);

    *Important to know - a method is a function that is invoked(called) as a property of an object.

    When a function is invoked this way, the object through which it is assesed becomes the value of the this keyword

    ie: //antipattern

    function say(person) {return "Hello" + name} //Hello Andre

    This works but is not object-oriented.  It is better to invoke a method on the object rather than passing the object to a function

    ie:

    var p = new Person('Andre', 30)

    p.say = function() {return this.name;}

    var name = p.say(); //Hello Andre

    However to add a method to an object before you invoke it is silly.

    ie: //improved constructor

    function Person(n,a) {

         this.name = n;

         this.age = a;

         this.say = function() {return this.name;}

    }

    var person = Person('Andre', 30)

    person.say(); //Hello Andre

    This works, but is not optimal.  Every Person created will have three properties.  The name and age of the Person may be different for each Person, but the say method of every singe Person object always refers to the same function.

    It is inefficient to use regular properties for methods that are intended to be shared by all objects of the same class(objects created with the same constructor).

    The solution is that every Javascript object has an internal reference to another object called the prototype.  Any properties of the the prototype appear to be properties of an object for which it is the prototype.  Our next example will clarify this.

    ie.

    //the constructor function initializes those properties that will be different for each instance

    function Person(n,a) {

         this.name = n;

         this.age = a;

    }

    //The prototype object holds methods and other properties that should be shared by each instance

    Person.prototype.say = function() {return this.name;}

    A constructor gives us a name for a "class" (in this case Person is the class), of objects and initializes properties, such as name and age that may be different for each instance of the class.  The prototype associated with the constructor, and each object created via the constructor inherites the same set of properties form the prototype.

    It can be good to use prototype based inheritance without constructors and classes.

    ie.

    //Create and return an object that has p as its prototype

    function inherit(p) {

         function f() {} //A dummy constructor function

         f.prototype = p; //Specify the prototype object we want

         return new f();  //Invoke the constructor to create new object

    }

    *Important - Properties from the prototype are not copied form the prototype object; they only appear as if they were properties of those objects.

    This is an important concept because the use of prototype can dramatically decrease the amount of memory required by each object because the object can inherit many of its properties.  Also an object inherits properties even if they are added to its prototype after the object is created.  This means it is possible (but not a best practice) to add new methods to existing classes.  So you can alter String or Object or Array, but other programmers may not be aware of your alterations or additions and can cause bugs or problems.

    To distinguish that a object has properties you can use the Object.hasOwnProperty() method

    ie.

    var person = new Person('Andre', 30);

    person.hasOwnProperty('name'); //true: name is a direct property of person

    person.hasOwnProperty('say'); //false: say is an inherited property of person

    'say' in person; //true: say is a property of person

    Make note that we can enumerate through the object and prototype properties are counted, but it is not the own property of the object instance.

    More to come!

    Feel free to ask questions, I am learning as much as you are.  Take the time to test these examples via jsfiddle or jsbin or whatever IDE you use.  Let me know of any errors please!

  • Anonym   25 maj 2011 06:12
    Som Svar På:   Andre Dublin   24 maj 2011 18:36

    Keep 'em coming!yes

     

    You need to know about o.freeze(),  o.seal(),  o.preventExtensions() and o.defineProperty()

    along with

    o.isFrozen(), o.isSealed(), o.isExtensible()

  • Anonym   16 maj 2011 02:13

    Can I put this one in here?: http://jsbin.com/agoke6/edit

  • Andre Dublin   16 maj 2011 08:23
    Som Svar På:   Anonym   16 maj 2011 02:13

    Yea this is good. I'm gonna rework my example, I need to figure out how to make the prototype available to new objects w/ ES 5

  • Anonym   17 maj 2011 10:20
    Som Svar På:   Andre Dublin   16 maj 2011 08:23

    You can do:

    var anObject = Object.create(Object.prototype);

    then anObject is equivalent to new Object().

  • Andre Dublin   17 maj 2011 17:11
    Som Svar På:   Anonym   17 maj 2011 10:20

    http://jsfiddle.net/dublinan/hjwrC/

    Here is what you suggested, its an interesting result with ES 5.  Using the Object class prototype is a great way to create public methods.

  • Andre Dublin   15 maj 2011 21:05

    Classical Inheritance Pattern with ECMAScript 5 (updated)

    http://jsfiddle.net/dublinan/eaaKL