Prototype behavior

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Roberto Sileoni

    Prototype behavior

    While i was trying to understand prototype behavior,
    i wrote this sample code:

    function MyString() {
    }

    MyString.protot ype = new String()

    var a=new MyString("aaaaa ");
    alert(a.valueOf ());

    When i run this code on Firefox it raise an error like this:
    String.prototyp e.valueOf called on incompatible object.

    Can someone help me to understand what happens and why this code
    does not work.

    Thanks a lot and sorry for my english.

  • Michael Winter

    #2
    Re: Prototype behavior

    On 25/05/2005 00:39, Roberto Sileoni wrote:

    [snip]
    [color=blue]
    > function MyString() {
    > }
    >
    > MyString.protot ype = new String()
    >
    > var a=new MyString("aaaaa ");
    > alert(a.valueOf ());
    >
    > When i run this code on Firefox it raise an error like this:
    > String.prototyp e.valueOf called on incompatible object.[/color]

    Certain predefined methods are considered generic; they can be used with
    any object. For example, calling charAt (another String method) on
    MyString should pose no problems as charAt will convert the MyString
    instance to a string value, and then return the character at the given
    offset.

    However, some methods are not transferable; if they are called from an
    object that is not of the correct type, the ECMAScript engine with throw
    a TypeError exception. The String.prototyp e.valueOf method is one such
    non-transferable method.

    User-defined objects, such as MyString, will always be Object instances.
    You can give them prototypes of other built-in types, but they will
    still be Objects.

    [snip]

    Does that help at all?

    Mike

    --
    Michael Winter
    Replace ".invalid" with ".uk" to reply by e-mail.

    Comment

    • Grant Wagner

      #3
      Re: Prototype behavior

      "Michael Winter" <m.winter@bluey onder.co.invali d> wrote in message
      news:maPke.3912 0$G8.9494@text. news.blueyonder .co.uk...[color=blue]
      > On 25/05/2005 00:39, Roberto Sileoni wrote:
      >
      > [snip]
      >[color=green]
      >> function MyString() {
      >> }
      >>
      >> MyString.protot ype = new String()
      >>
      >> var a=new MyString("aaaaa ");
      >> alert(a.valueOf ());
      >>
      >> When i run this code on Firefox it raise an error like this:
      >> String.prototyp e.valueOf called on incompatible object.[/color]
      >
      > Certain predefined methods are considered generic; they can be used
      > with any object. For example, calling charAt (another String method)
      > on MyString should pose no problems as charAt will convert the
      > MyString instance to a string value, and then return the character at
      > the given offset.[/color]

      Nope:

      function MyString() { }
      MyString.protot ype = new String();
      var a = new MyString("aaaaa ");
      alert(a.charAt( 1)); // Line 14

      Error: String.prototyp e.toString called on incompatible Object
      Source File: file:///c:/DOCUME~1/grantw/LOCALS~1/Temp/hs~new.htm
      Line: 14

      The only solution to this is to wrap a String object inside your object
      and expose the methods you want to allow on your object:

      function MyString(newStr ing) {
      var s = newString;
      this.charAt = function(n) { return s.charAt(n); }
      }
      var a = new MyString("aaaaa ");
      alert(a.charAt( 1));

      But if you're going to that, you might as well just write a factory
      "class":

      var MyStringFactory = new function() {
      this.getInstanc e = function(newStr ing) {
      var s = new String(newStrin g);
      s.repeat = function(n) {
      return (new Array(n + 1)).join(this);
      }
      s.trimRight = function() {
      return this.replace(/\s$/, '');
      }
      s.trimLeft = function() {
      return this.replace(/^\s/, '');
      }
      s.trim = function() {
      return this.trimRight( ).trimLeft();
      }
      return s;
      }
      }();
      var a = MyStringFactory .getInstance("a bc");
      alert(a.valueOf () + ';' + a.repeat(5));

      This is probably something like how I'd do it. You can now "extend" the
      String class however you want without sacrificing any built-in
      functionality. Instead of making an object that "looks like" a String,
      you're creating a String with additional properties/methods.

      --
      Grant Wagner <gwagner@agrico reunited.com>
      comp.lang.javas cript FAQ - http://jibbering.com/faq


      Comment

      • Michael Winter

        #4
        Re: Prototype behavior

        On 25/05/2005 16:31, Grant Wagner wrote:
        [color=blue]
        > "Michael Winter" <m.winter@bluey onder.co.invali d> wrote in message
        > news:maPke.3912 0$G8.9494@text. news.blueyonder .co.uk...[/color]

        [snip]
        [color=blue][color=green]
        >> Certain predefined methods are considered generic; they can be used
        >> with any object. [...][/color]
        >
        > Nope:
        >
        > function MyString() { }
        > MyString.protot ype = new String();
        > var a = new MyString("aaaaa ");
        > alert(a.charAt( 1)); // Line 14[/color]

        You aren't providing any mechanism to get at that value passed to the
        constructor. The Object.prototyp e.toString method that would be used by
        String.prototyp e.charAt no longer exists on that object. Instead, it
        would use String.prototyp e.toString, which, like
        String.prototyp e.valueOf, is a non-transferable method.

        If you change the constructor to:

        function MyString(value) {
        this.toString = function() {return value;};
        }

        then the charAt method works just fine.

        [snip]

        Mike

        --
        Michael Winter
        Replace ".invalid" with ".uk" to reply by e-mail.

        Comment

        • Grant Wagner

          #5
          Re: Prototype behavior

          "Michael Winter" <m.winter@bluey onder.co.invali d> wrote in message
          news:ni1le.3945 7$G8.8955@text. news.blueyonder .co.uk...[color=blue]
          > On 25/05/2005 16:31, Grant Wagner wrote:
          >[color=green]
          >> "Michael Winter" <m.winter@bluey onder.co.invali d> wrote in message
          >> news:maPke.3912 0$G8.9494@text. news.blueyonder .co.uk...[/color]
          >
          > [snip]
          >[color=green][color=darkred]
          >>> Certain predefined methods are considered generic; they can be used
          >>> with any object. [...][/color]
          >>
          >> Nope:
          >>
          >> function MyString() { }
          >> MyString.protot ype = new String();
          >> var a = new MyString("aaaaa ");
          >> alert(a.charAt( 1)); // Line 14[/color]
          >
          > You aren't providing any mechanism to get at that value passed to the
          > constructor. The Object.prototyp e.toString method that would be used
          > by String.prototyp e.charAt no longer exists on that object. Instead,
          > it would use String.prototyp e.toString, which, like
          > String.prototyp e.valueOf, is a non-transferable method.
          >
          > If you change the constructor to:
          >
          > function MyString(value) {
          > this.toString = function() {return value;};
          > }
          >
          > then the charAt method works just fine.[/color]

          Hmm. Well in that case:

          function MyString(value) {
          if (value == null) {value = 'blah';}
          this.toString = function() {return value;}
          this.valueOf = function() {return value.valueOf() ;}
          }
          MyString.protot ype = new String();
          var s = new MyString(0);
          alert(s.valueOf ());

          However, you still need to wrap any other methods and properties that
          won't work properly (like I did with valueOf()). It also just occurred
          to me that in my "factory class" example you don't need
          a -MyStringFactory- at all:

          String.getInsta nce = function(newStr ing) {
          var s = new String(newStrin g);
          // ...
          }
          var s = String.getInsta nce("abc");


          Decisions, decisions. I think I still lean towards having a factory
          method on the String object rather than creating a new custom object
          type but I'll have to think about it a bit.

          --
          Grant Wagner <gwagner@agrico reunited.com>
          comp.lang.javas cript FAQ - http://jibbering.com/faq


          Comment

          Working...