From: Ryan Chan on 3 Jan 2010 00:40 Have read Douglas Crockfore's JavaScript The Good Parts, it recommend Augmenting Types, e.g. Function.prototype.method = function(name, func) { this.prototype[name] = func; return this; }; String.method('trim', function() { return this.replace(/^\s+|\s+$/g, ''); }); Is this a good thing in your opinion?
From: Thomas 'PointedEars' Lahn on 3 Jan 2010 02:53 Ryan Chan wrote: > Have read Douglas Crockfore's JavaScript The Good Parts, it recommend > Augmenting Types, e.g. > > Function.prototype.method = function(name, func) { > this.prototype[name] = func; > return this; > }; > > String.method('trim', function() { > return this.replace(/^\s+|\s+$/g, ''); > }); > > > Is this a good thing in your opinion? No, because the call to String.method() would unconditionally overwrite the property value in case there was already such a method. There needs to be one in conforming implementations of ECMAScript Edition 5, so if you use this exact pattern, you would in effect be replacing the faster built-in method by a slower user-defined one. It is understandable that the book does not consider this possibility as Edition 5 was published not before 2009-12. However, that does not excuse the lack of feature test before the assignment or the lack of a property registry to work around unwanted enumeration. As to the question you wanted to ask: Such syntactic sugar can be a good thing if done properly, and there is little wrong with it in this example. However, if you augment built-in prototype objects you need to be aware that all objects that have them in their prototype chain inherit those properties, and that at least new prototype properties are enumerable (see for-in iteration). Especially, if you augment the Object prototype object the new properties will show up with for-in iteration over Array instances, as their prototype chain is [object Array] --> Array.prototype --> Object.prototype PointedEars -- Prototype.js was written by people who don't know javascript for people who don't know javascript. People who don't know javascript are not the best source of advice on designing systems that use javascript. -- Richard Cornford, cljs, <f806at$ail$1$8300dec7(a)news.demon.co.uk>
From: Garrett Smith on 3 Jan 2010 03:11 Ryan Chan wrote: > Have read Douglas Crockfore's JavaScript The Good Parts, it recommend > Augmenting Types, e.g. > > Function.prototype.method = function(name, func) { > this.prototype[name] = func; > return this; > }; > This is not a good thing. The `method` method is not related to all Functions; only constructors. It takes more time to comprehend that method than:- MyConstructor.prototype.foo = fooFunc; That method is unnecessary, not well named, adds overhead, adds clutter. I criticized this part in another thread: http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/3a08fb741525ab6d/cd561210abc96faa#cd561210abc96faa > String.method('trim', function() { > return this.replace(/^\s+|\s+$/g, ''); > }); > No, it is not a good idea to replace a built-in method with a hand-rolled version; not without good reason. In fact, without good reason, that has some negative consequences. String.prototype.trim is an ES5 standard method. It is implemented in Tracemonkey (in Firefox). A good reason for doing that would be, say, if an implementation did not yet support the new method, or if it was shown to be buggy, but only then after performing a /feature test/. The FAQ contains an example of just that. When Douglas wrote that, he probably did not consider the possibility that String.prototype.trim would be added to the language. The consequence of adding String.prototype.trim is that it replaces the built-in String.prototype.trim with a user-defined version. That user-defined version will not perform as fast as native code that it replaced and will throw errors when used in a generic context. | The following steps are taken: | 1. Call CheckObjectCoercible passing the this value as its argument. | 2. Let S be the result of calling ToString, giving it the this value | as its argument. | 3. Let T be a String value that is a copy of S with both leading and | trailing white space removed. The definition of white space is the | union of WhiteSpace and LineTerminator. | 4. Return T. | | NOTE The trim function is intentionally generic; it does not require | that its this value be a String object. Therefore, it can be | transferred to other kinds of objects for use as a method. The following are specified to work in ES5: var trimFn = String.prototype.trim; trimFn.call( window.getSelection() ) trimFn.call( new Error("You broke it.") ); trimFn.call( window.location ); trimFn.call( document.links[0] ); var range = document.createRange(); range.selectNode(document.body); trimFn.call(range); In Firefox, they correctly do convert the thisArt to string, as specified by the standard. However, when Douglas' method replaces that, it results in a TypeError. By creating your own namespace, collisions like that can be avoided. -- Garrett comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Thomas 'PointedEars' Lahn on 3 Jan 2010 03:34 Garrett Smith wrote: > Ryan Chan wrote: >> Have read Douglas Crockfore's JavaScript The Good Parts, it recommend >> Augmenting Types, e.g. >> >> Function.prototype.method = function(name, func) { >> this.prototype[name] = func; >> return this; >> }; >> > > This is not a good thing. > > The `method` method is not related to all Functions; only constructors. Non sequitur. All Function instances may be used as constructor. > It takes more time to comprehend that method than:- > > MyConstructor.prototype.foo = fooFunc; Only that this is not equivalent (note the `return'), and if feature-tests were added as they should be, there would probably be the clutter that you are talking of below, in the main code. > That method is unnecessary, No. > not well named, True, it would only qualify as `method' if it checked for method references for the second argument, and the property name misses a verb (e.g. setMethod). > adds overhead, Any abstraction does. That is not a good reason for not doing it. > adds clutter. Define: clutter. > By creating your own namespace, collisions like that can be avoided. Whereas `namespace' should be understood as syntactic sugar created by aggregation, not (yet) as a language feature. One should therefore be aware that the less probability of name collision that this "namespacing" provides comes with a performance penalty. PointedEars -- Danny Goodman's books are out of date and teach practices that are positively harmful for cross-browser scripting. -- Richard Cornford, cljs, <cife6q$253$1$8300dec7(a)news.demon.co.uk> (2004)
From: Jorge on 3 Jan 2010 10:42
On Jan 3, 6:40 am, Ryan Chan <ryanchan...(a)gmail.com> wrote: > Have read Douglas Crockfore's JavaScript The Good Parts, it recommend > Augmenting Types, e.g. > > Function.prototype.method = function(name, func) { > this.prototype[name] = func; > return this; > > }; > > String.method('trim', function() { > return this.replace(/^\s+|\s+$/g, ''); > > }); > > Is this a good thing in your opinion? The -handy- ability to -miraculously- extend types on the fly -at runtime- is another of these awesome JS's features that Brendan Eich put there just for you not to use it. LOL. -- Jorge. |