SitePoint Sponsor

User Tag List

Results 1 to 9 of 9
  1. #1
    SitePoint Addict
    Join Date
    Nov 2008
    Location
    Thailand
    Posts
    329
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)

    literal inherit from a literal?

    I know this can be cheated in some browsers by setting __proto__, but what is the best way to setup one literal to be the prototype for another?

    So far I can only think of making a copy into a constructor. Is there a more efficient way?

    Code JavaScript:
    var meths = { 
      // creates a constructor function populated with a shallow copy of child
      // the prototype for the new instance is set to the parent.  
      extend : function(parent, child){
        var F = function(){
          for (var prop in child){
    	    if (child.hasOwnProperty(prop)){
    		  this[prop] = child[prop];
    		}
    	  }
        }
        F.prototype = parent;
        return new F();
      },
     
      bind : function(func, context){
        return function(){
          func.apply(context, arguments);
        }
      }
    };

    Test:
    Code JavaScript:
    var timerTest = meths.extend( meths, { 
      bindFN : function(func, context){
    	return this.bind(func, context)
      },
     
      setTimer : function(){
    	var o = this, x = 0, timer;
        var boundFN = o.bindFN(timerGo, this);
    	// a very simple setTimeout counter.
    	function timerGo(){
    	  console.log(x++);
    	  timer = setTimeout(boundFN, 500);
    	  if (x > 5) { clearTimeout(timer); timer = null; }
    	}
    	boundFN();
      }
    });
     
    console.log (timerTest);
    timerTest.setTimer();

    Thanks

    RLM

  2. #2
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by RLM2008 View Post
    I know this can be cheated in some browsers by setting __proto__, but what is the best way to setup one literal to be the prototype for another?
    I think that it may be about the only way, but there are ways to encapsulate such techniques in to first-class functions that help to automate the process.

    Crockford was talking about this recently in this video:
    Crockford on JavaScript -- Act III: Function the Ultimate (slides)

    Page 53 of his slides starts off the protypal inheritence part, with page 54 of the slide showing the new_constructor function.

    That new_constructor() function only works though in the highly rarified atmosphere of JavaScript version 1.85.

    I'll post shortly with a solution that works across todays web browsers.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  3. #3
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Here's how to get a new_constructor function working on todays modern web browsers.

    First, you'll need some compatibility code for Object.create() and Array.forEach()

    Code javascript:
    if (typeof Object.create != "function") {
      Object.create = function (o) {
        if (arguments.length > 1) { 
          throw Error('second argument is not supported'); 
        }
        function F(){}
        F.prototype = o;
        return new F;
      };
    }
    if (!Array.prototype.forEach) {
        Array.prototype.forEach = function(fun /*, thisp */) {
            "use strict";
            if (this === void 0 || this === null) {
                throw new TypeError();
            }
            var t = Object(this);
            var len = t.length >>> 0;
            if (typeof fun !== "function") {
                throw new TypeError();
            }
            var thisp = arguments[1];
            for (var i = 0; i < len; i++) {
                if (i in t) {
                    fun.call(thisp, t[i], i, t);
                }
            }
        };
    }

    The compatibilty code for Object.key() I wasn't able to get working on the methods, so I've updated new_constructor() to use for...in instead, with a hasOwnProperty check.

    This works on all modern web browsers. Internet Explorer has trouble where the method replaces a pre-existing method, such as toString. I don't know how to fix that for IE yet.

    Code javascript:
     
    function new_constructor(extend, initializer, methods) {
        var key,
            func,
            prototype = Object.create(extend && extend.prototype);
        if (methods) {
            for (key in methods) {
                if (methods.hasOwnProperty(key)) {
                    prototype[key] = methods[key];
                }
            }
        }
        func = function () {
            var that = Object.create(prototype);
            if (typeof initializer === 'function') {
                initializer.apply(that, arguments);
            }
            return that;
        };
        func.prototype = prototype;
        prototype.constructor = func;
        return func;
    }

    Now you can create new objects, the gizmo, or create other ones that inherit from other objets, the hoozit.

    Code javsacript:
     
    var gizmo = new_constructor(Object, function (id) {
        this.id = id;
    }, {
        toString: function () {
            return "gizmo " + this.id;
        }
    });
     
    var hoozit = new_constructor(gizmo, function (id) {
        this.id = id;
    }, {
        test: function (id) {
            return this.id === id;
        }
    });
    var giz = gizmo('giz');
    var hoo = hoozit('hoo');
    alert(hoo.test('hoo'));
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  4. #4
    SitePoint Addict
    Join Date
    Nov 2008
    Location
    Thailand
    Posts
    329
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Well done again pwm, fair play to you.

    A lot to work through there

    I actually ended up on John Resig's page http://ejohn.org/blog/ecmascript-5-o...nd-properties/ trying to figure out the internals of object.create etc.

    One implementation he gives is this

    Code:
    Object.create = function( proto, props ) {
      var ctor = function( ps ) {
        if ( ps )
          Object.defineProperties( this, ps );
      };
      ctor.prototype = proto;
      return new ctor( props );
    };
    Object.defineProperties is interesting. However if that newer method is available then wouldn't the generic Object.create also be available.

    The other thing that stood out to me from Crockfords code is

    (extend && extend.prototype)

    extend can't be an object literal then?

    Will have another look at this in the morning.

    Thank you very much

    RLM

  5. #5
    SitePoint Addict
    Join Date
    Nov 2008
    Location
    Thailand
    Posts
    329
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    The compatibilty code for Object.key() I wasn't able to get working on the methods, so I've updated new_constructor() to use for...in instead, with a hasOwnProperty check.
    That seems right to me.

    The compatibility code I found uses a for in loop anyway and pushes it into an array. You then loop through that array with for each. So basically 2 loops.

    RLM

  6. #6
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by RLM2008 View Post
    Object.defineProperties is interesting. However if that newer method is available then wouldn't the generic Object.create also be available.
    That's right it would. It doesn't make much sense that code form John Rezig, which is a shame because normally I hold him in high esteem.

    Quote Originally Posted by RLM2008 View Post
    The other thing that stood out to me from Crockfords code is

    (extend && extend.prototype)

    extend can't be an object literal then?
    No it can't. The purpose of Crockfords new_constructor is to construct a new object by prototyping from either the universal Object itself, or from some other object.

    You can though create a new object using an object literal to contain its properties and methods, by using the gizmo example from the code.

    Code javascript:
    var gizmo = new_constructor(Object, function (id) {
        this.id = id;
    }, {
        property1: 'foo',
        property2: 'bar',
        method1: function () {
            return "gizmo " + this.id;
        },
        method2: function () {
            ...
        }
    });

    It's not possible to extend directly from object literals, as they don't have prototypes or constructs just by themself, which I have just realized, is also why the Object.keys() compatibility code doesn't want to work with the object literals in the methods variable.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  7. #7
    SitePoint Addict
    Join Date
    Nov 2008
    Location
    Thailand
    Posts
    329
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    I'm going to come back to the Douglas Crockford code, but for starters I'm interested in the array forEach compatibility code posted.

    I've been looking through the ECMA docs and can see it ties in with that, but still a few questions.

    First void 0? Not really clear on void.

    Second why Object(this)?
    1.
    Let O be the result of calling ToObject passing the this value as the argument.


    Third var len = t.length >>> 0;
    I'm guessing that shift right with zero fill is doing this 3. Let len be ToUint32(lenValue).

    Why do you need to convert length to a 32 bit?

    RLM

  8. #8
    Unobtrusively zen silver trophybronze trophy
    paul_wilkins's Avatar
    Join Date
    Jan 2007
    Location
    Christchurch, New Zealand
    Posts
    14,729
    Mentioned
    104 Post(s)
    Tagged
    4 Thread(s)
    Quote Originally Posted by RLM2008 View Post
    First void 0? Not really clear on void.
    It just means that it's not provided. You'll often see ancient javsacript code setting the onclick event to "javascript:void(0)"

    Quote Originally Posted by RLM2008 View Post
    Second why Object(this)?
    Quote Originally Posted by RLM2008 View Post
    Why do you need to convert length to a 32 bit?
    ECMAScript 262 is not just for JavaScript, but for other things as well. The convert length part for example is in direct response to an issue brought up by Andrew Hunt in relation to VoiceXML
    http://www.w3.org/TR/2006/WD-voicexm...sp.html#R114-4

    By following the specifications from ECMAScript 262 Version 5, you're guaranteed that the code will work all the time as expected across different environments, even if they may not have much effect on the domain of JavaScript itself.
    Last edited by paul_wilkins; Nov 27, 2010 at 22:46.
    Programming Group Advisor
    Reference: JavaScript, Quirksmode Validate: HTML Validation, JSLint
    Car is to Carpet as Java is to JavaScript

  9. #9
    SitePoint Addict
    Join Date
    Nov 2008
    Location
    Thailand
    Posts
    329
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Ok thanks for that.

    By following the specifications from ECMAScript 262 Version 5, you're guaranteed that the code will work all the time as expected across different environments, even if they may not have much effect on the domain of JavaScript itself.
    Sure that makes sense.

    I'll check out the link you provided as well.

    Cheers

    RLM


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •