The function name is mixed even if I am using a namespace. In the below example when I call nwFunc.callMe() or $.Test1.callTest() it will execute _testFunction() of doOneThing. I am expected for $.Test1.callTest() to call _testFunction() in $.Test1 API instead of one in doOneThing. What I need to do to correct it?
Example:
var doOneThing = function() {
_testFunction= function() {
...
}
return {
// public
callMe: function(){
_testFunction();
}
}
}
var nwFunc = doOneThing();
nwFunc.callMe();
$.Test1.callTest();
below is a example API
jQuery.Test1 = (function(){
_testFunction= function() {
...// do differently
}
return {
// public
callTest: function(){
_testFunction()
}
}
}(jQuery))
You're not in an object literal, you are in a function body.
_testFunction: function() {
.... // do differently
}
is not an object property, but an anonymous function expression preceded by a label and is immidiately forgotten as it is not assigned anywhere. Make it a simple function declaration instead:
function _testFunction() {
.... // do differently
}
And
return {
// public
callMe() {
_testFunction();
}
}
is just a syntax error, in here you need the object literal sytnax:
return {
// public
callTest: function() {
_testFunction()
}
};
or
return {
// public
callTest: _testFunction // exporting the function directly
};
When I call nwFunc.callMe() or $.Test1.callTest() it will execute _testFunction() of doOneThing. What I need to do to correct it?
You have to use a var declaration to put your _testFunction variable in a local scope. Currently you're writing to the global scope, where only one _testFunction exists (currently in doOneThing you're overwriting the _testFunction from jQuery.Test1, and both callTest functions will invoke the new one). A function declaration would've fixed this as well (using the local scope), it is similar to a var statement + function expression.
You are mixing up your syntax slightly. You are using object literal notation when you declare the function originally and using function declaration notation when actually creating the object, so you should switch the two:
jQuery.Test1 = (function(){
function _testFunction() {
.... // do differently
}
return {
// public
callTest: _testFunction
}
}(jQuery))
Related
Is it possible to access method/function m1 from instance of MyObjGraph?
Thanks in advance for your answers
class MyObjGraph
{
constructor(id)
{
this.drawGraph(id);
}
drawGraph(id)
{
var inId = id;
function m1()
{
alert(inId);
}
}
}
Nope, because it is considered as local function so the scope wouldn't be outside the drawGraph method. Only drawGraph method can access it.
If you can slightly modify the code, you could expose the inner method to the "outside":
class MyObjGraph {
constructor(id) {
this.drawGraph(id);
}
drawGraph(id){
var inId = id;
function m1(){
alert(inId);
}
return { // <-------- return an object of everything you want to be exposed
m1
}
}
}
const instance = new MyObjGraph();
instance.drawGraph("123").m1()
Explanation:
In your original code, the method drawGraph does not return anything, therefor it only executes code, and nothing inside of it is accessible.
For anything to be accessible directly from a function, the function needs to have a return statement, so when you invoke that function you get something in "return"... and that something, in this case below, is an Object with a single property: m1 (reference to the m1 inner function)
I'm a javascript newbie and trying to understand how functions work. I found a similar question here but it doesn't really answer my question.
Taking the following piece of javascript as an example
var test = function(){
console.log("kick off");
var insideTest = "variable inside test";
var init = function(){
var insideInit ="variable inside init";
console.log("inside init");
}
return{
init:init
}
}
test().init();
The above code prints the following:
kick off
inside init
But if I remove
return{
init:init
}
it gives me an error saying
Uncaught TypeError: Cannot read property 'init' of undefined
Also, even though I'm calling init method using test().init() it doesn't print inside Init if the return statement is removed.
My question is why is it necessary to return init:init to execute init method.
EDIT:
To answer why my init function is inside the test() function here is the larger picture of what i'm trying to do.
var test = function() {
var init = function() {
var a = 0;
function1();
function2();
}
var function1() = function() {
//some code
}
var function1() = function() {
//some code
}
return {
init: init
}
}
Have added inline comments. Also the init inside test will have access to variable defined outside it(init) scope which is closure. test is returning an object to access it's inner function.This specific pattern is revealing module pattern
var test = function(){
console.log("kick off");
var insideTest = "variable inside test";
// Here init is a function which is private to test function
// Any function calling test will not have access to init unless it is 'exposed'
var init = function(){
var insideInit ="variable inside init";
console.log("inside init");
}
return{
init:init // exposing the private function
}
}
When you return, you're returning an Object with a single key of init, which you've assigned the "init" function that you defined within the test function. This allows you to return multiple functions if you'd like, so you can chain calls.
If you'd prefer a different way, you could just return the function without the curly braces, ie. return init;, and then assign the return of test() to a variable. var externalInitFnc = test();
Edit: Looking back it seems that you are fuzzy on the idea of scope in Javascript. When you defined init within the test function, it is only accessible within that function. Similar to how a private variable in a Java class is only available within that same class.
I've the following javascript code
var globalConfiguration = null;
function loadFile(filePath) {
}
function onLoadPage() {
}
function getConfiguration() {
}
function process() {
}
I want to use IIFE to encolose all my functions in a closure to avoid cluttering the global name space,so I wrote :
(function(window){
var globalConfiguration = null;
function loadFile(filePath) {
}
function onLoadPage() {
}
function getConfiguration() {
}
function process() {
}
});
However, I do not understand this notion very well, now in my HTML page how would I call my function onLoadPage?
You can't without putting it in the global namespace somehow.
My recommendation to structure code like this:
function ExampleHelper() {
(function(scope) {
scope.globalConfiguration = null;
scope.loadFile = function(filePath) {
};
scope.onLoadPage = function() {
};
scope.getConfiguration = function() {
};
scope.process = function() {
};
})(this);
}
var foo = new ExampleHelper(); // "foo" now contains all of your functions
foo.onLoadPage();
Now that you have enclosed the module, you need to decide what you want to expose to the outside world. Anything you want to expose, you can export. Also, you need to decide what context (in this case, window) that you want to attach to. Then pass the context in right away (thus completing the IIFE).
For example:
(function(window){
var exports = {};
var globalConfiguration = null;
function loadFile(filePath) {
}
function onLoadPage() {
}
function getConfiguration() {
}
function process() {
}
exports.getConfiguration = getConfiguration;
window.myModule = exports;
})(window);
Attaching to the passed in window object is one way to export things out in a controlled fashion. So, you do need to pass the context (in this case window) to the IIFE. Perhaps, window will not always be the context for the call.
After running this code, myModule will be available on the global scope.
You can set your function to window.onload callback.
(function(window) {
var globalConfiguration = null;
window.onload = onLoadPage;
function loadFile(filePath) {}
function onLoadPage() {
alert('hello world');
}
function getConfiguration() {}
function process() {}
}(window));
This is called chaining of functions/methods and is usually done for better readability of the code and to avoid the usage of temporary variables to hold the return value of each function.
Check this post on chaining methods which helped me to understand the chaining better.
I see you wanted to use closures to avoid cluttering the global object. However, do note that we write functions for reusability. Though you create a closure, ensure that your methods inside the outer function are abstracted such that they can be used by other parts of the code.
For ex: from your code, you have a loadFile method which could be reused.
Now to see how you can use the methods you described in a chain.
Assumptions: (since i don't know why you wrote those methods, i am making some assumptions).
loadFile(filepath) - returns a file object
onPageLoad() - once the page is loaded, it returns the object or id of the input file
getConfiguration() - gets the file path
process() - process the file
onPageLoad().loadFile(getConfiguration()).process();
The important part is that the scope of the object is set correctly in the chaining. In order to do this, each method must return the reference to appropriate object.
Hope this helps.
I have been creating several classes but I never had any that needed parameters on the class itself.
The following code works perfectly.
$(function()
{
search.anotherFunction('a', 'b');
});
search = function()
{
this.anotherFunction = function(param1, param2)
{
// do whatever
};
var public = { anotherFunction: anotherFunction }
return public;
}();
But now I would like to pass parameters inside search in order to avoid passing the same parameters to all the functions.
$(function()
{
search('front/file.php').anotherFunction('a', 'b');
});
search = function(url)
{
this.anotherFunction = function(param1, param2)
{
// use here the 'url' parameter
};
this.anotherFunctionB = function(param1, param2)
{
// use here the 'url' parameter
};
var public = { anotherFunction: anotherFunction,
anotherFunctionB: anotherFunctionB }
return public;
}();
This doesn't work and the console outputs the error.
Uncaught TypeError: object is not a function
It means that search isn't a function but yes a class name and therefore can't receive params?
To start with, the way you're creating your "classes" is incorrect, and ends up creating global variables: Inside the call to your anonymous function, because of the way you call it, this will refer to the global object*, so this.anotherFunction = ... will create a global variable called anotherFunction, because properties on the global object are global variables.
If you want to keep using your current pattern with minimal changes, then don't use this.xyz = ... with your functions, use var instead:
var search = function()
{
var anotherFunction = function(param1, param2)
{
// do whatever
};
var public = { anotherFunction: anotherFunction }
return public;
}();
Also note that you were falling prey to The Horror of Implicit Globals by not declaring search; I've added a var to declare it.
Your second example, with the changes above, would work if you didn't call the outermost function and just assigned the function to the search variable, then called it later:
var search = function(url)
{
var anotherFunction = function(param1, param2)
{
// use here the 'url' parameter
};
var anotherFunctionB = function(param1, param2)
{
// use here the 'url' parameter
};
var public = { anotherFunction: anotherFunction,
anotherFunctionB: anotherFunctionB }
return public;
}; // <== Note, no () here
Now search refers to a function, which we can call like this:
var x = search("http://example.com");
x.anotherFunction(...); // Will have access to the URL
* Why does this refer to the global object when you call your anonymous function? Because you call it without doing anything to set this to something else, and you're using loose mode. (I know you're using loose mode because if you were using strict mode, this would be undefined and so this.anotherFunction = ... would fail.)
Side note: I would recommend you stop using public as a variable name, as it's a future reserved word and has been since at least ES3.
You can use JavaScript closures here. Check out the below approach:
search = function()
{
return function (url) {
this.anotherFunction = function(param1, param2)
{
// use here the 'url' parameter
};
this.anotherFunctionB = function(param1, param2)
{
// use here the 'url' parameter
};
var public = { anotherFunction: anotherFunction,
anotherFunctionB: anotherFunctionB }
return public;
}
}();
search('front/file.php').anotherFunction('a', 'b');
Is there any reason you would ever want to call a function defined inside a namespace created using the revealing module pattern using its fully qualified name? For example, A vs. B below?
Example A.
var namespace = (function defineNamespace() {
function sayNoThankYou() { }
function callMeMaybe() {
sayNoThankYou();
}
return {
callMeMaybe: callMeMaybe,
sayNoThankYou: sayNoThankYou
};
}());
Example B.
var namespace = (function defineNamespace() {
function sayNoThankYou() { }
function callMeMaybe() {
namespace.sayNoThankYou();
}
return {
callMeMaybe: callMeMaybe,
sayNoThankYou: sayNoThankYou
};
}());
There is only one difference between namespace.sayNoThankYou(); and sayNoThankYou(); in your example: the value of this inside the sayNoThankYou function. If you don't use this inside the function, they are identical.