From: Andrea Giammarchi on 20 May 2010 17:50 new expression is basically an "elegant" module pattern recognizable since the beginning. var o = (function () {}()); what can "o" be? just everything, included undefined. var o = new function () {}; what can "o" be in above case? Inevitably an object ;-) About the "longest prototype", being the pattern self declarative, in the meaning that the inline constructor (expression) does not suppose to have any prototype property/method, I can't see concrete side effects since the instance will always call it's properties/methods and rarely those inherited via the Object.prototype. If this is an issue, we can always attach some method, if we need it var o = new function () { // up to callee.prototype.__proto__ var hasOwnProperty = this.hasOwnProperty; // then hasOwnProperty.call(this, key); // hasOwnProperty is "secure" here // or prolix ... this.hasOwnProperty = Object.prototype.hasOwnProperty; // or ... redefine the inherited this.hasOwnProperty = this.hasOwnProperty; }; Side effects for 2nd and 3rd way, hasOwnProperty will become enumerable (JScript a part) but I think this is not an issue if performances are compromised because of the double chain (over an empty prototype ... again, I don't think these are real bottlenecks in today applications) About minifiers, mungers, obfuscators, etc, the module pattern wins for the simple reason that "this" cannot be optimized. The simplest solution for this problem is the current one: var o = new function () { var self = this; // no this anymore self.getStuff = function () { return self.stuff; }; }; self, that, $this, all valid alias able to boost up minification ratio plus in latter example there will always be a "self" reference in that scope which means that every method will become automatically bound to the singleton. Sometimes this is a "nice have" but surely weare free to use "this" inside the method. I don't think above snippet comes easily and naturally with the module pattern ... e.g. var o = (function () { // private thingy var self = { method: function () { self ... } }; return self; }()); To me above example is a bit harder to read and it looks like a missed "new expression" rather than a module pattern ... but this is more a matter of style/habit I guess. The only advantage in fact of readability is what the closure can accept from the "outer world" var o = (function (slice, snap) { var privateWorld = "something here"; return { ... }; }(Array.prototype.slice, someInlineSnapshot())); This is not possible with the new expression pattern, but surely we can always do the same directly inside the expression scope, using arguments as "reminder" var o = new function (slice, snap) { // private for JSLint sake var self = this; // outer world assignments slice = Array.prototype.slice; snap = someInlineSnapshot(); // rest of the code here }; Using all these practices could result into clearer and cleaner code, don't you agree? About *singleton*, a pattern simply describes a solution for a generic/ common/abstract problem and the *singleton* meaning in this case is: create an instance being "sure" its class/constructor won't create/ initialize any other Accordingly, in ES3 we are kinda forced to shadow the constructor via re-assignment: var o = new function () { var self = this; self.constructor = Object; }; Unfortunately, (delete o.constructor) will make the assignment pointless, this is why we all love ES5 and Object.defineProperty: var o = new function () { var self = this; Object.defineProperty(self, "constructor", { value: Object, writable: false, configurable: false, enumerable: false }); }; But since latest example won't work right now as expected, our last resource is to hack the prototype inline. var o = new function () { var self = this; // goodbye constructor self.constructor.prototype.constructor = Object; }; Finally, back to the initial double chain problem, last trick shows how to make things "faster" var o = new function () { var self = this; // avoid extra lookup // BEFORE: no more double chain self.constructor.prototype.hasOwnProperty = Object.prototype.hasOwnProperty; // LAST THING TO DO: goodbye constructor self.constructor.prototype.constructor = Object; }; We could alias the proto easily but unfortunately "hasOwnProperty" will be still exposed in a forIn loop so latest example does not really bring anything new into this scenario. I think this is pretty much it about differences, have I missed anything? Best Regards, Andrea Giammarchi
From: David Mark on 20 May 2010 20:50 Andrea Giammarchi wrote: > new expression is basically an "elegant" module pattern recognizable > since the beginning. > > var o = (function () {}()); Good, except the last parenthesis is in the wrong spot. > > what can "o" be? just everything, included undefined. So what? > > var o = new function () {}; > > what can "o" be in above case? Inevitably an object ;-) Too bad it is the wrong answer. :) Don't use that.
From: dhtml on 20 May 2010 21:01 On May 20, 2:50 pm, Andrea Giammarchi <andrea.giammar...(a)gmail.com> wrote: > new expression is basically an "elegant" module pattern recognizable > since the beginning. > > var o = (function () {}()); > > what can "o" be? just everything, included undefined. > > var o = new function () {}; > > what can "o" be in above case? Inevitably an object ;-) > As explained. > About the "longest prototype", being the pattern self declarative, in > the meaning that the inline constructor (expression) does not suppose > to have any prototype property/method, I can't see concrete side > effects since the instance will always call it's properties/methods > and rarely those inherited via the Object.prototype. > > If this is an issue, we can always attach some method, if we need it [...] That looks like a bad idea. > > About minifiers, mungers, obfuscators, etc, the module pattern wins > for the simple reason that "this" cannot be optimized. The simplest > solution for this problem is the current one: > Your example does not support that statement. [...] > > The only advantage in fact of readability is what the closure can > accept from the "outer world" > Ah no, that is not an advantage. Both CallExpression and NewExpression can have Arguments (that means you can have parameters in either one). > var o = (function (slice, snap) { > var privateWorld = "something here"; > return { ... }; > > }(Array.prototype.slice, someInlineSnapshot())); > > This is not possible with the new expression pattern, but surely we > can always do the same directly inside the expression scope, using > arguments as "reminder" > With a NewExpression, Arguments are optional. If Arguments are omitted, then parameters cannot be passed. To pass parameters, use Arguments. For example, a function may be declared and used as a constructor. var Toy = function(n, m) { this.n = n; this.m = m; }; To construct a Toy instance, you could use: var t = new Toy; but the result will be an object with `n` and `m` properties that have value undefined. To pass arguments to a new expression, use the parenthesis. For example: t = new Toy(1, 2); NewExpression takes a MemberExpression, and so it can be a FunctionExpression. I suspect this may be the source of your confusion. Here is another example of a NewExpression without Arguments, but this time using a FunctionExpression as the MemeberExpression. var tt = new function(n, m) { this.n = n; this.m = m; }; Again, the result is `m` and `n` are both undefined. To fix that, we can pass arguments, just like we did before. var tt = new function(n, m) { this.n = n; this.m = m; }(1, 2); That results in an object with `n=1` and `m = 2` > About *singleton*, a pattern simply describes a solution for a generic/ > common/abstract problem and the *singleton* meaning in this case is: > create an instance being "sure" its class/constructor won't create/ > initialize any other > > Accordingly, in ES3 we are kinda forced to shadow the constructor via > re-assignment: > > var o = new function () { > > var self = this; > > self.constructor = Object; > > }; > > Unfortunately, (delete o.constructor) will make the assignment > pointless, this is why we all love ES5 and Object.defineProperty: > > var o = new function () { > > var self = this; > > Object.defineProperty(self, "constructor", { > value: Object, > writable: false, > configurable: false, > enumerable: false > }); > > }; > I don't see the point in that. > But since latest example won't work right now as expected, our last > resource is to hack the prototype inline. > > var o = new function () { > > var self = this; > > // goodbye constructor > self.constructor.prototype.constructor = Object; > > }; > > Finally, back to the initial double chain problem, last trick shows > how to make things "faster" > > var o = new function () { > > var self = this; > > // avoid extra lookup > > // BEFORE: no more double chain > self.constructor.prototype.hasOwnProperty = > Object.prototype.hasOwnProperty; > > // LAST THING TO DO: goodbye constructor > self.constructor.prototype.constructor = Object; > > }; > The assignment to `self` is pointless. Instead, the `this` keyword can be used. Creating an enumerable property "hasOwnProperty" does not seem worthwhile. Posting via GG because I made the uninformed choice to upgrade to Thunderbird 3.
From: dhtml on 20 May 2010 21:13 On May 20, 5:50 pm, David Mark <dmark.cins...(a)gmail.com> wrote: > Andrea Giammarchi wrote: > > new expression is basically an "elegant" module pattern recognizable > > since the beginning. > > > var o = (function () {}()); > > Good, except the last parenthesis is in the wrong spot. > > > > > what can "o" be? just everything, included undefined. > > So what? The point he is trying to make, AIUI, is that the seeing a grouped function does not imply that an object will be returned. With NewExpression, an object results. Since functions can return a value, and a newExpression callsa function, it might seem like the function could return a primitive, however that is not going to result in the returned value being a primitive. The obvious case is where a function returns undefined, as most constructors do: function T(){} // Constructor returns undefined. var t = new T(); You can see that the function returned undefined and the result was a new object. function A(){ return 12; } var a = new A; typeof a; // "object" Only when the function returns an object, does newExrpression return that value: function A(){ return A } var a = new A; typeof a; // "function" The result of the constructor was a function (actually the constructor itself is returned). When reading the code, a NewExpression shows that an object is being created. > > > > > var o = new function () {}; > > > what can "o" be in above case? Inevitably an object ;-) > > Too bad it is the wrong answer. :) Don't use that. The only way it cannot be an object is if the function throws an error.
From: David Mark on 20 May 2010 21:18
dhtml wrote: > On May 20, 5:50 pm, David Mark <dmark.cins...(a)gmail.com> wrote: >> Andrea Giammarchi wrote: >>> new expression is basically an "elegant" module pattern recognizable >>> since the beginning. >>> var o = (function () {}()); >> Good, except the last parenthesis is in the wrong spot. >> >> >> >>> what can "o" be? just everything, included undefined. >> So what? > > The point he is trying to make, AIUI, is that the seeing a grouped > function does not imply that an object will be returned. Of course it doesn't. > > With NewExpression, an object results. Since functions can return a > value, and a newExpression callsa function, it might seem like the > function could return a primitive, however that is not going to result > in the returned value being a primitive. The obvious case is where a > function returns undefined, as most constructors do: > > function T(){} // Constructor returns undefined. > var t = new T(); > > You can see that the function returned undefined and the result was a > new object. > > function A(){ return 12; } > var a = new A; > typeof a; // "object" > > Only when the function returns an object, does newExrpression return > that value: > > function A(){ return A } > var a = new A; > typeof a; // "function" > > The result of the constructor was a function (actually the constructor > itself is returned). > > When reading the code, a NewExpression shows that an object is being > created. > >> >> >>> var o = new function () {}; >>> what can "o" be in above case? Inevitably an object ;-) >> Too bad it is the wrong answer. :) Don't use that. > > The only way it cannot be an object is if the function throws an > error. That's not what I meant. I meant don't use that pattern. It's an awful choice for a one-off. ISTM this was just discussed recently. |