![]() |
"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 |
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> |
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 |
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 |
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. |
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 |
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. |
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> |
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 |
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 03:31 PM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.