In Javascript, it's possible to have some kind of inheritance, by using function contructors and their "prototype" attribute (i.e the "parent of future instances"), or more recently Object.create(), to get new objects.
However recently I needed to "override" the Jquery object ("$") for one of my projects, that is to say, provide a similar function, which also has all the fn/extend/... [inherited] attributes of the original "jQuery" factory function.
The goal was to have a "$()" function which always received "window.parent" as the second parameter by default, so that the whole program modified the parent frame and not the iframe in which the program was loaded.
Typically I expected to be able to do something like this:
var oldJQ = $;
$ = function (selector) {
return oldJQ(selector, window.parent);
}
$.__proto__ = oldJQ .__proto__;
$.extend({...}); // must work
Despite numerous attempts, I couldn't get it to work, I always got simple objects instead of real functions when using the "new" keyword, or the inheritance didn't work. I found alternative ways (for example, by copy-pasting all attributes from $ into my new function object), but it seems to me like a horrible way of doing stuffs.
Is there any way to have a new function object which has, as a parent/prototype, the original $ object ?
While functions are objects in javascript, they aren't regular objects. Specifically, they're objects for which inheritance is broken. Functions are not the only such objects in the language, DOM elements are similarly handicapped. That's one reason jQuery is implemented as wrapper around DOM rather than extending the DOM's features via inheritance.
Fortunately, while OOP doesn't work in this case, we can take inspiration from jQuery itself and use FP to do what we need. In other words, while you can't inherit functions, you can wrap it in another function.
For example, if you need a special console.log function for your app that sends logs back to your server you can override it by redefining it:
var log_orig = console.log;
console.log = function () {
ajaxlog([].slice.call(arguments,0).map(function(x){
return JSON.parse(x);
}).join(',');
log_orig.apply(console,arguments);
}
Or if you want a special version of $ that does something extra:
function $$ () {
/*
* do extra stuff
*/
return $.apply(null,arguments);
}
Or if you want to override $ instead if wrapping:
var old$ = $;
function $ () {
/*
* do extra stuff
*/
return old$.apply(null,arguments);
}
Related
I'm creating a JS library object that has a primary function, but I also want to assign sub-methods to that primary function to extend it.
So right now what I have looks like this:
Parser.prototype = {
init: function(){
},
primaryFunction:function(){
}
}
I really like this notation for assigning methods to Parser.prototype, but how can I use similar notation for assigning methods to primaryFunction? Also, the submethods are characterized by a string. Because eventually, my goal is to be able call like this: primaryFunction["*"]();
It seems I can't do this:
primaryFunction:function(char){
"*":function(){
}
}
Sort of makes sense why, but am I forced to do this?
primaryFunction:function(char){
this["*"] = function(){};
}
There's a big difference between adding properties to Parser.prototype and adding properties to primaryFunction. When you add to Parser.prototype, you're adding properties to a non-function object that is used as the underlying prototype of any object (instance) created via the new Parser expression. But if you add properties to primaryFunction, you're adding those properties to the function object of primaryFunction, directly.
The result is that properties added to Parser.prototype become, in effect, methods of instances created via new Parser. Within calls to those "methods," provided they're made normally (instance.init() and similar), this will refer to the instance.
But properties added to primaryFunction are methods of the function primaryFunction, not instances created with it. If you call them in the normal way (instance.primaryFunction["*"]()), within the call this is primaryFunction (the function object), not instance.
If that's really want you want, then you simply assign them after the fact (you can't do it within the object initializer):
Parser.prototype.primaryFunction["*"] = function() { /* ... */ };
But there are relatively few use cases for doing that, not least because if you're using Parser as a constructor function (e.g., with new Parser), you probably want to do things with the instance created, and you won't have access to it in primaryFunction["*"] unless you do some funny stuff.
The funny stuff, FWIW, looks like this — but I'm not recommending it (nor recommending against it), just being complete:
/* ...inside the `Parser` function... */
this.primaryFunction["*"] = this.primaryFunction["*"].bind(this);
That creates a new function that, when called, will call primaryFunction but setting this to the instance created by new Parser, and saves the resulting function as an "own" property on the instance being created.
From your comment below:
So my use case is just a parsing object that performs different
actions based on what characters it reads. The Parser loops through a
string, and my goal is to call a different function based on what the
current character at the index is. There will only be a set of unique
functions for each special character that may be in the string. For
instance, those characters could be: *, /, \, <, >,
essentially non alphanumerics. For anything alphanumeric, I want a
default function to handle those. So essentially, in a loop I'm
getting the currentChar, and trying to call a sub-method based on
which char it is. So the loop is essentially doing:
this.handleChar[currentChar]().
The bind solution above would work for that. But I think I'd probably go another way: Have a private, shared map of handler functions that you call (either passing in the parser instance as an argument, or as this) with the characters:
var Parser = function() {
var handlers = {
"*": function(char) {
// handle *...
},
"/": function(char) {
// handle /...
},
// ...and so on...
"default": function(char) {
// default handling...
}
};
function Parser() {
// ...
}
// (I always advocate *augmenting*, not replacing, `FuncName.prototype` properties)
Parser.prototype.handleChar = function() {
var currentChar;
while (!!(currentChar = /*...get the character...*/)) {
(handlers[currentChar] || handlers.default).call(this, currentChar);
// On some older JavaScript engines, you'd have to write the above like this:
//
// (handlers[currentChar] || handlers["default"]).call(this, currentChar);
//
// ...because ES3 didn't let you use a keyword as a property name literal
// (ES5 does, and some engines always did).
}
};
return Parser;
}();
That example passes the parser instance as this by using Function#call (the first argument is what ends up being this in the function call). It also uses JavaScript's curiously-powerful || operator to pick the function on handlers to call.
(If you don't care that handlers be private, then you don't need the wrapper.)
Is it acceptable to add an attribute or value to a JavaScript function?
Example:
var f = 1;
function foo (param) {
f++;
}
var fooFunc = foo;
fooFunc.dummy = f;
console.log('fooFunc: ' + fooFunc);
console.log('fooFunc.dummy: ' + fooFunc.dummy);
The above example creates a function (foo), then assigns it to a new variable (fooFunc) and then adds a dummy attribute to fooFunc.
When run, this example prints the text of the function first, and then it prints the expected value (1 in this case). When printing the function, it doesn't show any indication of the dummy value:
fooFunc: function foo(param) {
f++;
}
fooFunc.dummy: 1
JsFiddle here - open the browser's JavaScript console to see the log messages: http://jsfiddle.net/nwinkler/BwvLf/
Why does this work? And where is the dummy attribute stored, and why isn't it printed when I log the function?
Lastly, even if this works, is it a good idea (or an acceptable practice) to use this? I don't want to start an open ended discussion on this, but rather see if there's documented uses of this, or people discouraging this in JavaScript coding guidelines.
Everything except primitives ( null, undefined, number, string, boolean ) in JavaScript are objects. So functions are basically objects.
Objects in JavaScript can have properties and methods, hence functions too.
all functions inherit from Function.prototype and has certain properties ( name, length ) and methods ( .call, .apply ) coming through this chain.
It is sometimes very useful to keep properties attached to the function itself, like cache information, number of invocations etc. There is nothing wrong out in using it this way.
More details : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
Let's have a look at ECMAScript documentation (Which is the standard JavaScript is based on). Here's the 3rd. version of it:
http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf
Go to chapter 15, Native ECMAScript Objects.
15.3 > Function objects.
There's a lot of interesting information there concerning your question, but the first thing worth noticing is that function is an object.
As an object, it has attributes (predefined and that you can assign yourself).
For example, try:
console.log('fooFunc.name: ' + fooFunc.name);
It should display "foo" in your case.
Since it's documented quite well, you can use it as a standard way, though it is not so well-spread and may seem a bit unusual.
Hope this helps.
It is normal object behavior, whether "acceptable" or not.
By using the function keyword you are actually calling the native predefined Function() constructor. Like any object constructor it returns an object after building it. Like any object, the returned object can have properties, including other functions as method properties.
var adder = function(a, b){return a+b};
adder.subtracter = function(a, b){return a-b};
console.log(adder(1,2)); // 3
console.log(adder.subtracter(1,2)); // -1
TIP: if you want to see the adder object and its subtracter method, switch to DOM view from Console view after running the above code in console and then search for "adder". You'll see the object there, and then you can collapse to see what it's made from, including a subtracter object.
Of course, a function object is a special native object, which makes it possible to make calls like this: adder() and actually run some code. The fact that a function object is harder to inspect for custom attached properties, combined with its native special object treats (read built-in restrictive behavior), should give you a hint that, while it's possible, attaching custom properties is not the intended nor a good use of a function object.
I have pretty big javascript class with bunch of methods stored in a single js file. This methods can be logically categorized like common methods, methods to filter data, navigation methods etc. Now I want this class being split by separate files each containing its own specific category methods and leaving all properties and common methods in the current file. Shortly speaking I need something that c# partial keyword is used for.
I would like to avoid using prototype as it means I have to type class name for every function like class.prototype.functionname = function () { ... } that does not look great.
UPDATE: This is how my class looks like
function MyClass() {
var self = this;
self.common = function() {...}
self.filterData = function() {...}
self.navigate = function() {...}
}
I do not know how to handle self properly with prototypes or extension
If your class does not use the prototype, you have little chance - it is one [too] big function. However, such big functions shouldn't exist anyway, are you sure you need it to be a class (with multiple instances)? Then you should move the functions to the prototype as far as you can. If not, a singleton would make more sense for you, which is essentially nothing more than an object literal. You also might have a look at the [revealing] module pattern, which is what you need (or one of its flavors) - the (sub) modules usually can be spread easily across different files, potentially using a dependency tracking loader.
If it does, you can easily split it up into the single parts. That does not mean you would need to repeat class.prototype.… = …, you can just use helper functions like extend
MyFavLibrary.extend(class.prototype, {
functionname: function functionname() {…},
…
});
or a simple IEFE-closure:
(function(proto) {
// even some place for static, private helper functions
proto.functionname = functionname() {…};
…
})(class.prototype);
Without using jQuery, I'd like to know how to mimik a jQuery plugin
For example, maybe $('div.x').plugin() attaches an onclick to divs, and increments and displays an internal value.
Where does jQuery actually store the object with the internal variable?
Does an object get explicitly created somewhere and associated with each node?
I get lost trying to explain to myself why there is no explicit object creation in the main application listing.... must happen within the plugin somehow?
(PS: I am less concerned with the query engine side... just the plugin side :)
thanks
Normally you define a function like plugin() by writing
$.fn.plugin = ...
As discussed here, $.fn is actually just a shortcut for jQuery.prototype. When you attach a method to a constructor's prototype, JavaScript automatically attaches it to all instances created from that constructor with the new keyword, which jQuery does internally when you write something like $('li'). See http://javascriptweblog.wordpress.com/2010/06/07/understanding-javascript-prototypes/.
So here's a simple example of creating a library called kQuery in CoffeeScript that allows you to 1) create named instances and 2) add plugins:
instances = {}
kQuery = (name) ->
K = (name) ->
return instances[name] if instances[name]
instances[name] = new kQuery name
K.fn = kQuery.prototype
That's it! Now if someone were to write
K.fn.plugin = -> console.log 'foo'
K('whatev').plugin()
they'd see foo on their console. Note that the reason for the separate kQuery and K functions is that if you called new K from within the K function, you'd get an infinite loop (which would resolve to an error).
Could someone write down a very simple basic example in javascript to conceptualize (and hopefully make me understand) how the jQuery plugin design pattern is done and how it works?
I'm not interested in how creating plugin for jQuery (so no jQuery code here at all).
I'm interested in a simple explanation (maybe with a bit of Javascript code) to explain how it is done the plugin concept.
Plz do not reply me to go and read jQuery code, I tried, but I it's too complex, otherwise I would have not post a question here.
Thanks!
jQuery has a library of functions stored in an internal object named fn. These are the ones that you can call on every jQuery object.
When you do $("div.someClass") you get a jQuery object containing all <div> elements of that class. Now you can do $("div.someClass").each( someFunction ) to apply someFunction to each of them. This means, that each() is one of the functions stored in fn (a built-in one in this case).
If you extend (add to) the internal fn object, then you automatically make available your custom function to the same syntax. Lets assume you have a function that logs all elements to the console, called log(). You could append this function to $.fn, and then use it as $("div.someClass").log().
Every function appended to the fn object will be called in such a way that inside the function body, the this keyword will point to the jQuery object you've used.
Common practice is to return this at the end of the custom function, so that method chaining does not break: $("div.someClass").log().each( someFunction ).
There are several ways to append functions to the $.fn object, some safer than others. A pretty safe one is to do:
jQuery.fn.extend({
foo: function() {
this.each( function() { console.log(this.tagName); } );
return this;
}
})
Tomalak already posted almost everything You need to know.
There is one last thing that helps jQuery do the trick with the this keyword.
it's amethod called apply()
var somefunction=function(){
alert(this.text);
}
var anObject={text:"hello"};
somefunction.apply(anObject);
//alert "hello" will happen
It really helps in creating abstractions so that framework/plugin users would just use this as intuition tells them, whatever there is inside Your code
It works, as many other js frameworks, using javascript prototype orientation.
For instance you can declare a simple function
var alertHelloWorld = function() {
alert('hello world');
}
And then tie it to an existing object (including DOM nodes)
document.doMyAlert = alertHelloWorld;
If you do this
document.doMyAlert();
The alertHelloWorld function will be executed
You can read more about javascript object prototyping here