Prev: FAQ Topic - Why does simple decimal arithmetic give strange results? (2010-03-31)
Next: Consolidate Credit Card Debt
From: nick on 30 Mar 2010 22:41 So, I was using the good old module pattern, and I had some generic key handling code like this... window.myApp = {}; // so this example will run myApp.keys = (function(){ const down = 0, up = 1, callbacks = {}; var initted = false; // public methods return { register : function (key, onPress, onRelease) { if (!initted) init(); key = key === +key ? key : (key+'_').toUpperCase().charCodeAt(0); callbacks[key] = [onPress, onRelease]; }, unregister : function (key) { delete callbacks[key] } } // private methods // ... })(); .... and something hit me. You see that anonymous function calling itself (closure) all the time. Wouldn't it look a lot cleaner like this... myApp.keys = new function(){ const down = 0, up = 1, callbacks = {}; var initted = false; // public methods this.register = function (key, onPress, onRelease) { if (!initted) init(); key = key === +key ? key : (key+'_').toUpperCase().charCodeAt(0); callbacks[key] = [onPress, onRelease]; } this.unregister = function (key) { delete callbacks[key] } // private methods function onKey(evt, fn) { evt = evt || window.event; //IE reports window.event var kc = evt.chrCode || evt.keyCode, cb = callbacks[kc]; if (cb && typeof cb[fn] == 'function') return cb[fn](kc); return true; } function init(){ initted = true; document.onkeydown = function(evt){ return onKey(evt, down) } document.onkeyup = function(evt){ return onKey(evt, up) } } } ....I'm sure I'm not the first person who's thought of this, so I assume there is some reason that it's wrong / bad / suboptimal or you'd probably see it all over the place, but it sure looks a lot neater. Maybe using new on an anonymous function with no argument list is alright? As an extension of that, what about calling throwaway closures with new, maybe something like this? delete new function { /* do stuff here; 'this' is a temp object. */ } Thoughts?
From: nick on 30 Mar 2010 22:48 > delete new function { /* do stuff here; 'this' is a temp object. */ } should be delete new function(){ /* do stuff here... */ }
From: "Michael Haufe ("TNO")" on 31 Mar 2010 01:01 On Mar 30, 9:41 pm, nick <nick...(a)fastmail.fm> wrote: > delete new function { /* do stuff here; 'this' is a temp object. */ } delete should only be used for property removal. This is an error in ES5.
From: nick on 31 Mar 2010 02:10 On Mar 31, 1:01 am, "Michael Haufe (\"TNO\")" <t...(a)thenewobjective.com> wrote: > On Mar 30, 9:41 pm, nick <nick...(a)fastmail.fm> wrote: > > > delete new function { /* do stuff here; 'this' is a temp object. */ } > > delete should only be used for property removal. This is an error in > ES5. Fair enough, that's what the docs at MozDev indicate too. I just discovered a weird side effect that I don't really understand yet... I wanted a function to be able to chain itself to avoid passing an array as the argument, so I did this: this.register = function (key, onPress, onRelease) { if (!initted) init(); if (!onPress && !onRelease) unregister(key); callbacks[toCharCode(key)] = [onPress, onRelease]; // alert(this); return this.register; } ....and then tried this... myApp.keys.register('x', function(){alert(1)}) ('y', function(){alert(2)}) ('z', function(){alert(3)}) .... X and Y got registered, Z did not. The first two times around, 'this' was myApp.keys, but after that 'this' goes back to window / global (tested FF / V8). Can anyone shed some light on why that happens? Anyway, the obvious fix is to avoid 'this' inside of functions, but I'd still like to understand why the change happens. Anyway, here's what I ended up with... window.myApp = window.myApp || {}; myApp.keys = myApp.keys || new function(){ const me = this, DOWN = 0, UP = 1; var initted = false, callbacks = {}; // public methods this.register = function register (key, onPress, onRelease) { if (!initted) init(); if (!onPress && !onRelease) unregister(key); callbacks[toCharCode(key)] = [onPress, onRelease]; // alert(this); return register; } this.unregister = function unregister (key) { delete callbacks[key]; return unregister; } this.list = function (key) { return key ? callbacks[key] : callbacks; } this.clear = function () { callbacks = {}; return me } // private methods function init(){ initted = true; document.onkeydown = function(evt){ return on(evt, DOWN) } document.onkeyup = function(evt){ return on(evt, UP) } } function on(evt, fn) { evt = evt || window.event; //IE reports window.event var cb = callbacks[evt.chrCode || evt.keyCode]; if (cb && typeof cb[fn] == 'function') return cb[fn](evt); return true; } function toCharCode(v){ return v === +v ? v : (v+'_').toUpperCase().charCodeAt(0); } }
From: Richard Cornford on 31 Mar 2010 07:15
On Mar 31, 3:41 am, nick wrote: > So, I was using the good old module pattern, and I had > some generic key handling code like this... > > window.myApp = {}; // so this example will run > myApp.keys = (function(){ > > const down = 0, up = 1, callbacks = {}; ^^^^^ So this is JavaScript(tm) only, not a (cross or multi) browser script? > var initted = false; > > // public methods > return { > register : function (key, onPress, onRelease) { > if (!initted) init(); > key = key === +key ? key : > (key+'_').toUpperCase().charCodeAt(0); > > callbacks[key] = [onPress, onRelease]; > }, > unregister : function (key) { delete callbacks[key] } > } > > // private methods > // ... I always think that code in a function body after a - return - statement is needlessly obscure/confusing. Personally, I prefer function code to be structured such that it reflects how it will be handled; to reflect the two phase - variable instantiation then code execution handling, so with the variable and inner function declarations at the top. > })(); > > ... and something hit me. You see that anonymous function > calling itself (closure) all the time. Wouldn't it look a > lot cleaner like this... Isn't "cleaner" a judgment based on appearance? > myApp.keys = new function(){ > > const down = 0, up = 1, callbacks = {}; > > var initted = false; > > // public methods > > this.register = function (key, onPress, onRelease) { > if (!initted) init(); > key = key === +key ? key : > (key+'_').toUpperCase().charCodeAt(0); > callbacks[key] = [onPress, onRelease]; > } > > this.unregister = function (key) { delete callbacks[key] } > > // private methods > > function onKey(evt, fn) { > evt = evt || window.event; //IE reports window.event > var kc = evt.chrCode || evt.keyCode, cb = callbacks[kc]; > if (cb && typeof cb[fn] == 'function') return cb[fn](kc); > return true; > } > > function init(){ > initted = true; > document.onkeydown = function(evt){ return onKey(evt, down) } > document.onkeyup = function(evt){ return onKey(evt, up) } > } > > } In that case you are using the object created as a consequence of the use of the new operator. However, the structure that is the function expression immediately called is used for more purposes than creating single standard javascript objects with specified methods and properties. For any other purpose the use of the - new - operator would be inappropriate; the created object would not be employed and the resulting code would become more obscure than necessary as any reader would then wonder why the object was being created, what purpose it served. The extra examination of the code necessary to determine that the created object was useless, unnecessary and superfluous would suggest that it would be better not to use a construct that created one. And so the - (function(){ ... })(); - structure remains, must (eventually) be understood by any javascript developer, and so should not inhibit the understanding of code where it is used to create a single instance of a standard javascript object. > ...I'm sure I'm not the first person who's thought of this, No, it has even been (inappropriately) employed in one or two general purpose javascript libraries. > so I assume there is some reason that it's wrong / bad / > suboptimal or you'd probably see it all over the place, The history of browser scripting has never shown any relationship between the commonly observed and any notions of good/bad, right/ wrong, optimal/inefficient, etc./etc. The vast majority of browser script authors have a negligible understanding of what they are doing and so the vast majority of the scripts produced are uninformed in design and/or execution. > but it sure looks a lot neater. I don't see much in it, though I would prefer to see the - new - operator only used in conjunction with references to functions that are designed as constructors for (possibly) multiple instances of a type of object. > Maybe using new on an anonymous function with no argument list > is alright? It is correct javascript syntax. > As an extension of that, what about calling throwaway closures > with new, maybe something like this? > > delete new function { /* do stuff here; 'this' is a temp object. */ } ^^^ ()? > > Thoughts? Apart from the previously commented upon, useless and so superfluous, - delete - operation (why not - void -, or nothing at all as - new function(){ ... }; - is a perfectly fine ExpressionStatement on its own?), what does "'this' as temp object" mean? And when there is no use for the object created by the - new - operator do you use a different structure, or just create and throw it away unused? Richard. |