Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Javascript (http://www.velocityreviews.com/forums/f68-javascript.html)
-   -   "with" statement, extending prototype (http://www.velocityreviews.com/forums/t924020-with-statement-extending-prototype.html)

eman1000@gmail.com 04-05-2006 03:23 AM

"with" statement, extending prototype
 
I was recently looking at the prototype library
(http://prototype.conio.net/) and I noticed the author used the
following syntax:

Object.extend(MyObj.prototype, {
my_meth1: function(){},
my_meth2: function(){}
});

to define new methods on the MyObj prototype object. Object.extend
simply merges the two objects passed in. In this case MyObj.prototype
is our empty prototype object and the object literal is what we are
merging in. I really like this approach over the standard:

MyObj.prototype.my_meth1 = function(){};
MyObj.prototype.my_meth2 = function(){};

I like it because it allows me to use object initializers to define my
object (which is shorter, less error prone and keeps my code DRY) but
it doesn't squash any already existing properties on the object (kind
of feels like the open classes feature in Ruby). The only thing I don't
like about it is the need for using a function to do the merge. So I
got thinking of an alternate implementation that doesn't have this
problem but still has the same advantages. What if we did:

with(MyObj.prototype) {
function my_meth1(){}
function my_meth2(){}
}

It is my understanding that

function myfunc() {
}

is the exact same as

var myfunc = function(){}

which is the exact same as:

<current scope object>.myfunc = function() {}

Of course most of the time you can't access the top item on the scope
chain but that is what I understand to be happening behind the scenes.
Since the "with" statement puts my own object at the top of the scope
chain it seems that any functions defined in the with block would cause
a new property to be create on the specified object. This should allow
me to do what I want without using any special function (just builtin
stuff).

So I decided to try this experiment and it seemed to fail. I define my
object as follows:

var Car = function() {}
with(Car.prototype) {
function start() {
alert('starting');
}
}
mycar = new Car();
mycar.start();

This gives me an error about "start" not being defined on mycar. I
never get any errors with the with statement. It just seems that
functions defined in the with block don't get added to the Car
prototype object.

Anybody got any suggestions or ideas. I tested this theory under
Firefox.

Eric


RobG 04-05-2006 06:45 AM

Re: "with" statement, extending prototype
 
eman1000@gmail.com said on 05/04/2006 1:23 PM AEST:
> I was recently looking at the prototype library
> (http://prototype.conio.net/) and I noticed the author used the
> following syntax:
>
> Object.extend(MyObj.prototype, {
> my_meth1: function(){},
> my_meth2: function(){}
> });
>
> to define new methods on the MyObj prototype object. Object.extend
> simply merges the two objects passed in. In this case MyObj.prototype
> is our empty prototype object and the object literal is what we are
> merging in. I really like this approach over the standard:
>
> MyObj.prototype.my_meth1 = function(){};
> MyObj.prototype.my_meth2 = function(){};
>
> I like it because it allows me to use object initializers to define my
> object (which is shorter, less error prone and keeps my code DRY) but
> it doesn't squash any already existing properties on the object (kind
> of feels like the open classes feature in Ruby). The only thing I don't
> like about it is the need for using a function to do the merge. So I
> got thinking of an alternate implementation that doesn't have this
> problem but still has the same advantages. What if we did:
>
> with(MyObj.prototype) {
> function my_meth1(){}
> function my_meth2(){}
> }
>
> It is my understanding that
>
> function myfunc() {
> }
>
> is the exact same as
>
> var myfunc = function(){}


Not *exactly* the same, the first is a function declaration, the second
is a function expression. With an expression, the name (identifier) is
optional, so a closer match is:

var myfunc = function myfunc(){};

One difference is that Gecko's JS engine assigns a name attribute to the
function's arguments object. If the function is anonymous, the name
attribute is empty. Not so for a function declaration, which must have
an identifier (IE doesn't provide an arguments.name property).

There seems little point to using a function expression if none of its
specialness is being used - e.g. conditional evaluation:

var someFunc;
if (...){
someFunc = function(){ /* body 1 */ };
} else {
someFunc = function(){ /* body 2 */ };
}


> which is the exact same as:
>
> <current scope object>.myfunc = function() {}


Where 'current scope object' is what, an object? It is equivalent to
assigning an anonymous function to the myfunc property of the object.


> Of course most of the time you can't access the top item on the scope
> chain


Isn't the 'top item' always the global object? Or do you mean 'this'?


> but that is what I understand to be happening behind the scenes.
> Since the "with" statement puts my own object at the top of the scope


Not so much 'at the top' but before the scope chain of the current
execution context.


> chain it seems that any functions defined in the with block would cause
> a new property to be create on the specified object. This should allow
> me to do what I want without using any special function (just builtin
> stuff).
>
> So I decided to try this experiment and it seemed to fail. I define my
> object as follows:
>
> var Car = function() {}
> with(Car.prototype) {
> function start() {
> alert('starting');
> }
> }
> mycar = new Car();
> mycar.start();
>
> This gives me an error about "start" not being defined on mycar. I


Not exactly. It gives the error 'mycar.start is not a function', which
I guess is pretty much equivalent. :-)


> never get any errors with the with statement. It just seems that
> functions defined in the with block don't get added to the Car
> prototype object.


No errors because it 'works'. The function does get added, but as a
private member, not public - Mike Winter or someone can likely explain
how that works, not me!. You have effectively done:

var Car = function(){
function start(){
alert('starting');
}
}


What you need to do now is add a privileged method to call start():

Car.prototype.callStart = function(){start()};
var aCar = new Car();
aCar.callStart(); // shows 'starting'


Now it 'works', but it's not worth recommending just to satisfy some
coding preference - especially since it requires a non-preferred
statement to make it work, which defeats the purpose.

To use 'with' and keep start() public, you can use:

with (Car){
prototype.start = function(){alert('starting');};
}

but that just seems like a bad way to do:

Car.prototype.start = ...;


>
> Anybody got any suggestions or ideas. I tested this theory under
> Firefox.


Me too, but its the same for IE.


--
Rob
Group FAQ: <URL:http://www.jibbering.com/FAQ>

eman1000@gmail.com 04-05-2006 02:00 PM

Re: "with" statement, extending prototype
 
First I want to thank you for your feedback. I am one of the waves of
programmers who misunderstood Javascript for many years until the
recent development of Ajax libraries (such as prototype) have showed me
just how cool Javascript can be. I'm still trying to understand all the
details so I greatly appreciate any corrections to my understanding.

RobG wrote:
> > which is the exact same as:
> >
> > <current scope object>.myfunc = function() {}

>
> Where 'current scope object' is what, an object? It is equivalent to
> assigning an anonymous function to the myfunc property of the object.


<current scope object> referred to the last item added to the scope
chain. I thought identifiers created in the current scope were really
properties of the last item added to the scope chain. Maybe this is my
misunderstanding.

> > Of course most of the time you can't access the top item on the scope
> > chain

>
> Isn't the 'top item' always the global object? Or do you mean 'this'?


By "top item" I meant the last item added to the scope chain (I am
thinking about it like a stack with objects being popped on and off the
scope chain as you enter and exit functions).

> No errors because it 'works'. The function does get added, but as a
> private member, not public - Mike Winter or someone can likely explain
> how that works, not me!.


Hmmm.... I'm not sure I understand this private vs public member stuff.
Will have to do some reading on it. Thanks for pointing me in the right
direction.

> To use 'with' and keep start() public, you can use:
>
> with (Car){
> prototype.start = function(){alert('starting');};
> }
>


I'm not sure I understand why:

with (Car) {
prototype.start = function() {alert('starting');};
}

isn't equivilant to:

with (Car.prototype) {
start = function() {alert('starting');};
}

Once again thanks for your feedback,

Eric


Julian Turner 04-05-2006 02:23 PM

Re: "with" statement, extending prototype
 

eman1000@gmail.com wrote:

[snip]
> I'm not sure I understand why:
>
> with (Car) {
> prototype.start = function() {alert('starting');};
> }
>
> isn't equivilant to:
>
> with (Car.prototype) {
> start = function() {alert('starting');};
> }

[/snip]

In rough terms, when the "with" statement finds an "identifier", e.g.
"prototype" or "start", within the { ] it tries to find a corresponding
property of the object supplied to the with statement. But what it
does not do, is create a new property of the object, if it cannot find
one.

So:-

with (Car) {
prototype.start = function() {alert('starting');};
}

works, because "prototype" is an existing property of Car.

So it becomes the equivalent of "Car.prototype.start=", which is a
JavaScript valid way of creating a new property named "start".

and

with (Car.prototype) {
start = function() {alert('starting');};
}

does not work, because "start" is not an existing property of
"prototype", and there is no way that JavaScript can guess that you
want to create a new property. For all JavaScript knows, "start" could
equally be a previously declared variable or a new global variable you
are wanting to assign a value to.

The effect of the above code is to create a new "global" variable
called "start", and Car.prototype remains unchanged.

Regards

Julian Turner


Luke Matuszewski 04-05-2006 07:58 PM

Re: "with" statement, extending prototype
 

eman1000@gmail.com napisal(a):
> var Car = function() {}
> with(Car.prototype) {
> function start() {
> alert('starting');
> }
> }


Here is self explanatory example of public/protected paradigim:

function Car() {
function privateFunction()
{

}

this.publicFunction = function()
{

};
}

Car.staticConstructorFunction = function()
{

};

Car.prototype.sharedByAllCarObjectsFunction = function()
{

};

var car1 = new Car();

Car.prototype.start();
car1.start();

, still you can read about it here:

http://jibbering.com/faq/faq_notes/closures.html
http://www.litotes.demon.co.uk/js_in...te_static.html
http://www.crockford.com/javascript/private.html
http://www.crockford.com/javascript/inheritance.html

Greets
Luke M.


Thomas 'PointedEars' Lahn 04-05-2006 07:59 PM

Re: "with" statement, extending prototype
 
RobG wrote:

> eman1000@gmail.com said on 05/04/2006 1:23 PM AEST:
>> [...]
>> It is my understanding that
>>
>> function myfunc() {
>> }
>>
>> is the exact same as
>>
>> var myfunc = function(){}

>
> Not *exactly* the same, the first is a function declaration, the second
> is a function expression. With an expression, the name (identifier) is
> optional, so a closer match is:
>
> var myfunc = function myfunc(){};
>
> One difference is that Gecko's JS engine assigns a name attribute to the
> function's arguments object. If the function is anonymous, the name
> attribute is empty. Not so for a function declaration, which must have
> an identifier (IE doesn't provide an arguments.name property).


`name' attribute of the arguments object? What the heck are you talking
about?


PointedEars

Luke Matuszewski 04-05-2006 08:00 PM

Re: "with" statement, extending prototype
 

eman1000@gmail.com napisal(a):
> var Car = function() {}
> with(Car.prototype) {
> function start() {
> alert('starting');
> }
> }


Here is self explanatory example of public/protected paradigim:

function Car() {
function privateFunction()
{

}

this.publicFunction = function()
{

};
}

Car.staticConstructorFunction = function()
{

};

Car.prototype.sharedByAllCarObjectsFunction = function()
{

};



Car.prototype.start = function()
{
alert('starting');
};


var car1 = new Car();

Car.prototype.start();
car1.start();

, still you can read about it here:

http://jibbering.com/faq/faq_notes/closures.html
http://www.litotes.demon.co.uk/js_in...te_static.html
http://www.crockford.com/javascript/private.html
http://www.crockford.com/javascript/inheritance.html

Greets
Luke M.


VK 04-05-2006 08:39 PM

Re: "with" statement, extending prototype
 

Thomas 'PointedEars' Lahn wrote:
> `name' attribute of the arguments object? What the heck are you talking
> about?


About Mozilla's proprietary extension of callee object. It is not
supported by IE.

Try:

<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">

</head>

<body onLoad="alert(arguments.callee.name);">

</body>
</html>


RobG 04-05-2006 09:26 PM

Re: "with" statement, extending prototype
 
Thomas 'PointedEars' Lahn wrote:
> RobG wrote:

[...]
>>One difference is that Gecko's JS engine assigns a name attribute to the
>>function's arguments object. If the function is anonymous, the name
>>attribute is empty. Not so for a function declaration, which must have
>>an identifier (IE doesn't provide an arguments.name property).

>
>
> `name' attribute of the arguments object? What the heck are you talking
> about?


Ooops, I meant arguments.callee.name.


--
Rob

Lasse Reichstein Nielsen 04-05-2006 10:54 PM

Re: "with" statement, extending prototype
 
RobG <rgqld@iinet.net.au> writes:

> Ooops, I meant arguments.callee.name.


I.e., a "name" property on the function object. It has nothing to
do with the arguments object.

It is indeed not in the ECMAScript standard.

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


All times are GMT. The time now is 12:31 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.