SitePoint Sponsor

User Tag List

Results 1 to 2 of 2
  1. #1
    SitePoint Member
    Join Date
    Mar 2013
    Posts
    1
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Utility Module for Object Inheritance in JavaScript

    I have wrote a utility module for Object Inheritance in JavaScript
    Here is the Full Source Code.
    Code JavaScript:
    (function(){
    window.MUI=window.MUI || {};
    MUI.object=MUI.object ||
    	{
    		is:function(){
    			if(arguments.length<1)
    				throw "This function need at least one parameter.";
    			var b=true;
    			for(var i=0,len=arguments.length;i<len;i++){
    				if(typeof arguments[i]!=="object")
    					throw "The parameter "+i+"("+arguments[i]+") is expected to be an object.";
    				for(var o in arguments[i]){
    					if(!this[o]){
    						b=false;
    						break;
    					}
    				}
    				if(!b)
    					break;
    			}
    			return b;
    		},
    		become:function(){
    			if(arguments.length<1)
    				throw "This function need at least one parameter.";
    			for(var i=0,len=arguments.length;i<len;i++){
    				if(typeof arguments[i]!=="object")
    					throw "The parameter "+i+"("+arguments[i]+") is expected to be an object.";
    				for(var o in arguments[i])
    					this[o]=this[o]||arguments[i][o];
    			}
    			return this;
    		},
    		derive:function(){
    			var F=function(){};
    			F.prototype=this;
    			var res=new F;
    			for(var i=0,len=arguments.length;i<len;i++){
    				if(typeof arguments[i]!=="object")
    					throw "The parameter "+i+"("+arguments[i]+") is expected to be an object.";
    				for(var o in arguments[i])
    					res[o]=arguments[i][o];
    			}
    			return res;
    		}
    	};
    })();
    It's very easy to use.
    If you want to create a top-most person class with name property, you can write like bellow.
    Code JavaScript:
    var Person=MUI.object.derive({name:"Undefined Name"});
    Then, if you want to derive some classes from the class...
    Code JavaScript:
    var Teacher=Person.derive({subjects:[]});
    var Author=Person.derive({books:[]});
    var Seller=Person.derive({items:[]});
    You can also derive a class from multiple classes...
    Code JavaScript:
    var TeacherAndSeller=Teacher.derive(Seller);
    You can create an object from a class...
    Code JavaScript:
    var teacher=Teacher.derive({
    	name:"Peter Smith",
    	subjects:["Physics","Mathematics"]);
    A teacher may become an author...
    Code JavaScript:
    teacher.become(
    	Author.derive({
    		books:["Principle of Physics", "Applied Mathematics"]
    	})
    );
    is function is very useful...
    Code JavaScript:
    alert(Author.is(Person)); //true
    alert(Teacher.is(Person)); //true
    alert(Seller.is(Person)); //true
    alert(TeacherAndSeller.is(Teacher)); //true
    alert(TeacherAndSeller.is(Seller)); //true
    alert(Author.is(Teacher)); //false
    alert(teacher.is(Teacher)); //true
    alert(teacher.is(Author)); //true
    alert(teacher.is(Seller)); //false
    alert(teacher.is(Person)); //true
    That's all of it.
    How do you feel about this?
    Please visit my link.

  2. #2
    SitePoint Wizard bronze trophy Jeff Mott's Avatar
    Join Date
    Jul 2009
    Posts
    1,265
    Mentioned
    18 Post(s)
    Tagged
    0 Thread(s)
    I like that you were able to factor out constructor functions. Instead, types are just plain objects that inherit from other plain objects. I used that style myself once. The downside, however, is that after all the JavaScript browser optimizations that have been happening over the past few years, the native constructor function style got the lion's share of the optimizations, so this plain object style unfortunately won't run as fast. And since derived objects will likely permeate every aspect of an application, this turns out to make a significant difference.

    Some other pitfalls to look out for:

    1) IE8 won't copy property names that it considers non-enumerable. So, for example, toString won't copy.

    Code JavaScript:
    var Person = MUI.object.derive({
        name: "John Doe",
        toString: function () {
            return this.name;
        }
    });

    2) The "is" method seems to work entirely through duck typing. That can lead to an awful lot of false positives. For example:

    Code JavaScript:
    var HexEncoder = MUI.object.derive({
        parse: function () {
            // parse a hex string into bytes
        },
     
        stringify: function () {
            // stringify bytes into a hex string
        }
    });
     
    var Base64Encoder = MUI.object.derive({
        parse: function () {
            // parse a base64 string into bytes
        },
     
        stringify: function () {
            // stringify bytes into a base64 string
        }
    });
     
    // Is it true that HexEncoder *is* Base64Encoder?
    alert(HexEncoder.is(Base64Encoder));
    // MUI says yes
     
    // Is it true that Base64Encoder *is* JSON
    alert(Base64Encoder.is(JSON));
    // MUI says yes
     
    // These objects share similarly named methods,
    // but that doesn't necessarily mean they're related

    3) If your library gets shared enough, then eventually someone will try to use it in NodeJS or some other non-browser environment, where the "window" object doesn't exist. If you're not interacting with a browser DOM, then it's better to not reference window. The module pattern is usually better.

    Code JavaScript:
    var MUI = MUI || (function(){
        var MUI = {};
        MUI.object={
            // ...
        };
     
        return MUI;
    })();

    This pattern also comes with some extra perks. It plays nice with JavaScript module managers. Sometimes you want a library, such as MUI, to be scoped to only a defined module, or only to some other private scope. Declaring your library with just a simple "var" allows your library to exist in whatever scope the user wants it to exist in.

    A couple other suggestions:

    It would be nice if there was a defined place for object initialization. Normally that would be handled in a constructor. But since you don't have constructors anymore, you'll need to provide some kind of alternative.

    The JavaScript community has largely settled on certain style guidelines, sometimes for readability, and sometimes for code safety. I'd recommend running your code through JSHint and consider it's suggestions.
    "First make it work. Then make it better."


Tags for this Thread

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
  •