I wanted to pass many variables to child functions and that passed variables should also pass on to the next child functions. Passing them each time as parameters is a tedious job. I was wondering what would be the better way to do this in Js. I tried using the this keyword , But not sure if that is the correct way of usage to achieve this.
var scriptConfig = {
availableOptions: {
version: "1",
type: "one",
status: "free",
},
availableCategories: {
navbar: true,
hasCoupon: true
}
};
window.addEventListener('load', function() {
let options = scriptConfig.availableOptions;
let version = options.version;
renderDashboard(options, version);
});
function renderDashboard(options, version) {
createNavbar(options, version);
}
function createNavbar(options, version) {
console.log(options);
console.log(version);
}
Using this
var scriptConfig = {
availableOptions: {
version: "1",
type: "one",
status: "free",
},
availableCategories: {
navbar: true,
hasCoupon: true
}
};
window.addEventListener('load', function() {
this.options = scriptConfig.availableOptions;
this.version = options.version;
this.renderDashboard();
});
function renderDashboard() {
this.createNavbar();
}
function createNavbar() {
console.log(this.options);
console.log(this.version);
}
Can anyone suggest which would be a better way ? Also it would be great if anyone suggest better coding practice for the above lines of code.
Using this in global scope (outside class) is not a good idea as it pollute the Window object. I will suggest you to create a class and wrap everything like this:
class Dashboard {
constructor(config) {
this.options = config.availableOptions;
this.version = this.options.version;
}
renderDashboard() {
this.createNavbar();
}
createNavbar() {
console.log(this.options, this.version);
}
}
var scriptConfig = {
availableOptions: {
version: "1",
type: "one",
status: "free",
},
availableCategories: {
navbar: true,
hasCoupon: true
}
};
window.addEventListener('load', function () {
const dashboard = new Dashboard(scriptConfig);
dashboard.renderDashboard();
});
There is [apply()][1] function in JS.
It lets you specify what this is when calling a function and provide additional arguments.
Well if you are constantly passing a variable from one function to its child functions, or in other terms from one ui component to its ui component, what you are doing in this case is sharing context between these entities (functions, components, or call them whatever you want depending on the type of their output)
global variables should be avoided, however in certain use cases they are the only valid solution, one use case for global variables are contexts - some people differentiate between context and global state, in that a context is a read only, while global state is mutable, for managing global states, javascript has many libraries that handle this like redux.
Assuming that you are using an immutable context, then the best option is a global variable, obviously you should hide that global variable behind a getter function to also make code more decelarticve
// Assuming you are using javascript modules if not just remove the export keyword
// obviously add the needed properties for the object
const globalContext = Object.freeze({}) // freeze object to prevent mutations to it
export const getGlobalContext = () => {
// hiding the global variable behind a getter offers two advantages, it better conveys the message that this object should not mutated by code
// later it enables more customization of context sharing, if for example later you decide to nest contexts, but if your context will get complicated, then doing that through a library should be better option
return globalContext;
}
Finally dont use the this keyword outside of instances/classes context, this will produce poor code that is hard to read, and more prone to errors, and its one of the reasons ES6 added the syntatic sugar class to make code that uses this only use it there and not in normal functions ( though it is still valid syntax)
Related
I'm working with Webpack modules to keep things organized in my projects, but something very annoying is having to explicitly specify all the variables that the module might need, instead of just having it search for them in the calling function's scope. Is there a better way to do it? Example:
main.js
import {logMonth} from "./helpers";
document.addEventListener("DOMContentLoaded", () => {
let month = "September";
logMonth();
});
helpers.js
let logMonth = () => {
console.log(month)
}
This will produce an error since logMonth() doesn't have access to the month variable.
This is an extremely simplified example, but for functions that need many variables, it can get pretty ugly to pass all the required arguments that the function might need.
My question is: Is there a way to make modules have access to the variables of the calling scope instead of explicitly passing them?
You could, but why would you want to? Modules are designed to prevent this. Always prefer pure functions, it's way easier to debug once the app becomes complicated.
Then you don't want to be searching multiple nested scopes from multiple modules for a bug, optimally you want to only be looking in the module that threw the error instead of every scope it has access to.
So logMonth = month => console.log( month ); and logMonth( 'September' ); is preferred.
You can use an object if you need to send multiple parameters to a function.
That way you do not have to change the function call signature in all places, you just add another (optional) parameter to the object:
logMonths = ({ year, month, day}) => { ...do stuff... }
This will work both with logMonths({ month: 'september' }) as with logMonths({ month: 'september', year: '2019' }), so you never have to change like logMonths( 'september' ) into logMonths( null, 'september' ) and logMonths( 2019, 'september' ) everywhere you used logMonths() before it had a year parameter.
I actually discovered a sneaky way to do this. I'll demonstrate with two JavaScript files. The first will be the top level file, and the second will be the module.
top-level.js
import {PipeLine} from './PipeLine.js';
App = {
var1: 'asdf',
var2: 'dfgh',
method1: function() {
// do something...
},
}
pipeLine = new PipeLine(App);
PipeLine.js
export class Pipeline {
constructor(app) {
this.app = app;
// Now do what you will with all the properties and methods of app.
}
}
I have a separate object that manages a particular dialog box. Consider the following code. As it is very easy to imagine what the functions do, I'm however unable to access the instance of the class. I tried using the traditional that = this approach.
export class Whatever implements OnInit {
that = this;
dialog = {
data:{},
open:function() {
//way to access 'that' variable
},
close:function() {},
toggle:function() {}
}
//other declarations and functions
}
As my application is scaling, I'm having too many functions inside this service. So i'm trying to club some of these functions into objects, which will make the code much cleaner.
Also if there is any better approach to this, I'd love to know. Thanks.
Best way would be to replace the function(){} with the ES6 arrow functions, which holds your this context like so () => {}.
You can also use functions(){}.bind(this), but it's much better to just use arrow functions. Both will keep your reference to this as expected in the body of the function
You have to use arrow functions to not lose the context(this);
export class Whatever implements OnInit {
dialog = {
data:{},
open:() => {
//'this' will point to Whatever class's instance
},
close:() => {},
toggle:() => {}
}
//other declarations and functions
}
In your code, that isn't a variable, it's a property of the Whatever instance.
Your dialog is also a property of the Whatever instance. In calls to its methods, this will vary depending on how they're called.
To ensure they access the Whatever instance, you can use arrow functions and use this within the functions:
export class Whatever implements OnInit {
dialog = {
data: {},
open: () => {
// use `this` here
// use `this.dialog.data` to acccess the data above
},
close: () => {},
toggle: () => {}
};
//other declarations and functions
}
This works because class fields declared as you've declared them there are effectively initialized as though they were inside your constructor, and within the constructor, this refers to the instance. Arrow functions close over the this of the context where they're created (just like closing over an in-scope variable).
I've come across a problem while trying to build a simple jQuery plugin, having to do with scopes I guess.
The problem in short: A class (A) creates an object (B), in which a property (C) is set to one of the class methods (D). How can I access class A's methods not contained inside the object (B) through the property ( C)?
Longer version (code below): I'm declaring an object (lets call it publicMethods) inside the plugin, comprised of a bunch of methods. These methods should be some default methods (declared inside the plugin), or user declared ones if the user has declared her own when initializing the plugin.
The idea is that when the user defines her own custom method, there should be some functions and variables accessible to her (like this.someVar) in that function.
This creates some limitations though.
I want the default methods to have access to some internal functions and variables, not contained inside the object publicMethods. But when I access these methods through the object they are inside, instead of calling them directly, I do not have access to another variables/functions not inside that object.
I'm trying to find a way to let the default methods have access to it's class siblings. I know I can do some conditional statements before calling the method (if it is user defined or not), or even declare a global variable pointing to "this", but I'd rather keep it clean.
var Plugin = function (opt) {
this.settings = $.extend({
"someVar" : "Value",
"someFunc" : null
});
this.anotherVar = "Hello World";
this.setPublic();
this.run();
}
Plugin.prototype = {
setPublic: function() {
this.publicMethods.someFunc = this.someFunc;
if ($.isFunction(this.settings.someFunc)) {
this.publicMethods.someFunc = this.settings.someFunc;
} else {
this.publicMethods.someFunc = this.someFunc;
}
},
someFunc: function(arg) {
return this.anotherVar; // returns type error the second time
},
run: function () {
this.someFunc();
this.publicMethods.someFunc();
}
}
From MDN: Function.prototype.bind():
The bind() method creates a new function that, when called, has its this keyword set to the provided value, [...].
So the following should work:
setPublic: function() {
this.publicMethods.someFunc = this.someFunc.bind(this);
if ($.isFunction(this.settings.someFunc)) {
this.publicMethods.someFunc = this.settings.someFunc.bind(this);
}
// This is redundant anyway:
/* else {
this.publicMethods.someFunc = this.someFunc.bind(this);
}*/
},
Export Objects {} vs Export function
I'm developing an exercise application, I came across to the question When do I need to exports an object {} instead of a function class?
Scenario example:
I'm building a simple authentication module using the object style.
// file auth.js
module.exports = {
login: function() {
// code login
},
logout: function() {
// code logout
},
register: function() {
// code register
}
}
Here I'm using the anonymous function style
module.exports = function() {
return {
login: function() {
// code login
},
logout: function() {
// code logout
},
register: function() {
// code register
}
}
}
Requiring
When I want to require this module I just do:
var auth = require('auth');
auth.login(); // trigger login function via object
auth().login() // trigger login function via function
It will work with both the approaches, but I'm confused to choose which fit better and why.
Questions
How do you understand in your design of a module, when is appropriate to exports, an object, anonymous function, named function to Instantiate?
Which are the difference and how the require method behave, when requiring these functions or Objects ?
How do you understand in your design of a module, when is appropriate to exports, an object, anonymous function, named function to Instantiate?
true minimalists aim to export a single function if that will suffice. This is based on the scope of your module and assumes a small and focused purpose.
Export an object of related functions when you need a set of functions to have a meaningful set of functionality. For example, a tempConversion module might have both cToF and fToC functions.
If you are doing OO, exporting the constructor function is fine.
a closure function that returns the real payload (which can be an object or a function) is useful for configuration options. For example var tip = require('computeTip')(18); could store 18 in closure and return a function that would calculate 18% tip when called with a number.
Here's a rule of thumb: if you export only one named function a la require('average').average(listOfNumbers), it's redundant, so just export the average function directly to make it more concise. If you have more than one function you want to expose, use an object whose properties are the functions.
Which are the difference and how the require method behave, when requiring these functions or Objects ?
There are no differences. require has a single behavior that accommodates each of these techniques.
In both your examples you actually return an object and not a function class. In the second case you get the object by executing the function. In order to use the function as a class you should return a function which acts as the constructor, and then instantiate with the new operator.
That being said, I would prefer an object over a class if I consider my module as a singleton, something that would be common to every file that would include it. An example would be a module that implements a common access layer to my database.
A class makes more sense if you intent to instantiate it multiple times. An example would be a specific model class for your database schema, like a User class.
Looking at some backbone examples, I see some simple models like this:
var Vehicle = Backbone.Model.extend(
{
summary: function () {
return 'Vehicles move';
}
});
or
Vehicle = (function () {
return Backbone.Model.extend({
defaults: {
},
initialize: {
}
});
})();
Edit: (clarification)
I was wondering if someone could explain the differences between the two ways of defining backbone objects and what's more conventional. I know they don't have the same methods inside, but I'm more interested in how in the first one, they extend the backbone model, and the second one, they wrap it in a closure. I'm not sure if I really grasp what's going on in each and when you would use which pattern. Thanks in advance!
I would consider the first form much more conventional, especially since I don't even see the second form on the main Backbone.js website at all.
To understand how they do the same thing, first notice that Backbone.Model.extend() is a function that also returns a function:
> Backbone.Model.extend()
function () { return parent.apply(this, arguments); }
So the variable Vehicle ends up being set to a function that is a model constructor method either way you look at it. I would consider the second form more indirect and unnecessarily complex, though: it is setting Vehicle to the result of calling a function that, itself, just returns Backbone.Model.extend(), so its just a more convoluted way of saying the same thing.
If all the properties for the model are easy to define, pattern 1 is suggested. However, if any property is complex to implement thus need a "private" helper function which you do not want expose it either in your model or in global object, better to utilize the closure to hide it. that is the pattern 2.
An Example:
Vehicle = (function () {
function helper1() {} //don't want to expose it
function helper2() {}
return Backbone.Model.extend({
defaults: {
},
initialize: {
}
summary: function() {
helper1();
helper1();
}
});
})();