Prev: FAQ Topic - Why does simple decimal arithmetic give strange results? (2010-03-31)
Next: Consolidate Credit Card Debt
From: Richard Cornford on 31 Mar 2010 07:53 On Mar 31, 7:10 am, nick wrote: > On Mar 31, 1:01 am, Michael Haufe (\"TNO\") wrote: >> On Mar 30, 9:41 pm, nick 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 That will not result easily comprehended code. The 'chaining' where an object is returned and methods called on that is poor enough when it comes to intelligibility but at least in that case you have the method names giving slight clues as to the process that is being undertaken. If you (and particularly habitually) start directly calling the return values of function calls in long chains there will be nothing left in the code making the calls that indicates what is going on; it will always be necessary to have familiarity with (all of) the functions being called in order to understand what is going on. In code authoring there are a range of possibilities when it comes to the comprehensibility of the code, ranging from the self-documenting (where variable/function/method names, and the use of such, pretty much state what is going on at any point) to the utterly obscure (or "elegant" as it is often called these days). Your plan seems to be aiming at the obscure. > 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, No it wasn't. The first time it was myApp, the second time it was the global object, which is why the third attempt didn't work; - return this.register; - returned the undefined value when - this - referred to the global object in the second call as the global object does not have a - register - property (except possibly by coincidence, which would cause worse bugs if that property referred to a function). > but after that 'this' goes back to window / > global (tested FF / V8). Apparently not very effectively tested, as you failed to determine which object - this - was referring to in the second function call. > Can anyone shed some light on why that > happens? It follows from the application of javascript's (ECMA 262, 3rd Ed.) rules for determining the - this - value. Rules that are generally poorly appreciated by people authoring javascript, and anti-intuitive for people coming to javascript from C++, Java, etc (despite its being obviously arrogant to assume that any new programming language you start learning will function exactly as you expect rather then finding out how it actually does behave (though the shortcomings of most books on the subject may give some excuse)). The - this - value is determined on a per-function call basis, at the time of calling the function. If the expression to the left of the call operators (the set of parentheses) evaluates as anything but an instance of the internal Reference type then the - this - value will be the global object. If it evaluates as a Reference type, but the - base - of that Reference type is an "Activation" object or is null then the - this - value will be the global object. Otherwise the - this - value refers to the object referred to by the - base - of the Reference type. (The - call - and - apply - methods of function objects are not considered above.) The - return - statement with an optional expression evaluates that expression and then calls the internal - GetValue - function on the result of that expression and returns the result of that function call. The internal - GetValue - function will always turn Reference types into pure values, thus a (native) javascript function can never return a Reference type. If a function call cannot return a Reference type and calling a value that is not a Reference type will result in the - this - value inside the called function being a reference to the global object then the - this - value in the second, and subsequent, function calls in - aFunctionRef()()()()(); - must be the global object. > Anyway, the obvious fix is to avoid 'this' inside of > functions, Solving the wrong problem. > but I'd still like to understand why the change happens. <snip> Unfortunately, the best approach towards understanding how javascript works it to become familiar with its specification (ECMA 262). Richard.
From: Dmitry A. Soshnikov on 31 Mar 2010 08:25 On Mar 31, 6:41 am, nick <nick...(a)fastmail.fm> wrote: [...] > > const down = 0, up = 1, callbacks = {}; So, if you use "const" keyword, that means you write only for some specific implementation. You then can also use non-standard ".name" property of functions to provided "publicAPI" method which allows to register public interface. The main goal is that you can describe functions only in _declaration_ form and without using "this." prefix every time. var object = (function () { function _privateMehtod() { ... } function publicMethod() { _privateMethod(); } return publicAPI([ ... publicMethod, otherPublicMethod, ... ]); })(); function publicAPI(methods) { var object = {}; while (methods.length) { var current = methods.pop(); object[current.name] = current; } return object; } This approach is known, but has small but efficient (by code reuse) optimization -- it avoids to repeat public method name third time, as it would in: return { ... publicMethod: publicMethod, otherPublicMethod: otherPublicMethod ... }; Of course you can provide separately properties and methods (in one object) for "publicAPI" function. Dmitry.
From: nick on 31 Mar 2010 18:01 On Mar 31, 7:15 am, Richard Cornford <Rich...(a)litotes.demon.co.uk> wrote: > On Mar 31, 3:41 am, nick wrote:> So, I was using the good old module pattern, and I had > > ... > > const down = 0, up = 1, callbacks = {}; > > ^^^^^ > So this is JavaScript(tm) only, not a (cross or multi) browser script? Yeah, the thing I'm working on is eventually going to be a firefox / chrome extension, although now that you mention it I probably need to get rid of const in case I do a bookmarklet version and for the sake of ES compliance. > > 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. > I see your point. To me, the return statement serves as a reminder that there is no 'loose' code after that point, only function declarations. So the var declarations, public properties and any other init code goes before the return, and private functions go after. I suppose this is a matter of taste. > > ... 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? > I think so. It was more of a rhetorical question; it certainly looks cleaner to me (specifically, it uses less symbol characters and reads more like other ) but I agree that it's subjective. > > 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. Thanks for that analysis, it makes a lot of sense and I'm inclined to agree with you. > > > ...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. > Inappropriately because the object created by calling 'new' was discarded without being used, or for some other reason? > > 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. Good point. > > > 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. > Well, I say it looks cleaner because there are less 'weird symbols' laying around, and because the closure doesn't need to return anything... it looks more like 'most constructs' in other languages, and less 'javascripty.' But, as you pointed out, this is all just a matter of taste. > > Maybe using new on an anonymous function with no argument list > > is alright? > > It is correct javascript syntax. > Good, that was my main concern. Thanks, Richard!
From: nick on 31 Mar 2010 19:10 On Mar 31, 7:53 am, Richard Cornford <Rich...(a)litotes.demon.co.uk> wrote: > On Mar 31, 7:10 am, nick wrote: > ... > > I just discovered a weird side effect that I don't really > > understand yet... I wanted a function to be able to chain > > itself > > That will not result easily comprehended code. The 'chaining' where an > object is returned and methods called on that is poor enough when it > comes to intelligibility but at least in that case you have the method > names giving slight clues as to the process that is being undertaken. > If you (and particularly habitually) start directly calling the return > values of function calls in long chains there will be nothing left in > the code making the calls that indicates what is going on; it will > always be necessary to have familiarity with (all of) the functions > being called in order to understand what is going on. Ah, but isn't this a subjective matter as well? To me something like this is easily understandable, if a bit esoteric: Cufon('h1')('h2')('h3'); > > In code authoring there are a range of possibilities when it comes to > the comprehensibility of the code, ranging from the self-documenting > (where variable/function/method names, and the use of such, pretty > much state what is going on at any point) to the utterly obscure (or > "elegant" as it is often called these days). Your plan seems to be > aiming at the obscure. To the contrary, my plan aims at brevity and simplicity, both in the library itself and in the calling convention. While I agree that code like this may be less self-documenting, it's also a lot less to type. Plus, as a user of the function, you can always choose not to chain it... Cufon('h1'); Cufon('h2'); Cufon('h3'); > ... > > > ... X and Y got registered, Z did not. The first two times around, > > 'this' was myApp.keys, > > No it wasn't. The first time it was myApp, the second time it was the > global object, which is why the third attempt didn't work; - > return this.register; - returned the undefined value when - this - > referred to the global object in the second call as the global object > does not have a - register - property (except possibly by coincidence, > which would cause worse bugs if that property referred to a function). > You're right, I stand corrected. Sorry for that misinterpretation. > > Can anyone shed some light on why that > > happens? > > It follows from the application of javascript's (ECMA 262, 3rd Ed.) > rules for determining the - this - value. [...] > > The - this - value is determined on a per-function call basis, at the > time of calling the function. If the expression to the left of the > call operators (the set of parentheses) evaluates as anything but an > instance of the internal Reference type then the - this - value will > be the global object. If it evaluates as a Reference type, but the - > base - of that Reference type is an "Activation" object or is null > then the - this - value will be the global object. Otherwise the - > this - value refers to the object referred to by the - base - of the > Reference type. > > (The - call - and - apply - methods of function objects are not > considered above.) > > The - return - statement with an optional expression evaluates that > expression and then calls the internal - GetValue - function on the > result of that expression and returns the result of that function > call. The internal - GetValue - function will always turn Reference > types into pure values, thus a (native) javascript function can never > return a Reference type. > > If a function call cannot return a Reference type and calling a value > that is not a Reference type will result in the - this - value inside > the called function being a reference to the global object then the - > this - value in the second, and subsequent, function calls in - > aFunctionRef()()()()(); - must be the global object. Excellent, thank you, that's just the explanation I was looking for. > > > Anyway, the obvious fix is to avoid 'this' inside of > > functions, > > Solving the wrong problem. > I'm not sure what you mean by that. It solves the problem I was having, in that it allows my script to function as intended. The problem it solved was the one I meant to solve, maybe you meant it's the wrong solution to the problem? If so, what do you consider the right solution to be? Thanks again for your input, Richard.
From: David Mark on 31 Mar 2010 20:34
nick wrote: > On Mar 31, 7:53 am, Richard Cornford <Rich...(a)litotes.demon.co.uk> > wrote: >> On Mar 31, 7:10 am, nick wrote: >> ... >>> I just discovered a weird side effect that I don't really >>> understand yet... I wanted a function to be able to chain >>> itself >> That will not result easily comprehended code. The 'chaining' where an >> object is returned and methods called on that is poor enough when it >> comes to intelligibility but at least in that case you have the method >> names giving slight clues as to the process that is being undertaken. >> If you (and particularly habitually) start directly calling the return >> values of function calls in long chains there will be nothing left in >> the code making the calls that indicates what is going on; it will >> always be necessary to have familiarity with (all of) the functions >> being called in order to understand what is going on. > > Ah, but isn't this a subjective matter as well? To me something like > this is easily understandable, if a bit esoteric: > > Cufon('h1')('h2')('h3'); It's completely ridiculous. And I mean that in the nicest possible way (trying to save you some time here). > >> In code authoring there are a range of possibilities when it comes to >> the comprehensibility of the code, ranging from the self-documenting >> (where variable/function/method names, and the use of such, pretty >> much state what is going on at any point) to the utterly obscure (or >> "elegant" as it is often called these days). Your plan seems to be >> aiming at the obscure. > > To the contrary, my plan aims at brevity and simplicity, both in the > library itself and in the calling convention. While I agree that code > like this may be less self-documenting, it's also a lot less to type. The amount of typing is irrelevant. That's what macros and the clipboard are for. |