Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Javascript > with and prototype

Reply
Thread Tools

with and prototype

 
 
Robert
Guest
Posts: n/a
 
      08-24-2005
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;
}
 
Reply With Quote
 
 
 
 
web.dev
Guest
Posts: n/a
 
      08-24-2005

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.

 
Reply With Quote
 
 
 
 
Richard Cornford
Guest
Posts: n/a
 
      08-24-2005
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.


 
Reply With Quote
 
Richard Cornford
Guest
Posts: n/a
 
      08-24-2005
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.


 
Reply With Quote
 
Robert
Guest
Posts: n/a
 
      08-25-2005
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
 
Reply With Quote
 
Robert
Guest
Posts: n/a
 
      08-25-2005
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.
 
Reply With Quote
 
Richard Cornford
Guest
Posts: n/a
 
      08-26-2005
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.


 
Reply With Quote
 
Michael Winter
Guest
Posts: n/a
 
      08-26-2005
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.
 
Reply With Quote
 
Robert
Guest
Posts: n/a
 
      08-27-2005
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.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Prototype WTP 0.2 released,this release for Prototype 1.6.0 javascript fish Javascript 0 10-11-2008 07:35 AM
Class prototype vs C function prototype June Lee C++ 2 04-13-2008 08:17 PM
Prototype Object.extend(new Base() | Hash | Hash.prototype) usage: jacobstr@gmail.com Javascript 3 03-27-2007 07:56 AM
relation between prototype and Prototype.js shypen42@yahoo.fr Javascript 9 05-26-2006 01:13 AM
JSR014 prototype and AssertionError Wolfgang Jeltsch Java 1 12-19-2003 08:38 PM



Advertisments