Moving Function With Arguments To RequireJS - requirejs

I'm not only relatively new to JavaScript but also to RequireJS (coming from string C# background). Currently on my web page I have a number of JavaScript functions. Each one takes two arguments. Imagine that they look like this:
functionA(x1, y1) { ... }
functionB(x2, y2) { ... }
functionC(x3, y3) { ... }
Currently, these functions exist in a tag on my HTML page and I simply call each as needed.
My functions have dependencies on KnockoutJS, jQuery, and some other JS libraries. I currently have Script tags that synchronously load those external .js dependencies. But I want to use RequireJS so that they're loaded asynchronously, as needed. To do this, I plan to move all three functions above into an external .js file (a type of AMD "module") called MyFunctions.js. That file will have a define() call (to RequireJS's define function) that will look something like this:
define(["knockout", "jquery", ...], function("ko","jquery", ...) {???} );
My question is how to "wrap" my functionA, functionB, and functionC functions where the ??? is above so that I can use those functions on my page as needed. For example, in the onclick event handler for a button on my HTML page, I would want to call functionA and pass two it two arguments; same for functionB and functionC.
I don't fully understand how to expose those functions when they're wrapped in a define that itself is located in an external .js file. I know that define assures that my listed libraries are loaded asynchronously before the callback function is called, but after that's done I don't understand how the web page's script tags would use my functions. Would I need to use require to ensure they're available, such as:
require(["myfunctions"],function({not sure what to put here})]
I think I understand the basics of RequireJS but I don't understand how to wrap my functions so that they're in external .js files, don't pollute the global namespace, and yet can still be called from the main page so that arguments can be passed to them. I imagine they're are many ways to do this but in reviewing the RequireJS docs and some videos out there, I can't say I understand how...
Thank you for any help.

Just let your MyFunctions.js file return an object to which you have added the methods you want to expose, like so:
define([], function(){
function myPrivateFunction(){
console.log('in private function');
}
function myPublicFunction(){
console.log('in public function');
}
function myOtherPublicFunction(){
console.log('in the other public function');
}
return {
functionA: myPublicFunction,
functionB: myOtherPublicFunction
};
});
The name you give the parameter to your function which requires the MyFunctions does not matter at all. The name strings and the order of the strings in the dependency array does matter, as does the order of the parameters to the function, but the names of the parameters does not. E.g.
require('myFunctions', 'knockout', 'jquery', function(myFunctions, ko, $){
//here we can use the myFunctions, ko and $ variables.
//To call the public function, use the name which the function was
//exposed as; functionA
myFunctions.functionA();
});
The above sample code works exactly the same as the following:
require('myFunctions', 'knockout', 'jquery', function(my, k, j){
//In this example, your functions will be on the value of the 'my' variable,
//knockout will be the value of the 'k' variable and jQuery will be the
//value of the 'j' variable.
//To call the public function, use the name which the function was
//exposed as; functionA
my.functionA();
});

Related

What should I do to understanding this case? (nodejs) [duplicate]

I have a JavaScript file which is loaded by require.
// loaded by require()
var a = this; // "this" is an empty object
this.anObject = {name:"An object"};
var aFunction = function() {
var innerThis = this; // "this" is node global object
};
aFunction();
(function(anyParameter){
console.log(anyParameter.anObject);
})(
this // "this" is same having anObject. Not "global"
);
My question is: this in var a = this; is an empty object whereas this statements in functions are shadows of node.js global object. I know this keyword is different in functions but I could not understand why first this is not equal to global and this in functions equals to global.
How does node.js inject global to this in function scopes, and why it does not inject it to the module scope?
Here's a few fundamental facts you must understand to clarify the situation:
In the top-level code in a Node module, this is equivalent to module.exports. That's the empty object you see.
When you use this inside of a function, the value of this is determined anew before each and every execution of the function, and its value is determined by how the function is executed. This means that two invocations of the exact same function object could have different this values if the invocation mechanisms are different (e.g. aFunction() vs. aFunction.call(newThis) vs. emitter.addEventListener("someEvent", aFunction);, etc.) In your case, aFunction() in non-strict mode runs the function with this set to the global object.
When JavaScript files are required as Node modules, the Node engine runs the module code inside of a wrapper function. That module-wrapping function is invoked with a this set to module.exports. (Recall, above, a function may be run with an abitrary this value.)
Thus, you get different this values because each this resides inside a different function: the first is inside of the Node-created module-wrapper function and the second is inside of aFunction.
To understand this, you need to understand that Node.js actually wraps your module code in to a function, like this
(function (exports, require, module, __filename, __dirname) {
var test = function(){
console.log('From test: ' + this);
};
console.log(this);
test();
});
Detailed explanation can be found in this answer.
Now, this wrapped function is actually invoked like this
var args = [self.exports, require, self, filename, dirname];
return compiledWrapper.apply(self.exports, args);
So, this, at the module level, is actually the exports object.
You can confirm that like this
console.log(this, this === module.exports);
// {} true
Summary:
In Javascript the value of this is determined when a function is called. Not when a function is created. In nodeJS in the outermost scope of a module the value of this is the current module.exports object. When a function is called as a property of an object the value of this changes to the object it was called. You can remember this simply by the left-of-the-dot rule:
When a function is called you can determine the value of this by looking at the place of the function invocation. The object left of the dot is the value of this. If there is no object left of the dot the value of this is the module.exports object (window in browsers).
caveats:
This rule does not apply for es2015 arrow function which don't have their own binding of this.
The functions call, apply, and bind can bend the rules regarding the this value.
Example (NodeJS):
console.log(this); // {} , this === module.exports which is an empty object for now
module.exports.foo = 5;
console.log(this); // { foo:5 }
let obj = {
func1: function () { console.log(this); },
func2: () => { console.log(this); }
}
obj.func1(); // obj is left of the dot, so this is obj
obj.func2(); // arrow function don't have their own this
// binding, so this is module.exports, which is{ foo:5 }
Output:
It's because the default global object in a Node.js module is the exports object, and you are calling test() which doesn't specify this. In traditional JS, this points to the global object, with use strict, this will be null.
this can point to anything, it just depends on how you call it.
test(): Uses the global object (exports) as this, unless in strict mode, where this will be null;
test.call({}) or test.apply({}): You are specifying what to use as this (the first parameter)
var obj = {testRef: test}; obj.testRef(): this is set to the left of the ., that is, obj
Countering thefourtheye's answer
It is true that this in the top level of the module is exports, but that doesn't necessarily mean that this inside test() will also point to same thing as where it was called from.
Attempting to prove that this and the global object both point to exports
myGLobal = 5;
this.myGlobal; // 5

Check if a function exists inside another function in nodejs

Propose the following situation:
function functionExists(functionName) {
if (typeof window[functionName] == 'function') console.log("It's a function");
}
What would be an equivalent function in nodejs for functionExists where there is no global window variable?
CONCRETE SITUATION:
My concrete situation uses webpack instead of nodejs, but basically the problem is the same. I could use window here, but it would be too complicated to implement everything cleanly, and it isn't advised by webpack to mitigate things out to the window global variable.
Basically, I have a PHP backend, which generates a html <form> adding some options to it via a data attribute. When the page is loaded, my javascript initializes this <form> and gives it a bunch of functionalities (like validation for example). Another thing javascript does with this form, is that it parses the data attribute of it, and instead of the normal page reload submit, it changes the form so it is being submited over an ajax request to the server.
When this submit happens, it is set up, that the button and the whole form gets disabled, until my Ajax script sends back a response. How this is done, is that I have a Project_Form class, which when it is initialized, attaches itself to the jQuery submit event, stops the basic submit event, and runs an inner function which sends an ajax request to an api method. The ajax request is set up, that when a response is received, the same instantiated class will receive this response, so I can continue working with it.
When the form receives the response, it must do something with it. In the most basic situation, it must show a success message to the user, but there are some more complex situation, where for example, it has to make a page redirect (for example a login form). Right now, it is set up, that as a default, it will show a message, but when I define this form in PHP, I have the option to "hijack" this default behaviour, and instead of it, send the ajax response to a custom function, which will resolve the situation specifically.
When I am rendering the form in PHP, I already know where the form should send a success response (to which javascript function), but I can only provide this information to javascript, via a string. So my Project_Form class, should fetch this string, and should try to fetch a function from it which it will use. This is where my problem is coming from.
Unless you specifically KNOW that this is a global function (which is almost never the case in nodejs), functions by default in nodejs are scoped to the module and there is NO way to look them up by string name like you did with the window object in the browser, just like there is no way to look up local variables by name inside a function in Javascript.
In general, don't pass functions by string name. Or, if you have to, then you need to create a lookup table that you can check the function name against.
I'd suggest you explain the real problem you're trying to solve here because passing the function by string name is not how you would generally want to do things.
There is a bit of a hack using eval() that can see if a string represents a function name that is in scope:
// Warning, you must know that the argument f (if it is a string) does not
// contain harmful Javascript code because it will be used with eval()
function isFunction(f) {
// if already a function reference
if (typeof f === "function") {
return true;
// see if string represents a function name somewhere in scope
} else if (typeof f === "string") {
try {
return eval(`typeof ${f} === "function"`);
} catch(e) {
return false;
}
} else {
return false;
}
}
Note: This tests to see if the function is in the scope of the isFunction() function. If you want to test if it's in your current scope, then you need to do the:
eval(`typeof ${f} === "function"`)
inline in your current scope so it runs in the scope you want to do the lookup from.
To ever consider using this, you will HAVE to know that the source of your string is safe and cannot contain harmful code. But, as I said earlier, it's better to design your program differently so you aren't referring to functions by their string name.
And, here's a runnable snippet that shows it in action (also works in a node.js module):
function test() {
console.log("in test");
}
function isFunction(f) {
// if already a function reference
if (typeof f === "function") {
return true;
// see if string represents a function name somewhere in scope
} else if (typeof f === "string") {
try {
return eval(`typeof ${f} === "function"`);
} catch(e) {
return false;
}
} else {
return false;
}
}
console.log(isFunction("test")); // true
console.log(isFunction(test)); // true
console.log(isFunction("notAFunction")); // false
More added after question edit
If you only have the function name as a string and the function that it points to is not a property of some known object, then the only way I know of to turn that string into a function reference is with eval().
You could directly execute it with eval() such as eval(functionName + "()") or you could get a reference to the function with eval("let fn = " + functionName) and then use the newly defined fn variable to call the function.
If you control the various functions that could be referenced (because they're your Javascript), then you can make all those functions be a property of a known object in your Javsacript:
const functionDispatcher = {
function1,
function2,
function3,
function4
}
Then, instead of using eval(), you can reference them off the functionDispatcher object like you would have referenced before with window (except this isn't a global) as in:
functionDispatcher[someFunctionName]();
This would be a preferred option over using eval() since there is less risk of insertion of random code via an unsafe string.
In node.js you can achieve this like:
function functionExists(functionName) {
if(functionName && typeof functionName === "function")
console.log("It is a function");
}
Hope this works for you.

How to test the content of callback of method

I might not be getting something but I am trying to test the callback content of a method but without calling the method.
The function I am trying to test
functionToSkip(param1, param2, function(arg1, arg2){
if(arg1){
// Do some things here
} else {
// Do other things here
}
}
What I am trying to do is to test the content of the callback function with differents args values that I can change in the tests and the parameter of the functionToSkip can be anything.
All I successfully did is to skip the call of the function but I cannot call the callback method.
I did stub the function to skip and even trying to give values to the callback method but there is not any logs showing.
var spy = sinon.stub(Class, "functionToSkip").calledWith(param1, param2, ("arg1","arg2"))
The main method that is calling the stubbed function works since I can see the logs prior of the function when I call it in the tests.
First of all, if functionToSkip is an instance method on Class, it will be a property on Class.prototype, not Class itself. In order to stub, you can do one of two things:
Create an instance, and create the stub:
instance = new Class(/*costructor arguments*/)
var stub = sinon.stub(instance, 'functionToSkip')
Or, stub on the prototype:
var stub = sinon.stub(Class.prototype, 'functionToSkip');
In the second case, since class prototypes are global state, I'd recommend restoring it-- preferably in something like mocha afterEach to ensure it gets cleaned up whether your test is successful or not. This way it doesn't screw with other tests in your run:
stub.restore()
Between the two, though, I recommend the first approach.
Next up... If you want to make assertions on the content of calls, the firs thing you'll probably want to do is assert that it was in fact called with the signature you're looking for:
sinon.assert.calledWith(stub, sinon.match.any, sinon.match.any, sinon.match.func)
The any matcher allows any value, and the func matcher requires a func. After that, you can obtain the callback function like so:
var cb = stub.firstCall.args[2]
And invoke it like so:
cb('arg1', 'arg2');
As to what assertions you'd do after invoking the callback function-- I'd have to know more about what you're trying to test about it to make recommendations.

what should nodeJS/commonJS module.exports return

I know that I can set module.exports to either an object or a function
(and in some cases a function that will return an object).
I am also aware of the differences and ways to use exports vs. module.exports so no need to comment on that.
I also understand that whatever is returned is cached and will be returned on any consecutive call to require. So that if I choose to return a function and not an object then possibly this implies that on every require It is necessary to actually run this function.
I was wondering is there any defacto standard on which of those two should be used. Or if there is no such standard - what considerations would apply when deciding if my module should return an object, a function or anything more complicated...
The module I intend to write is expected to be used as part of an express application if it matters (maybe there is a "local defacto standard" for express/connect modules).
If the require'd code is standalone, and does not need access to any objects from the parent code, I export an object.
edit - the above is my preferred way to do it. I do the below only when I need to pass stuff into the module, like configuration data, or my database object. I haven't found a more elegant way to give the module access to variables that are in the parents' scope.
So to pass an object from parent into module I use a function:
//parent.js
var config = { DBname:'bar' };
var child = require('./child.js')(config);
//child.js
module.exports = function(cfg){
var innerchild = {};
innerchild.blah = function(){
console.log(cfg.DBname); // this is out of scope unless you pass it in
}
return innerchild;
};
"so that if I choose to return a function and not an object then
possibly this implies that on every require It is necessary to
actually run this function."
It does not matter whether you return an individual function or an object. In neither cases a function (or functions) are ran. unless you explicitly do so.
For instance, consider the a module hello.js:
exports = function () { return 'Hello'; };
You can use require to get that function:
var hello = require('hello');
If you want to run that function, you need to invoke it explicitly as follows:
var hello = require('hello')();
You wrote you want to make sure your function is executed exactly once. Intuitively this could lead you to writing your hello.js as follows:
var hello = function () { return 'Hello'; };
exports = hello();
In which case you could just store result from hello via require:
var hello = require('hello');
However: if you do that the export system may cache your module. In such cases, you do not get fresh result from hello, but instead, a cached value. This may or may not be what you want. If you want to make sure a function is invoked every time it is required, you need to export a function and call it after require.

How do I call a basic YUI3 function from within a normal JavaScript function?

I'd like to call a simple YUI3 function from within a JavaScript function.
Here is some code that does what I want in a very verbose way:
function changeContent (message) {
YUI().use("node", function(Y) {
Y.all('#content-div').setContent(message);
});
}
Is there a better way to do this?
NOTE: I don't want to attach this function to any event, I just want a global changeContent() function available.
If you want the API to exist outside of the YUI().use(...function (Y) { /* sandbox */ }), you can capture the returned instance from YUI().
(function () { // to prevent extra global, we wrap in a function
var Y = YUI().use('node');
function changeContent(message) {
Y.one('#content-div').setContent(message);
}
...
})();
Be aware that there is a race condition here if you use the seed file (yui-min.js) and dynamic loader to pull in the other modules. changeContent could be called before the Node API is loaded and added to Y. You can avoid this by using a combo script up front. You can get the combo script url from the YUI 3 Configurator. There is a performance penalty for loading the modules in a blocking manner up front. You may or may not notice this in your application.
You can do like this:
(function(){
YUI().use("node", function(Y) {
APP = {
changeContent: function(message){
Y.all('.content-div').setContent(message);
}
};
});
})();
Then, you can call changeContent by calling APP.changeContent(message); from anywhere you want. Hope this helps. :D

Resources