Inheritance request for comment

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Robert Spoons

    Inheritance request for comment

    Can you look over this code, preferably try it, and comment?

    I believe the 'extend' function below will allow you to use full
    'class inheritance' in javascript, but I would like to verify it.

    The extend function allows the following:
    1) inheriting from multiple classes,
    2) inheriting an inherited classes inheritances (awkward to say),
    3) inheriting appended prototype methods and properties of inhertited
    classes.

    Thanks.

    //----------------------------------------------------------
    //rspoons
    //'extend' must have two arguments, the object to inherit and
    //an Array of arguments to supply the superclass.
    //If the superclass requires no arguments, [null] must be passed.
    Object.prototyp e.extend=functi on(){
    if(arguments[1]){ //make sure argument(s) are supplied
    for(var i=0;i<arguments[1].length;i++){
    if(typeof(argum ents[1][i])=="string")
    arguments[1][i]="'"+argumen ts[1][i]+"'"
    }
    if(arguments[1].length>0){Argu ments=arguments[1].join(",")}
    else{Arguments= arguments[1][0]}
    for(var i in eval("new arguments[0]("+Arguments+") ")){
    if(i!='extend') {
    g=eval("new "+arguments[0]+"("+argumen ts[1]+")."+i)
    if(typeof(g)==" undefined"){
    eval("this.prot otype."+i+"=new
    arguments[0]("+arguments[1]+")."+i)
    }
    else{
    eval("this.prot otype."+i+"=g")
    }
    }
    }
    }
    }
    //an oval class
    function Oval(xaxis,yaxi s){
    this.xaxis=xaxi s
    this.yaxis=yaxi s
    this.classid="o val"
    }

    //a color class
    function Color(color){
    this.color=colo r
    }
    Color.prototype .RED="#ff0000"
    Color.prototype .GREEN="#00ff00 "
    Color.prototype .BLUE="#0000ff"

    //point class - a base class
    function Point(x,y){
    this.x=x
    this.y=y
    }

    //SUBCLASSES INHERIT APPENDED CLASS METHODS AND PROPERTIES.
    Point.prototype .moveto=functio n(x,y){this.x=x ;this.y=y}
    Point.prototype .moveby=functio n(dx,dy){this.x +=dx;this.y+=dy }

    //circle class - a subclassing class
    //OBJECTS CAN INHERIT FROM MULTIPLE CLASSES.
    function Circle(radius,c olor){
    Circle.extend(O val,[radius,radius]) //inherits from the more
    generic oval class
    Circle.extend(C olor,[color]) //also inherits from the color class
    this.classid="c ircle"
    }

    //No arguments
    function CompanyTag(){
    this.company="s omeco"
    this.author="Ro bret Spoons"
    this.date="01.1 0.04"
    }

    //mycircleclass subclasses a suclassing class
    //FULL OOP CLASS INHERITANCE
    function MyCircleclass(r adius,color,x,y ){
    MyCircleclass.e xtend(Circle,[radius,color]) //Inherits from Circle
    MyCircleclass.e xtend(Point,[x,y]) //Inherits from Point
    MyCircleclass.e xtend(CompanyTa g,[null]) //Inherits from
    CompanyTag - no arguments
    this.classid="m ycircleclass"
    }

    //Simple utility method to itterate through and
    //return an objects enumerable methods and properties
    function showprops(obj){
    var s=""
    for(var i in obj)
    if(i!='extend') s+=i+": "+eval("obj."+i )+"\n"
    return s
    }

    //CONSTRUCTING THE SUBCLASSED OBJECT AND USING AN INHERITED METHOD
    mycircle=new MyCircleclass(1 3,"blue",100,12 0)
    mycircle.moveby (2,-4)
    mycircle.color= mycircle.RED
    alert("mycircle \n"+showprops(m ycircle)) //shows all enumerable methods
    and properties

    Thanks
  • Lasse Reichstein Nielsen

    #2
    Re: Inheritance request for comment

    rdspoons@poncac ity.net (Robert Spoons) writes:
    [color=blue]
    > Can you look over this code, preferably try it, and comment?[/color]

    First of all, your code is broken -- in particular some long comment
    lines are broken onto the next line :) Please make sure your newsclient
    doesn't break lines or post only lines so short that they are not broken.
    Javascript code will not survive being wrapped as well as text, and
    everybody who wants to try your code must first find and fix the errors
    your newsclient has introduced (on a good day, they try, on a bad day,
    they move on without commenting at all).
    [color=blue]
    > I believe the 'extend' function below will allow you to use full
    > 'class inheritance' in javascript, but I would like to verify it.[/color]

    Define "full class inheritance". First, define what "class" means in
    a Javascript context, where there are no classes.
    [color=blue]
    > The extend function allows the following:
    > 1) inheriting from multiple classes,
    > 2) inheriting an inherited classes inheritances (awkward to say),
    > 3) inheriting appended prototype methods and properties of inhertited
    > classes.[/color]

    If I read it correctly, it copies the properties of the prototype
    of the class and calls(applies) the constructor.

    First, code comments:
    [color=blue]
    > //If the superclass requires no arguments, [null] must be passed.[/color]

    Why not the empty array? (or nothing, you should be able to check that)
    [color=blue]
    > Object.prototyp e.extend=functi on(){[/color]

    Why not
    Function.protot ype.extend=func tion(class,args ) {
    ?
    Instead of writing arguments[0] and arguments[1] everywhere?
    [color=blue]
    > if(arguments[1]){ //make sure argument(s) are supplied[/color]
    [color=blue]
    > for(var i=0;i<arguments[1].length;i++){
    > if(typeof(argum ents[1][i])=="string")
    > arguments[1][i]="'"+argumen ts[1][i]+"'"[/color]
    What if the arguement is the Javascript string "a hen's feather"? Or
    "String literals use a \\ to write newlines\nYou just write \\n."?
    You should also escape quotes, backslashes, special characters (ASCII<32), etc.[color=blue]
    > }
    > if(arguments[1].length>0){Argu ments=arguments[1].join(",")}
    > else{Arguments= arguments[1][0]}[/color]

    All this is only necessary if you use eval. Don't use eval. Never use
    eval.
    [color=blue]
    > for(var i in eval("new arguments[0]("+Arguments+") ")){[/color]

    Use this instead (no eval):
    function classCloner () { return class.apply(thi s,args); };
    classCloner.pro totype = class.prototype ;
    var newInstance = new classCloner();
    for (var i in newInstance) {
    [color=blue]
    > if(i!='extend') {
    > g=eval("new "+arguments[0]+"("+argumen ts[1]+")."+i)[/color]

    Fails if the object has property names like "foo bar" or "2".
    Use:

    g = newInstance[i];

    Then you don't need to create a new object for each property.
    [color=blue]
    > if(typeof(g)==" undefined"){
    > eval("this.prot otype."+i+"=new
    > arguments[0]("+arguments[1]+")."+i)[/color]

    if g is undefined, you create a new object *the same way* and take
    the same property again.

    this.prototype[i]=newInstance[i];
    [color=blue]
    > }
    > else{
    > eval("this.prot otype."+i+"=g")[/color]

    this.prototype[i] = g;
    [color=blue]
    > }
    > }
    > }
    > }
    > }[/color]


    Ok, my version:

    function newApply(class, argsArray) {
    function createApply() {
    return class.apply(thi s,argsArray);
    }
    createApply.pro totype = class.prototype ;
    return new createApply();
    }

    Function.protot ype.extend = function extend(class,ar gsArray) {
    var instance = newApply(class, argsArray);
    for (var i in instance) {
    if (i != "extend") {
    this.prototype[i]=instance[i];
    }
    }
    }

    Notice that you don't extend the object with a *class*, but with an
    *instance* of the class. Already there, it breaks with how it works in
    class based object oriented languages.

    ....[color=blue]
    > //circle class - a subclassing class
    > //OBJECTS CAN INHERIT FROM MULTIPLE CLASSES.
    > function Circle(radius,c olor){
    > Circle.extend(O val,[radius,radius]) //inherits from the more
    > generic oval class
    > Circle.extend(C olor,[color]) //also inherits from the color class
    > this.classid="c ircle"
    > }[/color]

    You change the properties of the prototype inside the constructor.
    That means that if you create two objects with this constructor,
    the second one overwrites the properties of the first ones prototype.
    Since they extend with different objects, the result is wrong.

    Example

    var c1 = new Circle(2,"#ff00 00");
    var c2 = new Circle(4,"#0000 00");
    alert(c1.color) ; // gives #000000

    Either add the new properties directly to the object being created:
    I.e., here:
    this.extend(Ova l,[radius,radius]);
    and in extend:
    this[i] = instance[i];
    (that is, make objects "inherit" properties from other objects)
    or only extend the class once:
    Circle10.extend (Oval,[10,10]);

    The problem is that you want to make classes inherit from instances.
    That really doesn't make much sense, conceptually.

    And:[color=blue]
    > if(i!='extend') s+=i+": "+eval("obj."+i )+"\n"[/color]
    don't use eval:
    if(i!='extend') s+=i+": "+obj[i];

    <URL:http://jibbering.com/faq/#FAQ4_39>

    /L
    --
    Lasse Reichstein Nielsen - lrn@hotpop.com
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleD OM.html>
    'Faith without judgement merely degrades the spirit divine.'

    Comment

    • Robert Spoons

      #3
      Re: Inheritance request for comment

      Lasse Reichstein Nielsen <lrn@hotpop.com > wrote in message news:<1xq7vrmx. fsf@hotpop.com> ...[color=blue]
      > rdspoons@poncac ity.net (Robert Spoons) writes:
      >[color=green]
      > > Can you look over this code, preferably try it, and comment?[/color]
      >
      > First of all, your code is broken -- in particular some long comment
      > lines are broken onto the next line :) Please make sure your newsclient
      > doesn't break lines or post only lines so short that they are not broken.
      > Javascript code will not survive being wrapped as well as text, and
      > everybody who wants to try your code must first find and fix the errors
      > your newsclient has introduced (on a good day, they try, on a bad day,
      > they move on without commenting at all).
      >[color=green]
      > > I believe the 'extend' function below will allow you to use full
      > > 'class inheritance' in javascript, but I would like to verify it.[/color]
      >
      > Define "full class inheritance". First, define what "class" means in
      > a Javascript context, where there are no classes.
      >[color=green]
      > > The extend function allows the following:
      > > 1) inheriting from multiple classes,
      > > 2) inheriting an inherited classes inheritances (awkward to say),
      > > 3) inheriting appended prototype methods and properties of inhertited
      > > classes.[/color]
      >
      > If I read it correctly, it copies the properties of the prototype
      > of the class and calls(applies) the constructor.
      >
      > First, code comments:
      >[color=green]
      > > //If the superclass requires no arguments, [null] must be passed.[/color]
      >
      > Why not the empty array? (or nothing, you should be able to check that)
      >[color=green]
      > > Object.prototyp e.extend=functi on(){[/color]
      >
      > Why not
      > Function.protot ype.extend=func tion(class,args ) {
      > ?
      > Instead of writing arguments[0] and arguments[1] everywhere?
      >[color=green]
      > > if(arguments[1]){ //make sure argument(s) are supplied[/color]
      >[color=green]
      > > for(var i=0;i<arguments[1].length;i++){
      > > if(typeof(argum ents[1][i])=="string")
      > > arguments[1][i]="'"+argumen ts[1][i]+"'"[/color]
      > What if the arguement is the Javascript string "a hen's feather"? Or
      > "String literals use a \\ to write newlines\nYou just write \\n."?
      > You should also escape quotes, backslashes, special characters (ASCII<32), etc.[color=green]
      > > }
      > > if(arguments[1].length>0){Argu ments=arguments[1].join(",")}
      > > else{Arguments= arguments[1][0]}[/color]
      >
      > All this is only necessary if you use eval. Don't use eval. Never use
      > eval.
      >[color=green]
      > > for(var i in eval("new arguments[0]("+Arguments+") ")){[/color]
      >
      > Use this instead (no eval):
      > function classCloner () { return class.apply(thi s,args); };
      > classCloner.pro totype = class.prototype ;
      > var newInstance = new classCloner();
      > for (var i in newInstance) {
      >[color=green]
      > > if(i!='extend') {
      > > g=eval("new "+arguments[0]+"("+argumen ts[1]+")."+i)[/color]
      >
      > Fails if the object has property names like "foo bar" or "2".
      > Use:
      >
      > g = newInstance[i];
      >
      > Then you don't need to create a new object for each property.
      >[color=green]
      > > if(typeof(g)==" undefined"){
      > > eval("this.prot otype."+i+"=new
      > > arguments[0]("+arguments[1]+")."+i)[/color]
      >
      > if g is undefined, you create a new object *the same way* and take
      > the same property again.
      >
      > this.prototype[i]=newInstance[i];
      >[color=green]
      > > }
      > > else{
      > > eval("this.prot otype."+i+"=g")[/color]
      >
      > this.prototype[i] = g;
      >[color=green]
      > > }
      > > }
      > > }
      > > }
      > > }[/color]
      >
      >
      > Ok, my version:
      >
      > function newApply(class, argsArray) {
      > function createApply() {
      > return class.apply(thi s,argsArray);
      > }
      > createApply.pro totype = class.prototype ;
      > return new createApply();
      > }
      >
      > Function.protot ype.extend = function extend(class,ar gsArray) {
      > var instance = newApply(class, argsArray);
      > for (var i in instance) {
      > if (i != "extend") {
      > this.prototype[i]=instance[i];
      > }
      > }
      > }
      >
      > Notice that you don't extend the object with a *class*, but with an
      > *instance* of the class. Already there, it breaks with how it works in
      > class based object oriented languages.
      >
      > ...[color=green]
      > > //circle class - a subclassing class
      > > //OBJECTS CAN INHERIT FROM MULTIPLE CLASSES.
      > > function Circle(radius,c olor){
      > > Circle.extend(O val,[radius,radius]) //inherits from the more
      > > generic oval class
      > > Circle.extend(C olor,[color]) //also inherits from the color class
      > > this.classid="c ircle"
      > > }[/color]
      >
      > You change the properties of the prototype inside the constructor.
      > That means that if you create two objects with this constructor,
      > the second one overwrites the properties of the first ones prototype.
      > Since they extend with different objects, the result is wrong.
      >
      > Example
      >
      > var c1 = new Circle(2,"#ff00 00");
      > var c2 = new Circle(4,"#0000 00");
      > alert(c1.color) ; // gives #000000
      >
      > Either add the new properties directly to the object being created:
      > I.e., here:
      > this.extend(Ova l,[radius,radius]);
      > and in extend:
      > this[i] = instance[i];
      > (that is, make objects "inherit" properties from other objects)
      > or only extend the class once:
      > Circle10.extend (Oval,[10,10]);
      >
      > The problem is that you want to make classes inherit from instances.
      > That really doesn't make much sense, conceptually.
      >
      > And:[color=green]
      > > if(i!='extend') s+=i+": "+eval("obj."+i )+"\n"[/color]
      > don't use eval:
      > if(i!='extend') s+=i+": "+obj[i];
      >
      > <URL:http://jibbering.com/faq/#FAQ4_39>
      >
      > /L[/color]

      /*
      Lasse Reichstein Nielsen, Thanks for your commentary - it did help.
      I will be more specific in the wording I choose.
      I still use eval in the function.

      Thanks, I've updated the extend function - it addresses all relavent
      points you made concerning the origional, and it now acts the way I
      desire the function to act.
      Also, the new version is much cleaner.
      The function will add all publically enumarable properties and methods
      of the specified target object to the calling object (effective
      inheritance). I have attempted to include example use.
      */

      /*
      --------------------------
      Much cleaner Inheritence function
      Use :must be inside of object's constructor
      this.extend(new ObjA(args))
      (The object Inherits all enumerable properties and methods of ObjA)
      */
      // obj is the object instance to inherit from
      // i is an Enumerable Property or Method
      // insta is a Property or Method Instance
      Object.prototyp e.extend=functi on(obj){
      for(var i in obj){
      insta=eval("obj ."+i)
      eval("this."+i+ "=insta")
      }
      }
      /*
      --------------------------
      */
      function point(x,y){
      this.x=x
      this.y=y
      }
      function location(x,y){
      this.extend(new point(x,y))
      }
      location.protot ype.moveTo=func tion(x,y){this. x=x;this.y=y}

      function oval(xrad,yrad) {
      this.radiusX=xr ad
      this.radiusY=yr ad
      }
      oval.prototype. meth=function() {alert("ok")}

      function circle(rad,colo r){
      this.extend(new oval(rad,rad))
      this.color=colo r
      }
      circle.prototyp e.area=function (){return
      2*Math.PI*Math. pow(this.radius X,2)}

      function myCircle(rad,co lor,x,y){
      this.extend(new circle(rad,colo r))
      this.extend(new location(x,y))
      }

      Object.prototyp e.showProps=fun ction(){
      var s=""
      for(var i in this)
      if(!(i=='extend '||i=='showProp s'))s+=i +": "+eval("this."+ i)+"\n"
      return s
      }
      a=new myCircle(3,"the hen's blue feather \n",5,10)
      b=new myCircle(10,"re d",100,120)
      c=new oval(4,5)
      alert("a\n"+a.s howProps()+"\nb \n"+b.showProps ()+"\nc\n"+c.sh owProps())
      alert("a area = "+a.area() +"\nb area = "+b.area())

      Comment

      • Lasse Reichstein Nielsen

        #4
        Re: Inheritance request for comment

        rdspoons@poncac ity.net (Robert Spoons) writes:

        Please trim the quotes :)
        [color=blue]
        > Use :must be inside of object's constructor
        > this.extend(new ObjA(args))[/color]

        Why? You can always call
        someObject.exte nd(someOtherObj ect)
        [color=blue]
        > // insta is a Property or Method Instance[/color]

        You don't declare insta as a local variable.

        [color=blue]
        > I still use eval in the function.[/color]
        [color=blue]
        > insta=eval("obj ."+i)
        > eval("this."+i+ "=insta")[/color]

        Why not just
        this[i] = obj[i];
        It is equivalent when the property name is a valid identifier,
        and, unlike your version, it works when it is not.

        /L
        --
        Lasse Reichstein Nielsen - lrn@hotpop.com
        DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleD OM.html>
        'Faith without judgement merely degrades the spirit divine.'

        Comment

        • Douglas Crockford

          #5
          Re: Inheritance request for comment

          What advantage is there to using

          Object.prototyp e.extend=functi on(obj){
          for(var i in obj){
          insta=eval("obj ."+i)
          eval("this."+i+ "=insta")
          }
          }

          instead of

          Object.prototyp e.extend = function(obj){
          for (var i in obj){
          this[i] = obj[i];
          }
          };

          Comment

          • Robert Spoons

            #6
            Re: Inheritance request for comment

            > Object.prototyp e.extend = function(obj){[color=blue]
            > for (var i in obj){
            > this[i] = obj[i];
            > }
            > };[/color]
            This is it. Thanks.

            Comment

            Working...