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]
