with and prototype

Discussion in 'Javascript' started by Robert, Aug 24, 2005.

  1. Robert

    Robert Guest

    Hi,

    I can use "with" like this:

    function MyObject(message)
    {
    this.message = message;
    }
    function _MyObject_speak()
    {
    alert(this.message);
    }

    with (MyObject)
    {
    prototype.speak = _MyObject_speak;
    }


    I was wondering why I can't use "with" like this:

    with (MyObject.prototype)
    {
    speak = _MyObject_speak;
    }
    Robert, Aug 24, 2005
    #1
    1. Advertising

  2. Robert

    web.dev Guest

    Robert wrote:
    > Hi,
    >
    > I can use "with" like this:
    >
    > function MyObject(message)
    > {
    > this.message = message;
    > }
    > function _MyObject_speak()
    > {
    > alert(this.message);
    > }
    >
    > with (MyObject)
    > {
    > prototype.speak = _MyObject_speak;
    > }
    >
    >
    > I was wondering why I can't use "with" like this:
    >
    > with (MyObject.prototype)
    > {
    > speak = _MyObject_speak;
    > }


    Hi Robert,

    When you use with(MyObject), you're accessing properties of MyObject
    within that scope. Therefore, extending MyObject is valid.

    However, when you use with(MyObject.prototype), you're accessing
    properties of MyObject.prototype within that scope. Therefore, you're
    not performing extensions to your MyObject.

    :) So you just misunderstood the behavior of the with statement.

    Hope this helps.
    web.dev, Aug 24, 2005
    #2
    1. Advertising

  3. Robert wrote:
    <snip>
    > I can use "with" like this:


    Be aware that the - with - statement is a part of javascript that some
    informed opinion would like to see eliminated from the language
    entirely, resulting in its use being strongly discouraged.

    I don't hold such a strong opinion on the subject, but I find that I
    have little use for the - with - statement. There is one interesting use
    for it in deliberately augmenting the scope chains of function
    expressions evaluate in a - with - statement (an alternative to using
    closures, or a different sort of closure, depending on how you look at
    it). But that is very far from an everyday requirement (and there are
    issues with older language implementations) and apart from that the use
    of - with - statements just seems to render source code obscure.

    The supporters of the - with - statement point out that it can reduce
    script size (and/or typing), but there are other ways of doing that
    (with at least equally obscure results).

    > function MyObject(message)
    > {
    > this.message = message;
    > }
    > function _MyObject_speak()
    > {
    > alert(this.message);
    > }
    >
    > with (MyObject)
    > {
    > prototype.speak = _MyObject_speak;
    > }


    You can do that, but I don't see any reason for doing so. Assigning
    methods to prototypes is clearly and easily achieved with statements
    such as:-

    MyObject.prototype.speak = function(arg1, arg2){
    ... //function body
    };

    - or entire prototypes compactly defined as:-

    MyObject.prototype = {
    speak:function(arg1, arg2){
    ... //function body
    },
    act:function(){
    ... //function body
    },
    ... // etc.
    };

    > I was wondering why I can't use "with" like this:


    The - with - statement acts by evaluating its expression
    (MyObject.prototype in this case,) type-converting the result into an
    object (no conversion is necessary if the expression resolves as an
    object, which is expected in the case of - MyObject.prototype -), and
    then adding that object to the top of the current execution context's
    scope chain for the duration of the evaluation of the statement that
    follows (which may be, and usually would be, a Block statement
    containing other statements).

    Unqualified Identifiers are resolved against the scope chain of the
    current execution contexts (ECMA 262 3rd edition; section 10.1.4). The
    object at the top of the scope chain is examined to see if it has a
    property with a name that corresponds with the Identifier. If it does
    then the Identifier is resolved as a reference to that object using the
    name that was found.

    In the terms of the specification; an instance of the internal Reference
    type is returned that has the object as its 'base object' and the
    corresponding property name as its 'property name' (ECMA 262, 3rd
    edition; section 8.7). This Reference type instance is used to target
    assignment ( [[Put]] ) operations and to source retrieval ( [[Get]] )
    operations, and is an internal intermediate result used in resolving
    expressions in place of the original Identifier.

    If the object does not have a property with a corresponding name then
    the next object in the scope chain undergoes a similar examination. This
    goes on until either one of the objects on the scope chain is found with
    a correspondingly named property, or the scope chain comes to an end
    (scope chains are always finite by specification).

    If Identifier resolution against the scope chain cannot resolve an
    Identifier (it gets to the end of the scope chain without finding a
    property with the corresponding name on any of the objects in the chain)
    then a Reference type is returned that has a null 'base object' (the
    property name still corresponds with the Identifier).

    When a Reference type with a null 'base object' is used to target or
    source an operation the global object is used in place of null. Thus any
    unresolved Identifiers become references to non-existent properties of
    the global object. (the global object is always the last object on any
    scope chain so if the global object already had a property with the
    corresponding name the scope chain resolution of the identifier would
    succeed, resulting in a Reference type with the global object as its
    'base object'. Though such a resolution is practically indistinguishable
    from a Reference type that has a null 'base object').

    So assigning to an unresolved, unqualified, Identifier results in the
    creation of a new named property of the global object and the assignment
    of the value to that property.

    > with (MyObject.prototype)
    > {
    > speak = _MyObject_speak;
    > }


    This does not have the desired effect because - MyObject.prototype -
    does not have a property named "speak". The Identifier "speak" is not
    resolved as a named property of any object on the scope chain
    (including - MyObject.prototype -) and so the assignment results in the
    creation of a new property of the global object named "speak" and the
    value is assigned to that property.

    if - MyObject.prototype - did have a "speak" property, e.g.:-

    MyObject.prototype = {
    speak:null
    };

    - then:-

    with(MyObject.prototype){
    speak = _MyObject_speak;
    }

    - would have succeeded, as the scope chain resolution of the Identifier
    "speak" would find that the - MyObject.prototype - object at the top of
    the scope chain did have a correspondingly named property and so the
    intermediate Reference type would have - MyObject.prototype - as its
    'base object' and "speak" as its 'property name'. The value would be
    assigned to - MyObject.prototype.speak -.

    It is at least in part this unobvious behaviour, in comparison to:-

    MyObject.prototype.speak = _MyObject_speak;

    - and the like, that encourages the deprecating attitude towards the -
    with - statement.

    For completeness; the issue that I mentioned above with older
    implementations is that the scope chain resolution of Identifiers is
    specified (in ECMA 262 3rd edition (only)) as including the prototype of
    objects on the scope chain. I.E. an object on the scope chain is
    considered to have a correspondingly named property if it, or its
    prototype, or its prototype's prototype (and so on) has a property with
    the name. Older implementations (Netscape 4 is a specific example) do
    not necessarily consider the prototypes in scope chain resolution of
    Identifiers. Thus:-

    with(MyObject.prototype){
    toString = _alternative_toString;
    }

    - will assign a - toString - method to - MyObject.prototype - on an ECMA
    262 3rd edition implementation because -
    MyObject.prototype.prototype.toString - exists (the - toString - method
    of - Object.prototype -), but Netscape 4 instead assigns the method to
    the global object, oblivious to its - Object.prototype.toString -.

    Richard.
    Richard Cornford, Aug 24, 2005
    #3
  4. Richard Cornford wrote:
    <snip>
    > When a Reference type with a null 'base object' is used to
    > target or source an operation the global object is used in
    > place of null.

    <snip>

    That isn't strictly true. A Reference type with a null 'base object'
    will throw an exception when used to source a value, only assignment
    uses the global object in place of null.

    Richard.
    Richard Cornford, Aug 25, 2005
    #4
  5. Robert

    Robert Guest

    web.dev wrote:
    > Robert wrote:
    >
    >>Hi,
    >>
    >>I was wondering why I can't use "with" like this:
    >>
    >>with (MyObject.prototype)
    >>{
    >> speak = _MyObject_speak;
    >>}

    >
    > However, when you use with(MyObject.prototype), you're accessing
    > properties of MyObject.prototype within that scope. Therefore, you're
    > not performing extensions to your MyObject.
    >
    > :) So you just misunderstood the behavior of the with statement.


    Yes, you are right. I misunderstood :)
    Robert, Aug 25, 2005
    #5
  6. Robert

    Robert Guest

    Richard Cornford wrote:
    > Robert wrote:
    > <snip>
    >
    >>I can use "with" like this:

    >
    >
    > So assigning to an unresolved, unqualified, Identifier results in the
    > creation of a new named property of the global object and the assignment
    > of the value to that property.


    Thanks, for your explanation! I understand now.


    > MyObject.prototype = {
    > speak:function(arg1, arg2){
    > ... //function body
    > },
    > act:function(){
    > ... //function body
    > },
    > ... // etc.
    > };


    That's an interesting alternative.
    I never really use -with-, but I will keep this in mind if I feel the
    urge to use it again.
    Robert, Aug 25, 2005
    #6
  7. Robert wrote:
    > Richard Cornford wrote:

    <snip>
    >> MyObject.prototype = {
    >> speak:function(arg1, arg2){
    >> ... //function body
    >> },
    >> act:function(){
    >> ... //function body
    >> },
    >> ... // etc.
    >> };

    >
    > That's an interesting alternative.

    <snip>

    It is a nicely clear, self-contained and compact approach to defining a
    prototype. However, it is worth being aware that it has consequence that
    will probably not be obvious to many. When a function object is created
    a prototype object is created for that function. This prototype object
    is given a property called "constructor" to which a reference to the
    function is assigned. So if the function is used as a constructor for
    new object instances they will all inherit a - constructor - property
    through their prototype, that refers back to the function that
    constructed them.

    I have never yet found any practical use for this - constructor -
    property. It can be used to allow scripts to determine the 'type' of an
    object instance at runtime. My thoughts are that if the 'type' of an
    object instance is at issue at runtime (and cannot be easily determined
    by some other means) then there is a code design problem that should be
    addressed before considering the object's - constructor - property.
    However, the property would exist on all normal object instances.

    The act of replacing the function object's prototype with an alternative
    object consequently results in the - constructor - property being
    inherited from that object's prototype. In the case of using an object
    literal as the prototype the - constructor - property is inherited
    from - Object.prototype -, and will be a reference to the - Object -
    function.

    On the plus side the - constructor - property of function prototypes is
    not read only (and an inherited - constructor - property can be masked
    on the object itself anyway), and "constructor" is not a keyword or
    reserved word in the language. So the replaced prototype can provide its
    own 'constructor' property if one is likely to be needed:-

    MyObject.prototype = {
    constructor:MyObject,
    speak:function(arg1, arg2){
    ... //function body
    },
    act:function(){
    ... //function body
    },
    ... // etc.
    };

    Though I wouldn't bother with that myself.

    Richard.
    Richard Cornford, Aug 26, 2005
    #7
  8. On 26/08/2005 02:37, Richard Cornford wrote:

    [snip]

    > I have never yet found any practical use for this - constructor -
    > property. It can be used to allow scripts to determine the 'type' of an
    > object instance at runtime. My thoughts are that if the 'type' of an
    > object instance is at issue at runtime (and cannot be easily determined
    > by some other means) then there is a code design problem that should be
    > addressed before considering the object's - constructor - property.


    I don't think that's fair.

    With other languages, one can often enforce code usage by including the
    type name with an argument thereby preventing client code accidentally
    misusing a method. Similarly, one can overload methods with different
    signatures. Though neither is natively supported by ECMAScript,
    type-checking using the constructor function allows emulation (much like
    closures allow emulation of other language features).

    If client code is trusted, the former case (type enforcement) isn't
    necessary, but latter can prove useful now and then.

    [snip]

    Mike

    --
    Michael Winter
    Prefix subject with [News] before replying by e-mail.
    Michael Winter, Aug 26, 2005
    #8
  9. Robert

    Robert Guest

    Richard Cornford wrote:
    > Robert wrote:
    >
    >>Richard Cornford wrote:

    >
    > <snip>
    >
    >>>MyObject.prototype = {
    >>> speak:function(arg1, arg2){
    >>> ... //function body
    >>> },
    >>> act:function(){
    >>> ... //function body
    >>> },
    >>> ... // etc.
    >>>};

    >>
    >>That's an interesting alternative.

    >
    > <snip>
    >
    > It is a nicely clear, self-contained and compact approach to defining a
    > prototype. However, it is worth being aware that it has consequence that
    > will probably not be obvious to many. When a function object is created
    > a prototype object is created for that function. This prototype object
    > is given a property called "constructor" to which a reference to the
    > function is assigned. So if the function is used as a constructor for
    > new object instances they will all inherit a - constructor - property
    > through their prototype, that refers back to the function that
    > constructed them.


    Aha, thank you for telling me this. I don't think it is a problem for
    any code I have written so far, however I thought about using the
    constructor when I write the types of the arguments of a function (used
    when I want a stacktrace in an invalid function call).

    The constructor would give me some additional information I did not get
    out of it so far.

    Would you consider this bad design?

    BTW I really enjoy the expertise in this newsgroup.

    Robert.
    Robert, Aug 27, 2005
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Wolfgang Jeltsch

    JSR014 prototype and AssertionError

    Wolfgang Jeltsch, Dec 19, 2003, in forum: Java
    Replies:
    1
    Views:
    343
    Wolfgang Jeltsch
    Dec 19, 2003
  2. June Lee
    Replies:
    2
    Views:
    801
    Jim Cobban
    Apr 13, 2008
  3. Replies:
    9
    Views:
    188
    Thomas 'PointedEars' Lahn
    May 26, 2006
  4. Replies:
    3
    Views:
    266
  5. javascript fish
    Replies:
    0
    Views:
    170
    javascript fish
    Oct 11, 2008
Loading...

Share This Page