I wrote a JavaScript file named global.js that has the following contents:
;
var Globals =
{
function getAppRoot() {
if (typeof (jQuery) !== "undefined")
return $("#ApplicationRoot").attr("href");
};
appRoot : getAppRoot();
};
Then in my HTML file (ASP.NET MVC project), I included my JavaScript file like so:
<link rel = "home" id = "ApplicationRoot"
href = "#Url.Content("~/")" />
<script src = "#Url.Content("~/Scripts/jquery-1.8.3.js")"
type="text/javascript"></script>
<script src = "#Url.Content("~/Scripts/global.js")"
type = "text/javascript"></script>
And then, in the HTML file, inside a SCRIPT tag, I write:
$(document).ready(
function() {
alert("Globals.appRoot = " + window.Globals.appRoot);
} );
However, when I run the code, it tells me that Globals is undefined.
UPDATE
Thank you, all. I just noticed that I'd forgotten the equal to sign (assignment operator) for one.
Another important thing that I observe now (which I wasn't fully sure of) is: I am assuming from your comments that an object declaration like so:
var foo = { /* cannot have anything that does not adhere to the bar : gar syntax? */ }
ANOTHER UPDATE
The thing is: if I made appRoot a method by doing so:
var Globals =
{
appRoot : function() { }
};
or like so:
var Globals =
{
appRoot : function getAppRoot() { }
}
The client would have to invoke appRoot with a set of following parenthesis. I would like for appRoot to be a property instead of a method. How do I do that?
FINAL UPDATE
I now have changed my code to read as follows:
// globals.js
// I understand that the starting semi-colon is not
// required. I'd left it in for reasons that it is used
var Globals =
{
appRoot : $("#ApplicationRoot").attr("href");
};
// inside the HTML file in $(document).ready();
if (tyepof(Globals) == "undefined" || Globals == null)
alert("Globals is either undefined or null");
else
alert("Globals.appRoot = " + Globals.appRoot);
I get the alert message Globals is either undefined or null.
ANSWER
Okay, finally. Thanks for all your help. I had another minor syntax error in the object declaration/initialization of the Globals object.
Since appRoot was a member of the object, and I was using the object initializer syntax, I should not have terminated the declaration of appRoot with a semi-colon. Instead, I should either have used a comma or just left it without any terminating character since it was the last (and the only member of Globals).
You need to re-write your globals.js, something like this should work:
var Globals = {
appRoot : function() {
if (typeof (jQuery) !== "undefined") {
return $("#ApplicationRoot").attr("href");
}
}
};
Your global.js should look more like this:
//; << not needed
var Globals = /*equal to missing*/
{
appRoot : function getAppRoot() {
if (typeof (jQuery) !== "undefined")
return $("#ApplicationRoot").attr("href");
}
};
Related
I'm creating a function that tests Angular filters using Jasmine. The specs are ran by Karma. The idea is to pass a module and filter name, with an array of tests to be performed on it. Every element of that array has a description, an input value and an expected result. But it also could contain a testSteps function for tests that are not as simple as passing an input value and expecting an exact value. The function I'm making is meant to create the corresponding Jasmine describe and it blocks for the tests, and it's inside a global variable defined like this:
var $uite = {
testFilter : function(filterName, moduleName, tests) {
this.filterObject = null;
this.isDefined = function(vble) {
return typeof (vble) != 'undefined';
}
describe('FILTER: ' + filterName, function() {
beforeEach(module(moduleName));
beforeEach(inject(function($filter) {
filterObject = $filter(filterName);
}));
for (var i = 0; i < tests.length; i++) {
var test = tests[i];
it(test.it, function() {
if (typeof (test.forInputValue) != 'undefined') {
var result = filterObject(test.forInputValue);
expect(result).toEqual(test.resultShouldBe);
} else if (typeof (test.testSteps) != 'undefined') {
test.testSteps();
}
});
}
});
}
}
The code for my tests is:
$uite.testFilter('nameFilter', 'app', [ {
it : 'gets male gender from a name ending in O',
forInputValue : 'Pedro',
resultShouldBe : 'el tal Pedro'
}, {
it : 'gets female gender from a name ending in A',
forInputValue : 'Carolina',
resultShouldBe : 'la tal Carolina'
}, {
it : 'transforms Lina into la tal Lina',
testSteps : function() {
var result = filterObject('Lina');
expect(result).toEqual('la tal Lina');
}
} ]);
It works just fine but just for curiosity and because I'm avoiding creating unnecesary global variables, I wrote the following test just after them:
describe('some test',function(){
it('works',function(){
expect(typeof(filterObject)).toEqual('undefined');
});
});
Which fails because type of filterObject is function. If my filterObject is defined inside the $uite object and was not (was it?) declared implicitly, then why is it accessible from another describe/it block set?
Your question: Am I creating a global variable?
TL;DR
yes
Full answer
It is global. You're making it global here:
filterObject = $filter(filterName);
If you don't put var before that, and you're not using strict mode (e.g. use strict;), then it will be a global.
If you want it to refer to this, you need to use this everywhere:
beforeEach(inject.call(this, function($filter) {
this.filterObject = $filter(filterName);
}.bind(this)));
Or something like that. Alternatively, you can declare var _this = this:
beforeEach(inject(function($filter) {
_this.filterObject = $filter(filterName);
}));
Everywhere else throughout your code, you'll need to refer to it as this.filterObject.
FYI, a note about strict mode (article on MDN) (I always suggest using it, because it catches accidental globals) from the section "Converting mistakes into errors":
First, strict mode makes it impossible to accidentally create global variables.
Additional references:
Function.prototype.bind on MDN
Function.prototype.call on MDN
P.S. Looks like you're coming from a Java background. When using objects, defining this.<whatever> and then trying to refer to it as simply <whatever> won't work in JavaScript like you'd expect it to work in Java.
Edit
To access filterObject in your third test, do this:
// ... in $suite
} else if (typeof (test.testSteps) != 'undefined') {
// make this.filterObject available as a parameter
test.testSteps(this.filterObject);
}
// then in your test definition...
}, {
it : 'transforms Lina into la tal Lina',
testSteps : function(filterObject) { // this line is important
var result = filterObject('Lina');
expect(result).toEqual('la tal Lina');
}
} ]);
I got js code from a design company, but I do not understand the reason for passing a function to a self executing function.
Here is the outline of the code.
(function(core) {
if (typeof define === "function" && define.amd) {
define("abc", function() {
var abc;
abc = window.Abc || core(window, window.jQuery, window.document);
abc.load = function(res, req, onload, config) {
var base, i, load, resource, resources;
resources = res.split(",");
load = [];
base = (config.config && config.config.abc && config.config.abc.base ? config.config.abc.base : "").replace(/\/+$/g, "");
if (!base) {
throw new Error("Please define base path to Abc in the requirejs config.");
}
i = 0;
while (i < resources.length) {
resource = resources[i].replace(/\./g, "/");
load.push(base + "/components/" + resource);
i += 1;
}
req(load, function() {
onload(abc);
});
};
return abc;
});
}
if (!window.jQuery) {
throw new Error("Abc requires jQuery");
}
if (window && window.jQuery) {
core(window, window.jQuery, window.document);
}
})(function(global, $, doc) {
var _c = {};
...
return _c;
});
Is there benefit of writing code such way over something like below?
(function( core, $, undefined) {
...
} (window.core= window.core|| {}, jQuery )};
Is this some advanced technique?
Basically, ....kinda.
In Javascript, functions are treated as first-class objects. This means you can pass them around in variables and whatnot. The first part, (function(core) { ... }), creates an anonymous function, taking a single argument called core. The parentheses around the function basically just resolve to a function. The second part, (function(global, $, doc) { ... }), is creating another function, which is passed immediately into a call to the first function as the value of core.
Put this way, here's what's happening.
// Define the first function (the one that takes core)
var firstFunc = function (core) { /* ... */ };
// Define the second function (the one that takes global, $, and doc)
var secondFunc = function (global, $, doc) {
var _c = {};
/* ... */
return _c;
};
// Call the first, passing in the second.
firstFunc(secondFunc);
The above code and the code you posted accomplish the same thing. One purpose for writing something like this would be to sandbox the second function so that the first can specify its own local versions of variables global, $, and doc, which avoids conflicts with, say, active-running versions of jQuery (which typically declares its own globally-scoped $ variable).
EDIT: Now that the code in the first function has been filled in, we can say for sure that the reason for doing this is to resolve dependencies and ensure they are present before manually passing them into the second function. From the look of the code provided, it appears that this is enforcing the presence of abc (which I'm assuming is some dependency) via require.js, as well as ensuring that jQuery is present. In addition, it looks like the values in _c returned from the function are used as a part of that dependency enforcement process, though I can't tell exactly how by looking at it.
<script src="http://domain.com/source1.js"></script>
<script src="http://domain.com/source2.js"></script>
source1.js
var PICTURE_PATH = "";
var PICTURE_ROOT = base_url+"YOUTAILOR_files/";
var PROGRAM = parseInt("1");
source2.js
if(PROGRAM==3 || PROGRAM==4 || PROGRAM==5)
{
}
I could not access value of program in source2.js..
When you declare var source1Var outside a function you are actually creating a variable on the window object. So you should just be able to access it from source2.js. Just make sure source1.js is before source2.js in the script tags...
If however you're declaring it within a function, it will be private to that function. If you really need to you could set it on window explicitly.
In source1.js
function foo() {
window.source1Var = 3;
}
In source2.js
function bar() {
console.log(source1Var); // this will search window if it cannot find in the local scope.
}
What is the problem you're trying to solve? It is generally better to use some form of dependency injection, event listeners, builder pattern etc. rather than using global variables.
do something like in your first .js
var VAR = {
myvalue: "hai"
};
then call it in second like
alert(VAR.myvalue);
It's easier than you think. If variable is global, you should access it from anywhere.
// source1.js
var colorCodes = {
back : "#fff",
front : "#888",
side : "#369"
};
And in another file:
// source2.js
alert (colorCodes.back); // alerts `#fff`
I load the same script in my page many times. I have some trouble on decide which is loaded first/after in my website, due to the async/load functions.
So, I'd like to put a global variable that count, when the script is loaded, the order of them.
So myScript.js will start with :
(function () {
var privateNumberScriptLoaded;
if (numberScriptLoaded === undefined) {
numberScriptLoaded = 0;
}
else {
numberScriptLoaded = numberScriptLoaded + 1;
}
privateNumberScriptLoaded = numberScriptLoaded;
console.log(privateNumberScriptLoaded);
})();
but when I load it with :
<script src="http://www.mywebsite.com/widget/myScript.js?type=normal" type="text/javascript"></script>
<script src="http://www.mywebsite.com/widget/myScript.js?type=rotation" type="text/javascript"></script>
I get (for two times) numberScriptLoaded is not defined.
How can I resolve this trouble? In fact I'll "create" a global variable in my website if it doesnt exist. Than increment it and store in a "private" variable for each script, so I can save the order of the execution for each script.
At present, your script falls prey to The Horror of Implicit Globals. I'd recommend not doing that.
You have three options:
As all global variables end up as properties on window, you could use window explicitly:
if (!window.numberScriptLoaded) {
window.numberScriptLoaded = 1; // 1, not 0
}
else {
++window.numberScriptLoaded;
}
Unlike the code without the window. prefix, that won't throw a ReferenceError, because looking up a property on an object works differently from resolving a freestanding identifier.
Live demo | demo page source | source of script it loads
Always put var numberScriptLoaded; (with no initializer) at global scope in your script, e.g. outside your scoping function:
var numberScriptLoaded; // No initializer (no = 0 or anything)
On the first load, this will create the variable; on subsequent loads, it's a no-op. Then you can do this without a ReferenceError:
if (!numberScriptLoaded) {
numberScriptLoaded = 1; // 1, not 0
}
else {
++numberScriptLoaded;
}
Live demo | demo page source | source of script it loads
Use typeof. If you take the typeof a variable that doesn't exist, you don't get a ReferenceError; you get "undefined". Then you can create it via the window. prefix (so you're not falling prey to The Horror).
if (typeof numberScriptLoaded === "undefined") {
// Assigning to window.numberScriptLoaded creates the global
window.numberScriptLoaded = 1; // 1, not 0
}
else {
++numberScriptLoaded;
}
Live demo | demo page source | source of script it loads
You should use typeof
if (typeof numberScriptLoaded === 'undefined') {
Try
if ( 'undefined' === typeof numberScriptLoaded ) {
numberScriptLoaded = 0;
} else {
numberScriptLoaded = numberScriptLoaded + 1;
}
myGlobalVar = typeof myGlobalVar == "undefined"? "New Value" : myGlobalVar;
myGlobalVar = typeof myGlobalVar == "undefined"? "Totally New Value" : myGlobalVar;
alert(myGlobalVar);
http://jsfiddle.net/8gnuwaah/2/
Global variables are direct attributes of window object. So if you'd like to init global variable from anywhere just type:
window.variableName = "what_ever_you_want"
As a best practice and to prevent this type of errors, all variables should be initialized before being used in your script.
You should put:
var numberScriptLoaded;
Just before your closure and the error won't happen.
If you're going to use the window to store the global, then you can do it in a single line with:
window.numberScriptLoaded = (window.numberScriptLoaded || 0) + 1
I am relatively new to javascript and I am facing some difficulty.I have two java script files as I have shown below. I am having trouble getting the value of the variable entry_title inside the getRss function and storing it inside the variables Rss1_title and Rss2_title . Creating a global variable and assigning it to entry_title will make things worse as I will not be able to know from which Rss url the title came from. Is there a easy way to get the value of the callback functions ?
<script type="text/javascript" src="jsRss.js"></script>
<script type="text/javascript" src="notification.js"></script>
My notification.js file
function get_rss1_feeds(){
var Rss1_title = getRss("http://yofreesamples.com/category/free-coupons/feed/?type=rss");
}
function get_rss2_feeds(){
var Rss2_title = getRss("http://yofreesamples.com/category/real-freebies/feed/?type=rss");
}
setTimeout('get_rss1_feeds()',8000);
setTimeout('get_rss2_feeds()',7000);
My jsRss.js file:
function getRss(url){
if(url == null) return false;
google.load("feeds", "1");
// Our callback function, for when a feed is loaded.
function feedLoaded(result) {
if (!result.error) {
var entry = result.feed.entries[0];
var entry_title = entry.title; // need to get this value
}
}
function Load() {
// Create a feed instance that will grab feed.
var feed = new google.feeds.Feed(url);
// Calling load sends the request off. It requires a callback function.
feed.load(feedLoaded);
}
google.setOnLoadCallback(Load);
}
Errors :
When the setTimeout(get_rss1_feeds, 8000); method is called I get a blank screen.
I get a error in my console saying octal literals and octal escape sequences are deprecated and it is pointing to the 6th line in this script.
Is it because I am using google-api for parsing my Rss?
if (window['google'] != undefined && window['google']['loader'] != undefined) {
if (!window['google']['feeds']) {
window['google']['feeds'] = {};
google.feeds.Version = '1.0';
google.feeds.JSHash = '8992c0a2cdf258e5bd0f517c78243cd6';
google.feeds.LoadArgs = 'file\75feeds\46v\0751';
}
google.loader.writeLoadTag("css", google.loader.ServiceBase + "/api/feeds/1.0/8992c0a2cdf258e5bd0f517c78243cd6/default+en.css", false);
google.loader.writeLoadTag("script", google.loader.ServiceBase + "/api/feeds/1.0/8992c0a2cdf258e5bd0f517c78243cd6/default+en.I.js", false);
}
Seeing as it's a different scope, you can either return it in a callback, or provide it in another way such as exporting it to a higher scope that is visible to your desired location. In this case, it's the global scope, so I'd advise against that.
function getRss(url, callback) {
//...
function feedLoaded(result) {
if (!result.error) {
var entry = result.feed.entries[0];
var entry_title = entry.title; // need to get this value
callback && callback(entry_title);
}
}
and call it like so,
function get_rss1_feeds() {
var Rss1_title = getRss("http://yofreesamples.com/category/free-coupons/feed/?type=rss", function(entry_title) {
// This scope has access to entry_title
});
}
As an aside, use your setTimeout like so:
setTimeout(get_rss1_feeds, 8000);
rather than
setTimeout("get_rss1_feeds()", 8000);
as the latter uses eval, whereas the former passes a reference to the function.
Eventhough it will make your code a mess, you can append the variables to the window object.
For example:
function a()
{
window.testStr = "test";
}
function b()
{
alert(window.testStr);
}
Or even create your own object, instead of using window, as such:
var MyRSSReader = {
TitleOne : '',
TitleTwo : ''
}
MyRSSReader.TitleOne = "My title";
Wikipedia has a nice article about global variables, and why they are bad.