Seeking advice on passing function as parameter practice in browser js code - javascript

I'm really just wondering if this is the "right" way to do things, or if I'm missing something about modules; we don't use node, just browser, but maybe this is applicable to both. In page.js we have a function world() that we need a module (module.js) to be able to call. Exporting world() and importing it into module doesn't seem like the appropriate way to do things.
Why not? page.js is js that is only applicable to one html page (page.html); world() manipulates some specific UI elements on page.html, and isn't going to ever be reused anywhere else. Module.js does some ajax/server related work; this is done on a lot of other html pages, so of course we make it a module for easy reuse.
init() is the real entry point. Contrived example:
page.js
import mod from 'module.js'
function init() {
hello(); // print 'hello' to console
const options = {
// pass the 'world' function to module.js
functionParam: world,
// some other irrelevant options here
};
mod.print(options); // print 'world' to console
}
function hello() {
console.log('hello');
}
function world() {
console.log('world');
}
module.js
function print(options) {
// should call the world function, we should see 'world' logged to console
options.functionParam();
}
export default print;

Related

webpack doesnt add prototype function to Object from other file

I have a file containing the definition of a Object and in that same file I have a function that is part of this object like so:
export function ARScene(_callbacks) {
this.callbacksObject = _callbacks;
// more fancy code..
}
ARScene.prototype.changeCar = function() {
//some fancy code here
this.loadHDCar(); // THIS LIKE GENERATES A ERROR.
}
now I have a different file containing an other method that is part of the Object called ARScene like so:
import { ARScene } from './arScene';
ARScene.prototype.loadHDCar = function() {
//some more fancy code..
}
What is happening when I build this with webpack and run it in the browser I get the error that this.loadHDCar(); is undefined I guess this happens because webpack doesnt add a file if it is not imported. But how do I make sure that ARScene.prototype.loadHDCar is added to the object in the final output?
I am a complete newbie to webpack and modules. I have found answers on stackoverflow about this but they had slightly different scenarios then me. So their solutions didnt work (or maybe I didnt understand it).
If more context or information is needed please let me know.
How do I make sure that ARScene.prototype.loadHDCar is added to the object in the final output?
You should import it in the arScene module, and you should even create the prototype method in there (where you are defining the class) for visibility.
export function loadHDCar() {
… //some more fancy code
}
import { loadHDCar } from './loadHDCar';
export function ARScene(_callbacks) {
…
}
ARScene.prototype.loadHDCar = loadHDCar;
ARScene.prototype.changeCar = function() {
… // some fancy code here
this.loadHDCar();
};

how to refactor anonymous function in npm using browserify

Learning npm with browserify.
I would like to refactor a code I wrote in modules.
For the sake of learning, I am trying to break it down little by little.
So far I have something like:
on index.html
<body onload=example.main()>
and on my javascript:
(var example = function() {
var helper = function (){
// smtg
}
// body:
// body is made by global objects, functions that I will then return on traps, e.g. main and helper. I would like now to separete functions and body in dedicated modules, to tide a bit the code
return {
main : function() {
// show main UX
},
helper : helper
}
})()
The first thing I want to do, is to export the function as a module, so that I can call example.main() on my index page.
I would like to start separate functions and "body", and then exports only traps I want in my example object.
I tried:
module.export = function () {
return example
}
var example = function() { ...} // no more calling the anonymous function
but got error example.main is not a function
and other attempts to export my example(), I cannot.
Is it maybe because it is not a constructor?
Could you help to show a syntax and logic of a first example to export only the traps I want from example ( main, helper) and how would you refactor helper, main, and "body" in three different npm modules ?

Does Node run all the code inside required modules?

Are node modules run when they are required?
For example: You have a file foo.js that contains some code and some exports.
When I import the file by running the following code
var foo = require(./foo.js);
is all the code inside the file foo.js run and only exported after that?
Much like in a browser's <script>, as soon as you require a module the code is parsed and executed.
However, depending on how the module's code is structured, there may be no function calls.
For example:
// my-module-1.js
// This one only defines a function.
// Nothing happens until you call it.
function doSomething () {
// body
}
module.exports = doSomething;
// my-module-2.js
// This one will actually call the anonymous
// function as soon as you `require` it.
(function () {
// body
})();
Some examples..
'use strict';
var a = 2 * 4; //this is executed when require called
console.log('required'); //so is this..
function doSomething() {}; //this is just parsed
module.exports = doSomething; //this is placed on the exports, but still not executed..
Only in the sense that any other JS code is run when loaded.
e.g. a function definition in the main body of the module will be run and create a function, but that function won't be called until some other code actually calls it.
Before exporting the content that are visible outside of your module, if there is same code that can be execute it it execute but the content that are export like a class will be execute in the code that import it.
For example, if I have this code
console.log("foo.js")
module.exports = {
Person: function(){}
}
the console.log will be execute when you require it.

Test that a function calls another function in an ES6 module with Sinon.js

I want to test that a function in an ES6 module calls another function using Sinon.js. Here's the basic layout of what I'm doing:
foo.js
export function bar() {
baz();
}
export function baz() {
...
}
test.js
import sinon from 'sinon';
import * as Foo from '.../foo';
describe('bar', function() {
it('should call baz', function() {
let spy = sinon.spy(Foo, 'baz');
spy.callCount.should.eql(0);
Foo.bar();
spy.calledOnce.should.eql(true);
});
});
But the spy does not pick up the call to baz(). Is there some other way I can set up the module or the test to allow sinon to pick this up? My alternative is to make some basic assertion on something baz does, but I obviously don't want to be doing that.
From what I've seen online I'm wondering if this is even possible with the code laid out as-is or if I need to restructure it to get what I want.
You're right in thinking this isn't possible with the way the module is currently structured.
When the code is executed, the baz reference inside function bar is resolved against the local implementation. You can't modify that since outside of the module code there's no access to the internals.
You do have access to exported properties, but you can't mutate these and so you can't affect the module.
One way to change that is using code like this:
let obj = {};
obj.bar = function () {
this.baz();
}
obj.baz = function() {
...
}
export default obj;
Now if you override baz in the imported object you will affect the internals of bar.
Having said that, that feels pretty clunky. Other methods of controlling behaviors exist such as dependency injection.
Also, you should consider whether or not you actually care if baz was called. In standard "black-box testing", you don't care how something is done, you only care what side effects it generated. For that, test if the side effects you expected happened and that nothing else was done.

Convert closure to es6 module

I'm using a javascript build environment that supports es6 modules (using es6-module-transpiler) so you can simply import stuff across different files.
Now I got a third party library that I'd like to be "importable".
The library populates its functionality like this:
(function () {/*...*/}).call(this);
Would it be safe to omit the closure and convert it to:
export default function () {/* ... */};
Or is there a better way?
Thanks in advance!
The original code you show invokes the anonymous function, which to make any sense must define a global variable, whereas the second code fragment you show merely exports the function, which is a different thing.
For purposes of discussion, let's assume the original code defines a global like this:
// my-third-party-module.js
(function() {
let myVar = 22;
window.MyThirdPartyModule = { log: function() { console.log(myVar); } };
}.call(this);
and you are using is as so:
// app.js
MyThirdPartyModule.log();
You could rewrite this as
// my-third-party-module.js
let myVar = 22;
export default { log: function() { console.log(myVar); } };
// app.js
import MyThirdPartyModule from `my-third-party-module';
MyThirdPartyModule.log();
Note that we have moved the variable myVar which was local to the anonymous function to the top module level.
However, depending on your preferences, rather than exporting a big object, which is sort of a pre-module mentality, you might want to export its APIs individually:
// my-third-party-module.js
let myVar = 22;
export function log { console.log(myVar); }
// app.js
import {log} from `my-third-party-module';
log();
or if you prefer
// app.js
import * as MyThirdPartyModule from `my-third-party-module';
MyThirdPartyModule.log();
However, all of these approaches assume you are able and willing to edit the source of the third party library. If that is not the case, you could write a little piece of glue code, such as
// my-third-party-module-interface.js
import 'my-third-party-module'; // This will run the module.
export default MyThirdPartyModule; // Export the global it defined.
// app.js
import MyThirdPartyModule from 'my-third-party-module-interface';
If you would prefer again to export individual APIs, you could extend the glue to re-export each of them:
// my-third-party-module-interface.js
import 'my-third-party-module'; // This will run the module.
const {log, otherAPI, ...} = MyThirdPartyModule;
export {log, otherAPI, ...};
// app.js
import {log} from 'my-third-party-module-interface';
The conversion of legacy dependencies is still an issue. And the horrible workflow they use makes things a lot harder, prefixing the actual code with browserify and webpack silliness.
So what to do? Existentially, the library is guaranteed only to deposit a global in window but by obscure and weird ways. And all slightly different.
So let the legacy simply do what it is supposed to do for you, but wrapped in a module so that you can import it rather than use a script tag:
https://medium.com/#backspaces/es6-modules-part-2-libs-wrap-em-up-8715e116d690

Categories

Resources