Questions about 'new' : is this pattern legit?

N

nick

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?
 
M

Michael Haufe (\TNO\)

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.
 
N

nick

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);
}

}
 
R

Richard Cornford

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.
 
R

Richard Cornford

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.
 
D

Dmitry A. Soshnikov

[...]
  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.
 
N

nick

On Mar 31, 3:41 am, nick wrote:> So, I was using the good old module pattern, and I had

    ^^^^^
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.
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.
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?
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.
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.
It is correct javascript syntax.

Good, that was my main concern. Thanks, Richard!
 
N

nick

On Mar 31, 7:10 am, nick wrote:
...

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');
...


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.
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.
 
D

David Mark

nick said:
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).
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.
 
N

nick

It's completely ridiculous.  And I mean that in the nicest possible way
(trying to save you some time here).

Why? It seems pretty self-evident to me. Look at this code:

myApp.keys.register
('w', panNorth)
('s', panSouth)
('a', panWest)
('d', panEast);

// nearby...
function panNorth(evt){/* ... */}
function panSouth(evt){/* ... */}
...

What else could it possibly be doing besides registering a bunch of
key handlers? It works and it makes sense, so it's not entirely
ridiculous. And, really, how is it any worse than something like this:

myApp.keys.register([
['w', panNorth],
['s', panSouth],
['a', panWest],
['d', panEast]
]);

// nearby...
function panNorth(evt){/* ... */}
function panSouth(evt){/* ... */}

This means the register function must be more complex, unless you want
to register a single key handler like this: register([[key,func]])

So maybe there is a bit of overhead to the first method, but if you're
just using it for a one-shot thing like registering key handlers or
replacing fonts it seems to make plenty of sense.
 
T

Thomas 'PointedEars' Lahn

nick said:
David said:
It's completely ridiculous. And I mean that in the nicest possible way
(trying to save you some time here).

Why? It seems pretty self-evident to me. Look at this code:

myApp.keys.register
('w', panNorth)
('s', panSouth)
('a', panWest)
('d', panEast);

// nearby...
function panNorth(evt){/* ... */}
function panSouth(evt){/* ... */}
...

What else could it possibly be doing besides registering a bunch of
key handlers? It works and it makes sense, so it's not entirely
ridiculous. And, really, how is it any worse than something like this:

myApp.keys.register([
['w', panNorth],
['s', panSouth],
['a', panWest],
['d', panEast]
]);

// nearby...
function panNorth(evt){/* ... */}
function panSouth(evt){/* ... */}

1. It requires you to keep an external reference to the initial calling
object as Richard has already explained.

2. Several function calls will be always more expensive than just one and
the creation of an Array instance.

BTW, few would consider spoiling the current execution context's namespace
declaring functions when using Array initializers as anonymous function
expressions would be readily available then.
This means the register function must be more complex, unless you want
to register a single key handler like this: register([[key,func]])

With the self-calling approach the register() method must be more complex
instead; it must use a closure to work on the initial calling object when
self-called.
So maybe there is a bit of overhead to the first method, but if you're
just using it for a one-shot thing like registering key handlers or
replacing fonts it seems to make plenty of sense.

You don't know what you are talking about. Incidentally, not even the
crappy jQuery promotes this ridiculous pattern, the chaining there goes
$(...).method(...).method(...) instead (which is only slightly less
inefficient, error-prone and hard to debug).


PointedEars
 
R

Richard Cornford

Ah, but isn't this a subjective matter as well?

There are subjective aspects to it (particularly the judgment), but it
is not entirely subjective. Unfortunately the question often gets
decided on a subjective basis; it is easy for me to understand so it
must be easily understandable, where the individual is not considering
what knowledge they are brining to their considerations that others
may not be able to.

The objective assessment would look at (only) the code itself and
asses what could be learnt from that. (Obviously some foreknowledge
must be assumed, like understanding javascript syntax, else attempting
to understand javascript code is not a realistic expectation).
To me something like
this is easily understandable, if a bit esoteric:

Cufon('h1')('h2')('h3');

Looking at this code itself we see a call to (what is assumed to be) a
function, and then a call to whatever is returned from that first
call, and then a call to whatever is returned from that. We might also
observe a similarity in the arguments.

That is all the information available in the code. In order to
determine that this actually represents three calls to the same
function it will be necessary to find the code for a - Cufon -
definition, or the code for whatever function is assigned to - Cufon -
at any given time. Otherwise (even if 'Cfon' were instead an
Identifier that described what the function did) the nature/process of
the second and third function calls remains unknown. It is not even
hinted at by the code above, and that is an objective fact.
To the contrary, my plan aims at brevity

I can see the brevity, but don't regard that as advantageous in
itself.
and simplicity,

That is a subjective judgment. I would not judge the above simpler
than what follows.
both in the library itself and in the calling convention.

As a general convention that is a frightening prospect. If you did
this exclusively with functions that returned references to themselves
then familiarity with the "library" might make this acceptable as then
you would be able to assume that - x()()(); - represented a sequence
of calls to - x -. But just one instance of a function that returned
any other function and all instances of code like - x()()(); - start
to need detailed examination before it can be understood.
While I agree that code like this may be less self-documenting,

I would say approaching non-self-documenting.
it's also a lot less to type.

Typing is a very overrated issue. Typing is not that difficult (having
done so myself, it only takes an hour a day for a month to learn how
to touch type (60+ words a minute)), and there are numerous tools and
facilities of tools for aiding code entry (and even if some may need a
little setting up, if code writing is your work (or even a significant
pastime) the long term returns justify the initial effort).

However, far more important than any assessment of the actual work
involved in typing is the realisation that entering code is something
you only do once, but reading code (with the intention of
understanding it) is something that accompanies debugging,
maintenance, modification and enhancement, and the appreciation that
it is in maintenance that the majority of the software authoring
expense lies.

This is where it is important to attempt to step away from your own
individual foreknowledge because there is no guarantee that someone
maintaining code is going to have that same knowledge or appreciation
of inner working of your code. You may know that the - Cufon -
function returns a reference to itself, but the later maintainer won't
know that until they have looked at, and understood - Cufon -.
Plus, as a user of the function, you can always choose not
to chain it...

Cufon('h1');
Cufon('h2');
Cufon('h3');

Looking at this code, with exactly the same (absence of) understanding
of the code that surrounds it, we again see three function calls, but
here we can see good ground for expecting those to be three calls to
the same function. There is information here that is absent from the
previous example.

Now replace - Cufon - with an identifier that makes an unambiguous
statement about what the function does and maybe we don't even need to
go an look at the function code in order to understand what this code
(and the code shrouding it) is trying to do.

I'm not sure what you mean by that.

The problem that you 'fixed' followed from the style you want to apply
in using your code; the chained function calls. The correct problem to
solve might be whatever it is that encourages you to attempt to adopt
divergent programming styles that introduce new problems if adopted.
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?

No, I meant solving the wrong problem.

Richard.
 
D

Dmitry A. Soshnikov

[...]
  myApp.keys.register
    ('w', panNorth)
    ('s', panSouth)
    ('a', panWest)
    ('d', panEast);

Although it is less efficient by performance than passing an array,
this approach seems to me quite elegant by code reuse.

Dmitry.
 
N

nick

1. It requires you to keep an external reference to the initial calling
   object as Richard has already explained.

What about arguments.callee? That's good enough for returning a
reference to the same function.
2. Several function calls will be always more expensive than just one and
   the creation of an Array instance.

Granted, but how much more expensive, and what's the tradeoff? If
average joe web designer screws up the first example 25% less than the
second, it might be worth those few extra milliseconds per page load.
BTW, few would consider spoiling the current execution context's namespace
declaring functions when using Array initializers as anonymous function
expressions would be readily available then.

What?
This means the register function must be more complex, unless you want
to register a single key handler like this: register([[key,func]])

With the self-calling approach the register() method must be more complex
instead; it must use a closure to work on the initial calling object when
self-called.

this.register = function (key, onPress, onRelease) {
if (!initted) init();
if (!onPress && !onRelease) me.unregister(key);
callbacks[toCharCode(key)] = [onPress, onRelease];
return arguments.caller;
}

// or //

this.register = function (key, onPress, onRelease) {
if (!initted) init();
if (typeof key == 'array') {
for (int i=key.length, i--;)
(callbacks[toCharCode(key[0])] = [key[1], key[2]])
}
else {
if (!onPress && !onRelease) me.unregister(key);
callbacks[toCharCode(key)] = [onPress, onRelease];
return arguments.caller;
}
}

....?
You don't know what you are talking about.  Incidentally, not even the
crappy jQuery promotes this ridiculous pattern, the chaining there goes
$(...).method(...).method(...) instead (which is only slightly less
inefficient, error-prone and hard to debug).

I don't know what you are talking about :)
 
R

Richard Cornford

What about arguments.callee? That's good enough for
returning a reference to the same function.

arguments.callee is good enough for (anonymously) returning a
reference to the current function. It won't be available in ES5 strict
mode, and it has been observed that some implementations are optimized
such that they don't create an - arguments - object if you don't refer
to it, so using - arguements.callee - will prevent that.

this.register = function (key, onPress, onRelease) {
if (!initted) init();
if (!onPress && !onRelease) me.unregister(key);
callbacks[toCharCode(key)] = [onPress, onRelease];
return arguments.caller;
}
<snip>

Apparently one issue with using - arguments.callee - is typeing it
wrongy and ending up with - argrument.caller -. ;-)

Richard.
 
N

nick

What about arguments.callee? That's good enough for
returning a reference to the same function.

arguments.callee is good enough for (anonymously) returning a
reference to the current function. It won't be available in ES5 strict
mode, and it has been observed that some implementations are optimized
such that they don't create an - arguments - object if you don't refer
to it, so using - arguements.callee - will prevent that.

    if (!initted) init();
    if (!onPress && !onRelease) me.unregister(key);
    callbacks[toCharCode(key)] = [onPress, onRelease];
    return arguments.caller;
  }

<snip>

Apparently one issue with using - arguments.callee - is typeing it
wrongy and ending up with  - argrument.caller -.  ;-)

Richard.

hahahah... apparently so.

My "real" code actually returns me.register, with 'me' being the
'this' that's getting created by my new function(). I guess it is kind
of a deviant pattern, but WTH. Anyway, thanks for your help :)

Here's the script as it is now if anyone is interested.

// global app object
window.myApp = window.myApp || {};

// our key handling module
myApp.keys = myApp.keys || new function(){

var me=this, down=0, up=1, initted, callbacks={};

// public methods

me.register = function (key, onPress, onRelease) {
if (!initted) init();
if (!onPress && !onRelease) me.unregister(key);
callbacks[toCharCode(key)] = [onPress, onRelease];
return me.register;
}

me.unregister = function (key) {
delete callbacks[key];
return me.unregister;
}

me.list = function (key) {
return key ? callbacks[key] : callbacks;
};

me.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);
}

}
 
R

Richard Cornford

So, I was using the good old module pattern, and I had


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.

As they are going to be tucked away in a closure anyway the difference
between their being constants and so not being changeable and their
being inaccessible variable is probably minimal. External code that
went to the effort of rendering the variable changed could as easily
modify the constants, so you only really need to remind yourself that
they are not supposed to be changed, which is usually done with the
naming convention of using all upper case (and underline) names for
variables that represent constants.
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.

It is not to my taste, but not worth too much argument. I do wonder
what happens when the function has no return statement but still have
internal function declarations. Having an implied return at the end of
a function body makes sense (what else would happen there), but having
it somewhere before the end seems non-obvious. Perhaps that suggests
no function bodies without explicit return statements, even if they
don't always return expressions (even if that would be counter to any
effort to reduce typing).

Inappropriately because the object created by calling 'new' was
discarded without being used, or for some other reason?

Yes, that was the substance of the criticism, and no counter argument
was proposed by the authors in question.

In general, if you have to otherwise indistinguishable alternatives
the one that creates the superfluous object becomes the inferior
option.

Well, I say it looks cleaner because there are less 'weird symbols'
laying around,

But more keywords.
and because the closure doesn't need to return
anything... it looks more like 'most constructs' in other
languages, and less 'javascripty.'

I don't know about looking like constructs in other languages. Using -
new - in, for example, Java has a meaning that would be difficult to
translate into this proposed use.

Also, the - (function(){ ... })(); - construct was hardly used prior
to 2003 (and then not for encapsulation/privacy purposes), and so
javascript is more then twice the age of (the general use of) that
construct, which makes it questionable to call it "javascripty".
But, as you pointed out, this is all just a
matter of taste.
<snip>

Largely, yes, but not necessarily entirely.

Richard.
 
A

Asen Bozhilov

nick said:
My "real" code actually returns me.register, with 'me' being the
'this' that's getting created by my new function(). I guess it is kind
of a deviant pattern, but WTH. Anyway, thanks for your help :)

Here's the script as it is now if anyone is interested.
[...]

var me=this;
me.register = function(){};

Why do you use that code? `this` associated with execution context
immutable, and will be much more fast if you use `this` instead of
identifier, which evaluate against Scope Chain.

I always wonder, what is the reason for people want "private"
emulation in Javascript. If the developer, who use your code is
unreasonable person, you cannot stop errors and mistakes. I prefer to
use naming convention for private properties. For example:

this._privateMethod = function() {
//...
};

It's enough, before language support native access modifiers.
 
J

johnwlockwood

var me=this;
me.register = function(){};

Isn't this done so you can reference the this from a closure function?
like:
function MyObject(id)
{
var me = this;
me.id = id;
me.getId_ = function()
{
return me.getId();
};
};

var MyObject.prototype.getId = function()
{
var me = this;
return me.id;
}

var myObject = MyObject("test");

var getMyObjectId = myObject.getId_;

// or assign myObject.getId_ as a callback

alert(getMyOjbectId());

// alert should display "test"


Why do you use that code? `this` associated with execution context
immutable, and will be much more fast if you use `this` instead of
identifier, which evaluate against Scope Chain.

I was told there was a bug in one of the browsers that caused a
problem if you didn't use the me=this.
If that is not true, I could do it like so:

function MyObject(id)
{
this.id = id;
this.getId_ = function()
{
return this.getId();
};
};

var MyObject.prototype.getId = function()
{
return this.id;
}

This is obviously a very contrived example.

-John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,756
Messages
2,569,534
Members
45,007
Latest member
OrderFitnessKetoCapsules

Latest Threads

Top