Re: "with" statement, extending prototype
Available news archives: comp.lang.tcl - comp.lang.python - comp.security.firewalls - sci.crypt - comp.lang.php - comp.lang.javascript
Google
 
Web news.hping.org


comp.lang.javascript archive

Re: "with" statement, extending prototype

From: RobG <rgqld@iinet.net.au>
Date: Wed Apr 05 2006 - 08:45:27 CEST

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>
Received on Mon May 1 04:42:13 2006