I have a jquery function like this:
(function($){
$.fn.myjqfunction = function(cfg){
var foo1, foo2;
return this.each...
};
})(jQuery);
How can I make foo1 and foo2 to be accessible from outside (from another function like this)?
These variables will store the state of some things that affect the entire document, and I want the other function to be aware of that...
Declare them outside the function, i.e., global.
You may want to put them in a namespace/object/module to be on the safe side. Which method is best depends on what you're actually doing with them.
For example, if they're related to specific selectors, it might be "best" to attach them directly to the DOM elements using .data, or keep them inside another jQuery function, etc.
Set up your function like this:
(function($){
function myjqfunction( cfg ) {
return this.each( ... );
}
$.myjqfunction = {
foo1: ... ,
foo2: ...
};
$.fn.myjqfunction = myjqfunction;
})(jQuery);
Then from outside your plugin, code can refer to $.myjqfunction.foo1 to get at those variables, and you'd refer to them the same way from inside your plugin code.
There are of course other similar ways to set that up.
Related
I am writing a jQuery plugin which, ideally I would like in it's own namespace.
So far, this seems to work (in terms of namespace nesting)
(function($) {
$.fn.nspace = {
foo: function() {
// Does not work becuase $(this) is not the correct selector.
$(this).show();
}
}
})(jQuery);
So given then example above, I might call my function like so:
$("html, body").nspace.foo();
but $(this) is not [html, body]...How can I solve this?
EDIT: To clarify (based on user comments)...
$("html, body").nspace.foo(); should call foo for [html, body] but, $(this) inside nspace resolves to nspace...so it's trying to call nspace.foo();
You shouldn't do this, but just because I dislike when someone says "You can't" in programming (often untrue, especially in Javascript) - here's how you could do this:
The jQuery object is constructed each time using its prototype.init function, which is aliased to fn.init, so you could overwrite it with a wrapped function that adds your namespace object in a way that doesn't harm any existing usage or libraries, like so:
(function($) {
var baseInit = $.fn.init;
$.fn.init = function(selector, context, rootjQuery) {
// Instantiate jQuery the way it expects
var j = new baseInit(selector, context, rootjQuery);
// Add our extra object/namespace
// Use j inside to refer to the current jQuery object
j.nspace = {
foo: function() {
j.show();
}
};
// Return it all and other libraries are none the wiser
return j;
}
})(jQuery);
http://jsfiddle.net/b9chris/7TPZY/
You should consider using the classic pattern for a jQuery plugin: define only one method: in your case, nspace. Inside this method, you'll take every case into account. Sounds hard, but it's pretty easy once you've looked into that.
(By the way you definitely have to look at that when writing a jQuery plugin)
You can't add an object as a plugin and still get the jQuery object that was used to get the object. You simply have no reference to that jQuery object when you call a method in your object.
Put the function directly as the plugin:
(function($) {
$.fn.nspace = function() {
this.show();
};
})(jQuery);
Usage:
$("html, body").nspace();
(Note that the object is the jQuery instance, not a selector or an element, so you don't need to use $(this)).
Let's say I have a lot of instances of $(this).show("slow", function(){fVar;}); where $(this) are different objects at different times, but they all need .show("slow", function(){fVar;}); and fVar is a previously defined function var.
Is it possible to set .show("slow", function(){fVar;}); as a var like "myVar" so I could theoretically do something like $(this).myVar();
You sure can. Check out the jquery docs
(function( $ ) {
$.fn.myPlugin = function() {
// Do your awesome plugin stuff here
};
})( jQuery );
don't forget about proper namespacing! And just use the method that you declare (so mPlugin) just as you would any other JQuery method
I'm not so much into JQuery but try this -
$.prototype.myVar=function(){
//here goes your code
}
just create it as a function expression and you can use it wherever you want. this function takes in an event object that is created by an event listener. ie: click functions. use this var as your event function callback and pass in the event object so it knows what to show.
var showSlow = function(eventObject){
$(eventObject).show("slow", function(){
fVar;
});
}
i was exploring in the last few days how big frameworks works , how they assign their function name and it can't(?) be override , i pretty much know how framework work with anonymous function , for example they do it this way or similar version :
(function(){
var Sizzle = function (){
var x;
};
Sizzle.f = function(){
alert("!");
};
window.Sizzle = Sizzle;
})();
i still don't get few things about those huge frameworks and i hope i can find answer :
how do they assign function name and the name can't be override?
in the code above to call the function i need to write Sizzle.f() to get the function to work , but when i use jquery i don't write Jquery.show() , just show() , how do they vanish the "jquery" from "jquery.show()" function call?
by saying the name can't be override i mean , if i create function with one of the jquery functions names , the jquery function will work.
thanks in advance.
As has been shown for #2, it's really easy for BIG_NAMESPACE.Functions.doStuff to be added to anything you want.
var _ = BIG_NAMESPACE.Functions.doStuff;
_(); // runs BIG_NAMESPACE.Functions.doStuff;
As for #1:
Most libraries DO let their functions be overwritten.
It's the values that are inside of the framework's closure which are preserved, for safety reasons.
So you could do something like:
BIG_NAMESPACE.Functions.doStuff = function StealEverything() {};
(BIG_NAMESPACE.Functions.doStuff === StealEverything) // true;
But doStuff would have NO access to any of the variables hidden inside of the framework's closure.
It would also mean that until the page was reloaded, doStuff would also not work the way you want it to.
HOWEVER, in newer versions of JavaScript (ECMA5-compatible browsers), it WILL be possible to do something like what you're suggesting.
BIG_NAMESPACE = (function () {
var do_stuff = function () { console.log("doin' stuff"); },
functions = {
set doStuff (overwrite) { }
get doStuff () { return do_stuff; }
};
return { Functions : functions };
}());
Then, this will work:
BIG_NAMESPACE.Functions.doStuff(); // "doin' stuff"
BIG_NAMESPACE.Functions.doStuff = function () { console.log("ain't doin' jack"); };
BIG_NAMESPACE.Functions.doStuff(); // "doin' stuff"
However, Frameworks aren't going to use this for a LONG time.
This is not even remotely backwards compatible. Maybe in 2016...
There were defineGetter and defineSetter methods as well, but they aren't a formal part of the JavaScript language. Like innerHTML, they're things that the browser vendors put in, to make life better... ...as such, there's no real guarantee that they're going to be in any/all browsers your users have. Plus, they're deprecated, now that new browsers use the get and set constructs that other languages have.
(function(){
var jqueree = {};
jqueree.someval = 22;
jqueree.somefunc = function(){ alert(this.someval); };
window.jqueree = jqueree;
window.somefunc = function(){ jqueree.somefunc.call(jqueree); };
window.$$$ = jqueree;
})();
// all equivalent
window.somefunc();
window.jqueree.somefunc();
$$$.somefunc();
somefunc();
Answering your Questions
At the top of jQuery you'll see: var jQuery = (function() {, which creates the local function (its incomplete; the }); occurs elsewhere).
At the very end of jQuery you'll notice the following, which is how it attaches it to the global namespace:
// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;
I have never seen a jQuery function called without referencing the jQuery object. I think you always need to use jQuery.show() or $.show(); however maybe you're saying you don't have to call window.jQuery.show(), which you are permitted to drop the window, since that is the default.
Using your example
(function(){
/* This is where Sizzle is defined locally, but not exposed globally */
var Sizzle = function (){
var x;
};
/* If you put "window.f = Sizzle.f = function(){" then you could *
* call f() w/o typing Sizzle.f() */
Sizzle.f = function(){
alert("!");
};
/* The following line is what makes it so you can use Sizzle elsewhere *
* on your page (it exposes it globally here) */
window.Sizzle = Sizzle;
})();
use function _name_() {} and the name is static
the simply use var $ = jQuery; to create an alias.
jQuery works this way:
Supposed you have this jQuery code:
$("#title").show();
You have three elements to that line.
$ is a javascript function
"#title" is an argument to that function
.show() is a method call
Here's how it works.
Javascript executes the function named $ and passed it an argument of "#title".
That function does it's business, finds the #title object in the DOM, creates a jQuery object, puts that DOM element into the array in the jQuery object and returns the jQuery object.
The Javascript execution engine then takes the return value from that function call (which is now a jQuery object) and looks for and executes the .show() method on that object.
The .show() method then looks at the array of DOM elements in the jQuery object and does the show operation for each DOM element.
In answer to your question, there is no .show() all by itself. It's a method on a jQuery object and, in this example, that jQuery object is returned from the $("#title") function call.
jQuery plugins use a pattern like this to hide private functions of a plugin:
(function ($) {
var a_private_function = function (opts) {
opts.onStart();
}
$.fn.name_of_plugin = function (options) {
a_private_function(opts);
}
})(jQuery);
jQuery then makes those fn functions available like this:
some_callback = function() {};
jQuery('selector').name_of_plugin( { onStart: some_callback } );
Now I'd like to override a_private_function. Is there any way I can access it without patching the actual plugin code?
I thought maybe I could access the execution context of the private function by using caller but that did not work:
some_callback = function() {
console.log(some_callback.caller.a_private_function); // -> undefined
};
jQuery('selector').name_of_plugin( { onStart: some_callback } );
As I learned in this answer, the only way to access the private members of a jQuery plugin are to modify the plugin source itself.
What you have there is a classical example of a closured function.
a_private_function is a function which is only visible within the scope from the "outer" anonymous function. Because of closure, the anonymous function assigned to name_of_plugin has access to the outer context and therefore a_private_function.
This is a good thing since you can protect and hide some of functions and variables.
Short story, there is absolutly zero chance to access a closured variable from the outside.
When using the JQUERY UI widget factory, the functions (which are prefixed with _) are not private, but instead (simulated) protected (prototype) functions.
This means you can access them as long as you extend the existing prototype. For example:
$.extend( $.ui.accordion.prototype, {
open: function( index ) {
//now you can access any protected function
var toOpen = self._findActive( index );
toOpen.next().show();
},
_completed: function ( cancel ) {
//You can even overwrite an existing function
}
});
The function you have demonstrated in your first example is, however, private - and therefore as the other answers suggest you cannot access these from the outside.
However, if you want to access protected variables inside a JQuery UI widget then this is possible (as above).
Thought this might be useful.
I'm working on a proprietary site, and I'm having some issues. I'm using jQuery along with prototype, and I've got it namespaced properly, so in this question assume you can use $ or jQ as a namespaced reference to jQuery.
So I've got a bunch of functions, some mix jQuery and javascript, some plain javascript, some jQuery only. Now, currently some functions are defined within the document.ready jQuery function, and some are defined outside of it, kind of like this:
jQ(document.ready(function($) {
if ( ifConfig ) {
//page check, function calls here
fnc1();
fnc2();
fnc3();
fnc4();
}
function fnc1() {
//fnc code in here
}
function fnc2() {
//fnc code in here
}
}); //end document.ready
function fnc3() {
}
function fnc4() {
}
Now this is all pseudo code, you can assume the functions are valid and have valid code in them. Recently I was doing some debugging, and one of my functions that was declared and called inside the document.ready said it was undefined. I moved it outside of the document.ready, and everything worked again.
I'm basically trying to understand the order of how functions are initiated/called better, so my question is when do you declare functions inside the document.ready and when do you declare them outside? Do you only declare inside when they're called within that document.ready only? Or should I always just declare them outside of that document.ready?
Thanks.
Generally, you should declare & define your own namespace, where all of your application logic (including functions/methods) is located. That way you avoid collision with other scripts on your site + that way your code is much cleaner and easier to maintenaine.
var myapp = function(){
var foobar1 = null,
foobar2 = null,
foobar3 = null;
return {
getFoobar1: function(){
return foobar1;
},
getFoobar2: function(){
return foobar2;
},
setFoobar1: function(foo){
foobar1 = foo;
},
clickhandler: function(e){
alert('I am an event handler, and I am not anonymous');
}
// etc.
};
};
$(document).ready(function(){
var Application = myapp();
Application.getFoobar2();
$(document).bind('click', Application.clickhandler);
});
That pattern (some call it the "method pattern") creates a closured function/object which also guarantees private member variables within your namespace, only accessible through the getter functions from the outside.
This is really only a pretty basic example, you can push this idea & pattern to an extend, which is very nice & a good thing (IMO).
A great book about this stuff which was named and recommended pretty often is "Javascript: The Good Parts" by Douglas Crockford.
If a function is only used inside the document ready function, then declare it inside so you don't pollute the global scope. Otherwise, declare it outside so it the rest of your script has access to those functions.
(document).ready is more used for things that need to be executed at page load, and not function declarations. If you declare them inside of (document).ready, their scope will be local to that block - if they're only used locally, that's fine and they should be declared there. Otherwise, declare them outside.
So in your example, if the functions are only used in that block, they should be declared in there. If they're used other places additionally, they should be declared outside.