On Feb 27, 7:29 pm, 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:
>         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' 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'):
>
> 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;
>         };
>
> };
>
> This isn't the interesting thing yet. What is interesting about this
> function is how it is invoked. It absolutely has to be invoked at
> declaration, it will not work if it isn't invoked at its invoker's
> invocation. 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();
>
> So we could use this to basically do something like this:
>
> someFunc.extend( 'someMethod' ,  function(){does something} ); OR
> someFunc.extend( { 'someMethod' : function(){does something} } );
>
> My question doesn't revolve so much around 'how does this work', but
> as to 'why does this work', 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), 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? 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.

Hi

I'll have a go.

1.   Inheritance in JavaScript is implemented through chains of
prototype objects, ending ultimately at Object.prototype.  If you
access a property (including a property referencing a function - i.e.
a method) on an object, and the object does not have that property as
its own, then the interpreter will see if the the object's prototype
has that property, and if not whether that prototype's own prototype
has that property, and so on until it runs out at Object.prototype.

2.    Functions in JavaScript are first class objects like everything
else (but what makes them special is that they are also callable).
All functions are given the Function.prototype object in their
prototype chain by the interpreter (as well  as Object.prototype).

3.   If you seek to access the method "overloadSetter" on a function,
under point 1 above, the interpreter will eventually find it on the
Function.prototype.  As a result, at the very least you need to set
"overloadSetter" on the Function.prototype before you seek to access
it on a given function instance, and if you want it to be accessible
by all functions that you create.

4.    When you access a property (including one inherited in the
prototype chain in 1 above) of an instance of an object (using DOT or
[ ]) and that property is a method (i.e. a function reference), then
the "this" property within that called method will be set by the
interpreter to equal the specific object instance on which you used
the DOT or [].  If that specific object was a function (see 2), then
the "this" value will refer to the instance of the function object on
which the method was called.

5.  In your above example, the "this" value in "overloadSetter" will
point to the function created by the function expression appearing
after "extend=" (your primary function), although of course it is
never assigned to extend, as "overloadSetter()" returns another
function to which it is a closure.  In "overloadSetter" the "this"
value (your primary function) is then assigned to "self", so that it
can be used as a closure in the nested function (a,b) returned by
"overloadSetter".

6.  To finally answer your question, "overloadSetter" will only work
if the "this" value is pointing to your primary function object,  in
order for "self.call()" to work. Accordingly "overloadSetter" needs to
be a direct property of a function or on the prototype chain for a
function (i.e. Function.prototype, or Object.prototype), per item 4
above.

Regards

Julian








-- 
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]

Reply via email to