On Feb 28, 5:29 am, nathanJsweet <[email protected]> wrote:
> I've got a really interesting javascript pattern that I've been
> scratching my head over for a while. I basically understand what is
> going on with what I'm about to talk about, but I would like a fuller
> explanation than what I've been able to find on my own. Method
> invocation at declaration:
There is no declaration, only assignment.
> I was wandering around the MooTools source code to figrure out what I
> could learn and I ran into an interesting method attached to the
> global 'Function'
It may be better to call it the built-in Function object, and the
function is assigned as a method of its prototype.
> that basically allows for all new functions to have
> a method that allows them to take their arguments regular-style
> "function( a , b ){}" or as an object "function( { a , b } ){}". The
> code goes as follows (I've eliminated some of the other things that it
> does, such as circumventing a problem in IE where if a property with
> the DontEnum attribute exists in the prototype chain, or if the
> instance property is marked DontEnum, it is not enumerated, such as
> 'hasOwnProperty'):
That an environment doesn't iterate over DontEnum properties is per
ECMA-262.
Presumably you've added a hasOwnProperty filter so that only
enumerable properties of the passed object are iterated over, which is
a good idea since you may be iterating over function objects whose
prototype you've added enumerable properties too. And it is important
for all environments, not just IE.
>
> Function.prototype.overloadSetter = function(usePlural){
> var self = this;
> return function(a, b){
> if (a == null) return this;
> if (usePlural || typeof a != 'string'){
> for (var k in a) self.call(this, k, a[k]);
> } else {
> self.call(this, a, b);
> }
> return this;
> };
>
> };
A function is assigned to Function.prototype.overloadSetter and will
be inherited by all functions.
>
> This isn't the interesting thing yet. What is interesting about this
> function is how it is invoked.
You mean called.
> It absolutely has to be invoked at
> declaration,
There is no declaration, only assignment. And it can be done anytime
before the function is called, you can declare the function then
assign the modified version later if you want.
> it will not work if it isn't invoked at its invoker's
> invocation.
I have no idea what that means. You can refactor the function to
either be called as a property of Function.prototype, or as a global
function, e.g.
function overloadSetter(fn, usePlural) {
var self = fn;
return function(a, b){
if (a == null) {
return this;
}
if (usePlural || typeof a != 'string'){
for (var k in a) {
self.call(this, k, a[k]);
}
} else {
self.call(this, a, b);
}
return this;
};
}
An example of how to call it is below.
> Here is a function that uses it that sets an string and
> some other object as an extension:
>
> Function.prototype.extend = function(key, value){
> this[key] = value;
>
> }.overloadSetter();
That would be clearer if the function expression on the RHS was
wrapped in the grouping operator so readers have a hint that the
function will be called before being assigned:
Function.prototype.extend = (function(key, value){
this[key] = value;
}).overloadSetter();
There is no magic here - overloadSetter() wraps the anonymous function
in some argument-testing-and-forking logic and returns that. In the
refactored version, it would be:
Function.prototype.extend = overloadSetter(
function(key, value){
this[key] = value;
}
);
>
> So we could use this to basically do something like this:
>
> someFunc.extend( 'someMethod' , function(){does something} ); OR
> someFunc.extend( { 'someMethod' : function(){does something} } );
Or the extend function can include the overloadSetter functionality
and not require the extra call.
> My question doesn't revolve so much around 'how does this work', but
> as to 'why does this work',
Not sure I understand the difference, or your difficulty.
> so if you're 100% sure of EXACTLY why this
> is working than please tell me. Before you do consider that this
> pattern can only be used on the global 'Function' object (seriously
> try it),
I am tempted to write "bullshit", but I'm supposed to be nice
here. :-)
But seriously, you can write the above as separate functions and you
can call them anytime you like, as long as you modify the 'extended'
function before you call it as an extended function.
And there is another prototype on the inheritance chain of all
functions (hint: all Functions are Objects).
So plenty of options other than attaching methods to
Function.prototype.
> it cannot be used in some other parent object basically you
> couldn't replace the word 'Function' in the above code with anything
> else, this ONLY works with the global 'Function' object, but why?
If the intention is to add a property to Function.prototype, then
replacing the identifier 'Function' with some other identifier that
had not previously been assigned a reference to 'Function' seems a bad
idea. And if you were to do such a thing, then the property will be
added to some other prototype (or fail completely if that object
doesn't have a prototype property that is an object) so it is
unsurprising that it is not added to Function.prototype.
In any case, it doesn't only work that way, so there is no 'why'.
> I
> guess that's my question. I understand all of the above code and how
> it's working, but I don't understand why it's working.
Bone up on prototype inheritance. You added some methods to
Function.prototype, so all functions inherit them:
typeof someMethod.overloadSetter // function
typeof someMethod.extend // function
HTH.
--
Rob
--
To view archived discussions from the original JSMentors Mailman list:
http://www.mail-archive.com/[email protected]/
To search via a non-Google archive, visit here:
http://www.mail-archive.com/[email protected]/
To unsubscribe from this group, send email to
[email protected]