Background:
Building on this question about how to expose a library for unit testing with Jest. I would now like to create a class of functions that can be called with dot notation inside of dot notation (this may not even be possible). First a bit of methodology that I'm currently using:
Here's an example of how I've been modifying the JavaScript Math functions:
Math.mean = function(numericArray){
if(Math.isNumericArray(numericArray)){
return math.mean(numericArray);
}
return false;
}
FYI, The lowercase math.mean() call is to the math library: https://mathjs.org/, and isNumericArray is just a validator to make sure what's passed in is a numeric array.
And then I export it like this:
module.exports.mean = exports = Math.mean;
So Jest can see it for my unit tests.
My actual question:
What I want to do is create an upper level "class" called Math.acs, so you'd make the call into it with Math.acs. Then it would have sub-functions (EG: foo() & bar()) so you'd call them like this: Math.acs.foo(data); or Math.acs.bar(data);
I've tried to encapsulate them into an IIFE:
Math.acs = (function(data) {
function foo(data){
console.log('hi mom');
};
function bar(data){
console.log("hi dad");
}
return bar;
})();
Which didn't work (the CLI can't see anything below Math.acs), I've also tried straight functions inside of functions which also didn't work.
I'm not going to die if this isn't possible, but it would make the half dozen or so functions required in the acs module centralized and easier to maintain. If it's not possible, I can write the individual math modules the same way I've shown above.
You need to take a function with properties and return this function.
Math.acs = (function(data) {
function f() {};
f.foo = function (data) { console.log('hi mom'); };
f.bar = function (data) { console.log("hi dad"); };
return f;
})();
Related
I'm creating a wrapper for an API that will be used in a couple different applications.
I'm using a global object and placing the various functions into that object as different keys. So I'll have:
window.globalContainer = {
APIEndpoint1: function(){
make API call and resolve result
},
APIEndpoint2: function(){},
...
}
All the meat of the API calls are directly in the functions. That is, you could go to window.globalContainer.APIEndpoint1 from the console and see the entire function.
Is this generally bad practice for something that's used across multiple applications and acts as a helper library? Or is this acceptable? I looked at jQuery in the console and it seemed to do much of the same. If it is frowned upon, how do I implement private functions within the global object?
A good place to start is anonymous closures:
(function (global) {
var foo = global.foo || {};
//accessible
foo.publicVar = 5;
foo.publicFcn = function (a, b) {
privateFcn(a, b);
...
};
//not accessible
var privateVar = 5;
function privateFcn(a, b) {
...
}
global.foo = foo;
})(window)
With these you can pretty intuitively build a library and not pollute the namespace.
You explicitly say which variables and functions you want to be made accessible.
You can use an IIFE to implement private functions/properties.
window.globalContainer = function () {
//what ever you define here is not accessible outside. Only the API in
//the returned object is accessible outside
function private1() {
make API call and resolve result
}
return {
APIEndpoint1: function(){
private1();
},
APIEndpoint2: function(){},
...
}
}();
I may be wording this title wrong but in javascript is it ok to call a nested function like so, if not why and what are some safer or more proper ways
function foo() {
return function poo() {
console.log("ew");
}
}
var fooPoo = foo()();
Yes, that's fine, and fairly normal, if you want poo to have access to information that's private within foo and you don't want the calling code to have access to that information. Or even just if foo is what knows how to create the poo function, even if private information isn't needed.
It's relatively rare to do it all in one expression, because usually when you return a function from another function, you want to keep the function around:
var p = foo();
var fp1 = p();
var fp2 = p();
...but only relatively unusual, not unusual.
Here's an example of using the private information held by the context of the original call to the function (allocator, here, is like your foo):
function allocator(seed) {
return function() {
return seed++;
};
}
var a = allocator(1);
console.log(a()); // 1
console.log(a()); // 2
console.log(a()); // 3
Note that the code calling a can't manipulate seed directly. It can only call a and use the value it returns.
Yes, it as a functional technique referred to as currying. it allows you to set parameters for the function in different places in your code
function foo(param1) {
return function poo(param2) {
console.log(param1, param2);
}
}
var fooPoo = foo('param1')('param2');
A common thing I do is use currying for passing in settings when running event listeners to allow greater reuse of functions
function setColor(color) {
return function (e) {
e.target.background = color
}
}
someElement.addEventLister('click', setColor('red'))
Here you can pass in your configuration when declaring your event listener but it won't be called until later when the event is fired and due to the closure you will have access to the color variable within the event listener callback. But now that I know the technique I use it quite a bit
What are the pros and cons?
Is there a consensus or good practice established for this case?
What says linters tools, code conventions and standard guides about that?
function before(){
// declare variables
function x(){
}
// do stuff
return x();
}
function after(){
// declare variables
// do stuff
return y();
// ------------------------
function y(){
}
}
Another exmaple:
var Person = function(name) {
var person = {
name: name,
smile: smile,
talk: talk
};
// here alongside function execution?
function talk() {
}
return person;
// or here, after return statement?
function smile(){
}
};
It is a matter of personal choice and both has got and sweet side.
In the later case it's useful when developer needs to read quickly how functions are invoked at the top of the source file, without the necessity to scroll down and read the details about function implementation.
A style close to the second one is followed when binding member in angular js.
Here is a link for recommended style-guide on how angular js binding members up top
Since functions get hoisted up the scope, there's no real difference, only preference.
return's natural place is at the end, so why not have it there?
I wrote a node.js module which have a main function and two helper functions, I exported only main function and my question is: is it okay to keep two helpers like a global functions or I can find a better way?
function myFirstHelper(args) {
// ...
return result;
}
function mySecondHelper(args) {
// ...
return result;
}
module.exports = function main(args) {
// ...
return result;
};
I think you don't need to worry about the scope for other modules.
However I understand what you feel. If you want to keep clean your feeling, you could use the Self invoking function like below.
You know, you could use this pattern in all javascript environment even outside of nodejs.
(function(){
function myFirstHelper(args) {
// ...
return result;
}
function mySecondHelper(args) {
// ...
return result;
}
exports.main = function(args) {
// ...
return result;
};
})();
You could use nested functions:
module.exports = function main(args) {
function myFirstHelper() {
// ...
return result;
}
function mySecondHelper() {
// ...
return result;
}
// ...
return result;
};
... and there would be no need to pass args since it would be accessible to those nested functions. Yet there's no reason to worry about this unless your module is very large.
The visibility/scope of something only tends to be problematic if the visibility/scope is much wider than its applicability.
For example, a variable declared at the top of a massive function might be a tripping point and a source of confusion and maintenance issues if it is declared/defined at the very top but only used by 3 lines of code towards the bottom. In that case, the visibility of the variable is significantly wider than its applicability, and therefore the reader must kind of keep it in account when tracing through the function for a much longer period of time than it is actually used, increasing the intellectual overhead. Of course, massive functions also tend to be a smell, but that's a different matter.
So here you have functions which are visible within the module. If the module is small and consists mostly of code using these functions, then the visibility/scope of these functions is not significantly wider than their applicability/usage within the module.
That said, nested functions are handy even for pure organizational purposes if you haven't encountered them before, and precisely because of how they allow you to avoid polluting an outer scope. So they might be a handy alternative to consider in this kind of case. But don't worry too much about the scope of a function (or anything) which is already pretty narrow.
Consider this:
window.onload = function () {
myObj.init();
};
var myObj = {
init: function () {
console.log("init: Let's call the callMe method...");
//callMe is not defined...
callMe();
//Works fine!
this.callMe();
},
callMe: function () {
console.log('callMe');
}
};
Since the init function gets called this way (myObj.init), I expect this to be myObj in the init function. And if that is the case, why the callMe function fails? How am I supposed to call the callMe function without using the this context in the init body? (Actually, it's too annoying to call the object methods using this over and over again through the functions. So what's the point of having a single object?)
I would like to know how can I fix this so that the callMe method gets called using the first invocation in the code above?
this is never implicit in JavaScript as it is in some other languages. Although there are ways to do it, like this using the with statement:
init: function () {
console.log("init: Let's call the callMe method...");
// Make `this` implicit (SEE BELOW, not recommended)
with (this) {
// Works
callMe();
}
},
...it's generally a bad idea. Douglas Crockford probably wrote one of the better descriptions of why it's a bad idea, which you can find here. Basically, using with makes it nearly impossible to tell what the code's going to do (and slows the code down, if you do anything else in that with statement that doesn't come from the this object).
This isn't the only way that JavaScript's this is not the same as it is in some other languages. In JavaScript, this is defined entirely by how a function is called, not where the function is defined. When you do this.callMe() (or the equivalent this["callMe"](), or of course foo.callMe(), etc.), two things happen: The function reference is retrieved from the property, and the function is called in a special way to set this to be the object that property came from. If you don't call a function through a property that way, the call doesn't set any particular this value and you get the default (which is the global object; window on browsers). It's the act of making the call that sets what this is. I've explored this in depth in a couple of articles on my blog, here and here.
This (no pun) can be made even clearer if you look at JavaScript's call and apply functions, which are available on all function objects. If I do this:
callMe.call({});
...it'll call the callMe function with a blank object ({}) as this.
So basically, just get used to typing this. :-) It's still useful to have properties and methods associated with an object, even without the syntactic convenience (and confusion!) of an implicit this.
You can also use the module pattern, which captures all private variables inside a closure, so you are free to use them without this, as they're in the same scope. You then pick and choose which methods/variables you want to make public:
var myObj = (function () {
var init = function () {
callMe(); // This now works
};
var callMe = function () {
...
};
// Now choose your public methods (they can even be renamed):
return {
init: init, // Same name
callMyName: callMe // Different name
};
}) ();
Now:
myObj.init(); // Works
myObj.callMyName(); // Works
myObj.callMe(); // Error