I have this big "class".
function MyFunc(){
this.prop = true;
}
MyFunc.prototype.method1 = function(){
// code here
}
etc, lots of methods in one file. and then, the instance is created and run on document.ready
And then, I have one particularly large method, that I would like to move to a separate file. However, when I move it and include them one after another, main file first, the second one says MyFunc is not defined. I cannot add that prototype.method declaration on document.ready, also, since it has to be ready before instance is initialized.
What pattern should I use here to properly organize my code? Thanks.
Related
Following http://processingjs.org/articles/PomaxGuide.html for using Processing sketches on webpages, one of my functions utilizes this perfectly:
function drawSomething() {
// some calculations
var pjs = Processing.getInstanceById('canvasID');
var number = 5 // placeholder result of calculations
pjs.drawText(number);
}
Yet with another function, drawSomethingElse, the same pjs variable definition logs:
TypeError: pjs is undefined
All the code is wrapped in docReady, and drawSomething(); is called when the page loads:
$(document).ready(function(){
// do lots of stuff
drawSomethingElse();
}
Scope in javascript works like this. If you declare a var or function inside another function it's only visible inside this function
function outerScope(){
var outerVariable = "is defined in outer scope";
function innerScope(){
var innerVariable = "is defined in inner scope";
console.log(outervariable); //innerScope can see outerVariable (through a closure)
}
console.log(innerVariable) //=undefined outerScope can't see innerVariable
console.log(outerVariable) //outerScope can still see outerVariable
}
console.log(outerScope) //= function, global scope can see outerScope
console.log(outerVariable) //=undefined but global scope can't see inside outerScope
console.log(innerScope) //= undefined, therefore it can't see innerScope
console.log(innerVariable) //=undefined and of course not into inner scope
This is true for all functions, including jQuery functions, they are no exception to this rule. So that's why you have to define a var in the scope you want the scope "layer" you want to use it. And to not pollute the global scope you wrap things into these anonymous functions, just to add a scope "layer"
This model always applies, no matter how many layers you add. You will always be able to understand the behavior. (btw always check all the things with console.log you are unsure about, it helps to track down bugs. the more precise you can answer what is wrong with your solution the better you know how to fix it)
Adapting what you know about scopes and since you didn't define Processing in the current scope you know it therefore must be in global scope, means you can open your browser console and just console.log(Processing) and maybe call the method Processing.getInstanceById() yourself in the console a few times. Maybe it's not the canvas id, maybe it's the name of your sketch that defined the name of the instance. Try it out.
Since you now know that your .pde sketch isn't loaded by the time you want to get the instance via javascript, you have a few options. The easiest would be to make the sketch part of the document, so the $(document).ready() only fires and execute your javascript when both, processing and the sketch are loaded.
Usually processing checks the custom data-processing-sources attribute on the canvas and sends a asynchronous request for the files (your sketch). But since it's asynchronous it's not part of your document loading, so the document is ready but your sketch isn't.
If you instead put the sketch code in a script tag inside the document the document won't be ready until it's loaded. You also need to set the mime type or the browser will think this is javascript and throw an error. It doesn't change anything else, it's just another way of setting up your Processing Sketch.
<script type="text/processing" data-processing-target="canvasID">
//your sketch code
</script>
<canvas id="canvasID"></canvas>
And for you to still be able to load your sketch externally here comes the slightly more confusing 3rd way to set up your sketch. Remove the whole script tag and your sketch.
Skip the data-processing-target and data-processing-sources attributes, and instead of pjs = Processing.getInstanceById write
$(document).ready(function(){
var xhr = new XMLHttpRequest();
xhr.open("GET", "yourSketch.pde");
xhr.onload = function(){
var code = xhr.response;
var canvas = document.getElementById("canvasID")
pjs = new Processing(canvas,code);
//rest of your code
}
xhr.send();
});
Note: This technique won't work if you view your website locally from the file:// protocol
pjs scope is drawSomething function for using it in different function change your code like this
(function() {
var pjs = Processing.getInstanceById('canvasID');
function drawSomething() {
var number = 5 // placeholder result of calculations
pjs.drawText(number);
}
function someotherfunction() {
drawSomething();
}
}());
now you can use pjs anywhere in this anon function
It keeps me from easily defining global variables and its often a nuisance. Why doesn't the code outside functions that are called execute? For example, if I call the function myFunction from HTML, this works...
function myFunction() {
var myObject = document.getElementById("myHTMLObject");
myObject.style.backgroundColor = "blue";
}
but not this...
var myObject = document.getElementById("myHTMLObject");
function myFunction() {
myObject.style.backgroundColor = "blue";
}
If I call the function from the HTML, only the code inside that function will run (unless that function calls other functions). Am I making a mistake or is there a way around this? I don't want to encompass all my code in a window.onload function.
P.S. I run my html on Chrome if it makes a difference.
Thanks for any help.
It does execute, and does when when the script runs, which is when the <script> element is parsed.
If you try to get an element that is added to the DOM by HTML that appears after the <script>, then it won't exist when you look for it so you will get nothing back.
If the <script> appears after the element, then you won't have a problem.
If this example:
var myObject = document.getElementById("myHTMLObject");
function myFunction() {
myObject.style.backgroundColor = "blue";
}
doesn't work, then here are a couple possible reasons:
The script is running too early and thus when you do document.getElementById("myHTMLObject");, the page has not yet been loaded and thus myHTMLObject does not exist yet.
You have more than one global definition of myObject and one is overwriting the other.
Your second coding example is recommended for a number of reasons:
Doesn't use a global variables which is advantageous (variables are private to within the function and can't create conflicts with any other code or be interfered with by any other code).
The functionality is entirely contained within the function
There are no timing related issues with when the initialization code is run because the DOM is searched only when the operation is about to be carried out.
Getting DOM objects when needed works better with dynamically added HTML.
A simple user, triggered operation is plenty fast getting a DOM object when needed.
A simple question.
I have a web project includes multi JavaScripts.
JS:
// (1) Event
$('.input').keyup(function()
{
keyUpFunction();
});
// (2) Function
function keyUpFunction(){ ... }
(1),(2) which should come first in one javascript file? If the browser read the function first, does it store the function in memory and invoke it when scan the event.
In some case, the same function is defined in multi javascript . e.g.
prm.add_endRequest(function() {
fn1();
fn2();
});
$(document).ready(.......)
Should I duplicate the function name and define each component in each js file.
or keep the function declare in one file and invoke sub-function composite the function?
Functions defined in the following manner:
function fooBar(){}
Are 'hoisted' to the top of the current scope. This means they will always be available, in the current scope, even if they are defined at the end of the file.
This does not hold true if you defined you functions like this:
var fooBar = function(){};
These functions are not hoisted, and must be defined before they can be used.
It should be noted that in your specific example, keyUpFunction will only be called once a keyup event has fired. This also means that all javascript on your page will already be evaluated, so the keyUpFunction will be defined (parsed) already regardless.
EDIT: To be more explicit, this first example is okay:
doSomething('hello world');
function doSomething(str){
console.log(str);
}
However, this will cause you problems:
doSomething('hello world');
var doSomething = function(str){
console.log(str);
}
#Matt's answer covers the function hoisting stuff nicely.
To avoid function name clashes within multiple files, wrap your content in an immediately invoked function expression, e.g.:
(function() {
// put your variables functions here
...
// register event handlers
})();
Any variables or functions declared therein will be constrained to that scope.
I have a situation where I'm trying to consolidate several Javascript files into one, and conditionally apply them. I don't want to modify the actual files. Is there a way I can wrap these files and call them on demand?
The catch is, some of these files have function xyz() {} in them. So, wrapping them with if (false) { function xyz() {} } makes bad things happen.
For example, if this is my code...
if (includeFile) {
/* The file */
function foo() {}
/* The file */
}
The problem becomes that Chrome will see foo() and place it in the global scope even if includeFile is false.
The easy solution would be to modify it to be var foo = function() {} but I can't modify these files.
I also have a general concern about running eval() on these functions since they are fairly huge. (Think jQuery wrapped in a function. If this isn't a problem then maybe eval is the answer?)
I was hoping I could nest functions and pass window in as the scope, but tried it on jsFiddle and it didn't seem to work.
(function() {
function foo() {
alert('it works');
}
}).apply(window, []);
foo();
There are a few similar questions. But, none addressed the same situation that I have. Thanks.
Have you considered using a library like require.js? There are several libraries out there that can do this for you in a more elegant fashion.
If you don't want a dependency-loading library, but you're using jQuery or some similar library, you can load scripts conditionally using an AJAX request (in jQuery, you'd use the script dataType). This is far better than a simple eval(), but less robust when you're trying to manage a series of dependencies.
Another option here, if you want to simply concatenate everything, is to wrap each file in an anonymous function and then assign the necessary elements to the window object, placing them in the global scope:
(function(window) {
/* file 1 here */
function xyz() {
// etc ...
}
/* end file 1 */
// now selectively choose what you want to be
// in the global scope
window.xyz = xyz;
}(window));
xyz();
This requires more work for you, however, to identify what you want to be available globally. Note that it's note necessary to pass window in as an argument to the anonymous function, but it's not a bad idea if you're going to be be referring to it multiple times (this speeds up references and allows for variable-name munging during code compression).
Just wanted to know if it was a good JavaScript practice.
Let's say I have many Web pages that all call an initialization function "init()", would it be the right thing to use an IIFE inside my pattern to run the function everytime the script is loaded?
var foo = (function() {
var bar = "something";
(function init() {
// Do something crazy that's gonna be the same across all my web pages
// like adding an event listener or something
// ...
document.write('page init...');
}());
function privatePage1() {
// This stuff is gonna be used only in page1.html via foo.privatePage1
document.write('page 1' + bar);
}
function privatePage2() {
// This stuff is gonna be used only in page2.html via foo.privatePage2
document.write('page 2' + bar);
}
return {
privatePage1: privatePage1,
privatePage2: privatePage2
}
}());
This is a pretty subjective area, but here's my take:
When you use the module pattern, you're providing a contained set of functionality to the rest of your code. It's essentially a mini-library.
In general, I wouldn't expect a library to do anything when I load it, other than initialization steps that are entirely internal to the library (e.g. setting up the configuration, instantiating a few necessary objects, etc) - nothing that actually affects the DOM or otherwise significantly alters the environment (which is why I've never been entirely comfortable with libraries like Date.js or Prototype that change the prototypes of basic objects).
There are a couple of reasons for this, but the main one is that I don't want to have to worry about the load order of my libraries/modules, other than simply managing dependencies. Independent modules shouldn't affect each other at all. When you manipulate the DOM in your module at load time, sooner or later you'll realize that another piece of your code is expecting the DOM to be in a certain state at a certain time, and that you now have to care about whether you load your module before or after that time. This is an extra bit of complexity that's essentially hidden in the script tag that loads your module.
The other issue here is portability and adaptability. Maybe you'll want to use your module in another project with another DOM setup. Maybe you'll want to pass a different DOM element or config variable to the init() function on a specific page. If you execute init() automagically, you lose the opportunity for configuration.
So what I generally do is to set the init() method as an attribute of the returned module object:
var foo = (function() {
function init() {
// Do something crazy that's gonna be the same across all my web pages
}
//...
return {
init: init,
// etc
}
}());
and then call it as needed elsewhere in my code:
foo.init();
Yes, this adds an extra line of redundant code to the initialization for all my pages (though this is probably just one other script anyway, so the added weight is all of 11 characters). But it allows me a more fine-grained control over when the module is initialized, and offers a hook for configuration arguments when I (inevitably) determine I need them later.
Is the init() function the same across web pages? If so, this is what I'd do:
var foo = (function()
{
init();
return {};
}());
If not, I don't see a reason to use an IIFE, and would simplify your original code like so:
var foo = (function()
{
/* body of the original IIFE here */
return {};
}());