From: Richard Cornford on
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
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
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
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
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.