i'm following along a book and I have 2 javascript files. Both are in the HTML file as:
<script src="playlist_store.js"></script>
<script src="playlist.js"></script>
however, when I try to call a function from playlist_store.js inside of playlist.js chrome debugger says "uncaught reference error. loadPlaylist is not defined. loadPlaylist() is the function from playlist_store.js
I thought there might be a typo somewhere but I don't think there is. Does playlist.js actually need to somehow import or include / require the playlist_store.js ? Is the browser not smart enough to somehow link them so the functions in one you can call from another?
Defining a function like follows
function myaction () { }
is a named (private) function.
It is better to write a (private) function assigned to a variable:
var myaction = function () { };
Now what you need is a function, that is assigned to a variable in the global object:
myaction = function () { };
// or strict:
window.myaction = function () { };
It is now a global (public) function, so you can use it outside of your defining .js.
Beware that the first example, a function statement doesn't have a semicolon. Using the function operator as in the other examples, you need a semicolon.
Related
I have a js file that exports a function myFunction. Then, I have another function defined outside the exported module. How can I access it dynamically by its name?
I'm trying in this way but it doesn't work:
exports.myFunction = () => {
let functionName = 'helperFunction';
global[functionName]();
}
const helperFunction = () => {
console.log('helperFunction invoked');
}
I'm trying with the global scope global[functionName]();, but doesn't work. What is the scope of the helper function?
The reason why helperFunction is outside the export is because I export multiple functions in the same file that call helperFunction.
TLDR:
Use eval.
Hi there,
I tell you one thing about hoisting and then answer your question.
Now that you have defined your helperFunction after the export, it might cause a problem because of a JS behaviour called hoisting. The declaration of helperFunction is recognized in myFunction, but not the initialization. That will give you the following error:
ReferenceError: Cannot access 'helperFunction' before initialization
So, just move the helperFunction to the top of the file.
Now, to the actual answer. As you might have realized your helperFunction is actually in scope and you can call it. To do this, you need to evaluate the string: helperFunction(). You can use the following snippet:
console.log('hi');
let functionName = 'helperFunction';
eval(`${functionName}()`);
console.log('bye');
Bonus: what you are actually doing with your code is creating an array with one string element and call that array. That, of course, throws the following error:
TypeError: [functionName] is not a function
Theoretically speaking, you can make it work with global.
global.helperFunction = () => {
console.log('helperFunction invoked');
}
const myFunction = () => {
let functionName = 'helperFunction';
global[functionName]();
}
Whether or not this is a good idea... well, that's an entirely different discussion.
I don't know any details, but using Classes is usually the way to go in these cases.
I am newbie in js and I want to override/overwrite some fullcalendar functions from another script (my-fullcalendar.js) to make some changes in it for myself. for example function names are :
formatRange and oldMomentFormat.
formatRange is accessible from this.$.fullCalendar.formatRange but oldMomentFormat is not accessible via this kind of chain. But even when I do something like this in my-fullcalendar.js:
;(function () {
function MyformatRange(date1, date2, formatStr, separator, isRTL) {
console.log( "MyformatRange");
//other parts is exactly the same
// ...
}
this.$.fullCalendar.formatRange=MyformatRange;
console.log(this);
})();
nothing happens because no log is generated and even line by line tracing does not pass from here. but when observing "this" in console log MyformatRange replaced by original formatRange.
another problem is how can I override/overwrite oldMomentFormat function which is not in window hierarchy to access (or I can not find it) ??
OK, let's simplify the problem. In essence, you have this situation:
var makeFunObject = function () {
var doSomething = function (msg) {
console.log(msg);
};
var haveFun = function () {
doSomething( "fun!");
};
return {
doSomething : doSomething,
haveFun : haveFun
};
};
In other words you have a function that is creating a closure. Inside that closure are two "private" functions, one of which calls the other. But both functions seem to be "exposed" in the returned object.
You write some code:
var myFunObject = makeFunObject();
myFunObject.haveFun(); // fun!
Yep, seems to work just fine. Now let's replace the doSomething function in that returned object and call haveFun again:
myFunObject.doSomething = function (msg) {
console.log("My new function: " + msg);
};
myFunObject.haveFun(); // fun! <== wait what?
But wait! The new replacement function is not being called! That's right: the haveFun function was expressly written to call the internal function. It in fact knows nothing about the exposed function in the object at all.
That's because you cannot replace the internal, private function in this way (you cannot replace it at all, in fact, not without altering the original code).
Now draw back to the FullCalendar code: you are replacing the external function in the object, but the internal function is the one that is called by every other function inside FullCalendar.
I realize this is an old question, but I was butting my head against this same problem when I wanted to override the getEventTimeText function.
I was able to accomplish this, from inside my own JS file, like so:
$.fullCalendar.Grid.mixin({
getEventTimeText: function (range, formatStr, displayEnd) {
//custom version of this function
}
});
So, in terms of the function you were trying to override, you should be able to do it with:
$.fullCalendar.View.mixin({
formatRange: function (range, formatStr, separator) {
//custom formatRange function
}
});
Note: Make sure this runs before where you actually create the calendar. Also note that you need to make sure to override the function in the right place. For example, getEventTimeText was in $.fullCalendar.Grid, while formatRange is in $.fullCalendar.View.
Hopefully this helps other people who end up on this question.
I read some JS module design patterns recently. I came across this small code snippet as below.
(function(window) {
var Module = {
data: "I'm happy now!"
};
window.Module = Module;
})(window);
Still not quite understand this code well, my questions are:
How to use/call this module outside this particluar JS file? Need I
assign a variable to this module? e.g. var module1 = (...)(...);
Could anyone explain what the window parameter here stands for?
Is it a good practice to have two/three such kind of modules in the
same file?
The main reason to create an anonymous function in this case is to prevent global object pollution. It's not really a module pattern.
The problem arise when you declare a variable. Without the function scope, the variable will be added to the global object (window). If you were to declare the variables within a function. It would add the variable to the function scope without polluting the global object window.
What happen is that a javascript file could add a variable named foo and on a different file use that variable named foo too. Unless you really want to have a variable shared by two javascript files, it would probably create conflicts and bug that are difficult to fix.
For example: a.js
var foo = "one"
b.js
var foo = "two"
c.js
alert(foo)
In this case, the alert box might show either "one" or "two", depending of the order in the javascript files are included.
But having this a.js:
(function () {
var foo = "one"
})()
b.js
(function () {
var foo = "two"
})()
c.js
(function () {
alert(foo)
})()
This would create an error as you cannot alert a non declared variable.
One way to detect undefined variables, is to make sure to execute the javascript code in strict mode.
To do that, add the string "use strict" at the top of the file or function.
function () {
"use strict"
...
}
Undeclared variable will raise errors and it should be possible to fix the code that way.
Also, if you forget to declare a variable with the var keyword, it might end up adding the variable to the global scope even if the code is scoped into a function. The only way to prevent global scope pollution is to run the code in strict mode.
In the code snippet that you provided, the module with name Module is explicitly added to the window object. You can access the window object from any place in javascript unless the window name is ghosted by an other variable.
Now, back to the modules. If you want to define modules, it can be done in many ways. As an exemple, you could create an object on the window object called modules. In this object, you'll insert your modules.
module.js
window.modules = {}
foo.js
(function (window) {
var module = {}
...
window.modules.foo = module
})(window)
This variant isn't super good as you have to manually add the module to the modules object. You have to manually modify the window object, and that can be subject to errors.
modules.js
window.modules = {}
function define(name, constructor) {
var module = {exports: {}}
constructor(module)
window.modules[name] = module.exports
}
function require(name) {
return window.modules[name]
}
foo.js
define("foo", function (module) {
module.exports.one = function () {
return 1
}
module.exports.plus = function (a, b) {
return a + b
}
})
bar.js
define("bar", function (module) {
module.exports = function () {
var foo = require("foo")
return foo.plus(foo.one(), foo.one())
}
})
This is a module definition that looks a bit like module defined with http://requirejs.org/. It is quite basic as it doesn't take into account module dependencies so if bar is loaded and used before foo. Then the require method won't be able to return the module.
Also, if you want to store modules without having them visible into the global scope, you can only define the require and define method on the window object and hide modules into an anonymous scope like this:
(function (window) {
var modules = {}
function define(name, constructor) {
var module = {exports: {}}
constructor(module)
modules[name] = module.exports
}
function require(name) {
return modules[name]
}
window.define = define
window.require = require
})(window)
This way, define and require are the only function that can give you access to modules. Other modules won't be able to modify other modules without requiring them first. This can be useful when using third parties script that could conflict with your module system.
In fact this is not a module, but a Self-Invoking Ananymous function or an Immediate function which gets an object in parameter and assign a Module property to it:
The page window is a parameter passed to this function.
So an object named Module containing a data property is assigned to window.
JavaScript Self-Invoking Functions:
A self-invoking expression is invoked (started) automatically, without being called.
Function expressions will execute automatically if the expression is
followed by ().
You cannot self-invoke a function declaration.
You have to add parentheses around the function to indicate that it is
a function expression
So As you can see Immediate Functions can't be called as its name states it will be immediately executed and by its self, no other function or scope can execute it.
For better reference take a look at :
Javascript Self Invoking Functions.
Self-Invoking Functions section in JavaScript Function Definitions.
And concerning your last question about its benefits and good practices as shown on the given Article reference:
Where to use self-executing functions?
One obvious situation is when you want to auto-run a function like I
showed in above example but that is trivial. If you are in a situation
where you want to run a piece of code repeatedly like updating
something in the database based on user interaction or fetching
records from database every 10 seconds or you want to load new stories
via ajax similar to how facebook does on its homepage or some other
similar situation, one would normally go for setInterval function
something like this:
setInterval(doStuff, 10000);
Above, doStuff function will get called every 10 seconds. That is the
normal approach most developers seem to go with. However, there is a
huge problem with that.
The setInterval will call doStuff function exactly at specified time of 10 seconds again and again irrespective
of whether doStuff function actually finished doing what it is
supposed to do. That is bad and will certainly get you into unexpected
results.
That is one example of where setInterval is "bad" and should be
avoided.
This is exactly where self-executing functions come in handy. We can
do the same task with the help of self-executing function along with
setTimeout like this:
function foo(){
// your other code here
setTimeout(foo, 10000);
}();
This code will also repeat itself again and again with one difference.
setTimeout will never get triggered unless doStuff is finished. A much
better approach than using setInterval in this situation.
Calling it from another file:
And if this function is on another file it will be called automatically if this file is included.
Why do we use Self-Invoking Functions in JavaScript?
And if you ask yourself why do we use these functions, self-invoked function are used to manage Variable Scope.
Take a look at the answer here for further information.
I'm using PhantomJS v2.0 and CasperJS 1.1.0-beta3. I want to query a specific part inside the page DOM.
Here the code that did not work:
function myfunc()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
}
var del=this.evaluate(myfunc());
this.echo("value: " + del);
And here the code that did work:
var del=this.evaluate(function()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
});
this.echo("value: " + del);
It seems to be the same, but it works different, I don't understand.
And here a code that did also work:
function myfunc()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
}
var del=this.evaluate(myfunc);
this.echo("value: " + del);
The difference here, I call the myfunc without the '()'.
Can anyone explain the reason?
The problem is this:
var text = this.evaluate(myfunc());
Functions in JavaScript are first class citizen. You can pass them into other functions. But that's not what you are doing here. You call the function and pass the result into evaluate, but the result is not a function.
Also casper.evaluate() is the page context, and only the page context has access to the document. When you call the function (with ()) essentially before executing casper.evaluate(), you erroneously try to access the document, when it is not possible.
The difference to casper.evaluate(function(){...}); is that the anonymous function is defined and passed into the evaluate() function.
There are cases where a function should be called instead of passed. For example when currying is done, but this is not applicable to casper.evaluate(), because it is sandboxed and the function that is finally run in casper.evaluate() cannot use variables from outside. It must be self contained. So the following code will also not work:
function myFunc2(a){
return function(){
// a is from outer scope so it will be inaccessible in `evaluate`
return a;
};
}
casper.echo(casper.evaluate(myFunc2("asd"))); // null
You should use
var text = this.evaluate(myfunc);
to pass a previously defined function to run in the page context.
It's also not a good idea to use reserved keywords like del as variable names.
I have a script that I didn't write already running on a page. I'd like to, in a script I did write, be able to execute a function from the original script. Here's a simplified example of what I'm trying to do:
(function ($) {
$.fn.myExistingFunction = function (options) {
function doMyThing(text) {
alert(text);
}
}
}(jQuery));
jQuery(document).ready(function($) {
$.fn.myExistingFunction.doMyThing("alert text");
});
However, when I run this, I get the console output:
Uncaught TypeError: Object function (options) {
function doMyThing(text) {
alert(text);
}
} has no method 'doMyThing'
But it clearly has the method! I can see it right there. What am I getting wrong here?
You can only access that method from the scope of the plugin function. It is not defined in the global scope.
So you can't call that function. All you can do in your code is call functions that are available through what's called the scope chain where the function is called. In your case that is everything that is either defined in your function($){} or in global scope. But the function in the plugin is neither.
When you call $.fn.myExistingFunction.doMyThing you are treating doMyThing like an field in the myExistingFunction object. But actually it is defined inside the function. Maybe this code makes it clearer:
$.fn.myExistingFunction = function (options) {
var doMyThing = function(text) {
alert(text);
}
var hi = "hello";
}
In hi and doMyThing are local variables in the scope of myExistingFunction. If the plugin wasn't designed to expose the functionality to external code you can't access the variables.
An example of a plugin that was designed to expose some of its internal functions would be the jQuery UI datepicker (documentation). It needs functions like parseDate and formatDate interally, but these utility functions are likely to be useful for general development as well, which is why they have been added to the datepicker object explicitly.
I think your code needs a major rewriting, 'cause as it is it will never work, in fact your function doMyThing is not a property of $.fn.myExistingFunction, it is simply declared inside of it, and due to how the scope works in javascript, you'll never be able to call it.