Calling a function recursively in the context of "export default"? - javascript

This may be obvious to others but I don't know the syntax for calling a function recursively in the following code:
//request.js
export default {
send() {
... do stuff ...
this.send(); // Can't call "send" of undefined
}
}
//main.js
import request from './request'
export default class Main extends Component {
init() {
request.send();
}
}
In the above example, I'm calling the send function from main.js. All this is working fine but I have a condition in the send function that will recall the same function. The problem is that I have no idea how to call the function from within the function. Anybody?

If you want to call the default export recursively in Node.js, using Babel.js to transpile, you can use the exports object:
// request.js
export default {
send() {
console.log('Yo');
setTimeout(() => {
exports.default.send();
}, 1000);
},
};
Importing:
// main.js
import request from './request';
request.send(); // Writes "Yo" to the console once per second
This is because Babel.js simply transforms to the CommonJS syntax. This:
export default 42;
Becomes this:
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = 42;
No idea how this may change in a future implementation of ES6 Modules in Node.js.

I don't see any reason why this.send() wouldn't work, given you are exporting an object with a method.
But if it doesn't work, you can always use a named function expression:
export default {
send: function send() {
… send() …
}
};
or a named function declaration:
function send() {
… send() …
}
export default { send };
or just name your exported object:
export default const request = {
send() {
… request.send() …
}
};
But I would recommend to not default-export an object at all, and use named exports instead so that you can import them separately or on a namespace object:
// request.js
export default function send() {
… send() …
}
// main.js
import * as request from './request'
…
request.send()

well just as a quick glimpse, I would say that you should
console.log(this)
to see the value of it in the first and second request.
I didn't build your code to check it, but I assume it is an issue with your context.
Still not sure what you try to achieve, but you can always use
someFunction.bind(this)
again it is quite vague but maybe it will give you an idea.

i think this is simple solution.
//request.js
export function send () {
... do stuff ...
send(); // Can't call "send" of undefined
}
//main.js
import {send} from './request'
export default class Main extends Component {
init() {
send();
}
}

Related

How do I make variables available across different javascript files when the variables are declared using async/await?

<html>
<!-- ... (other page content) ... -->
<script src="common.js"></script>
<script src="homepage.js"></script>
</html>
On every page on my website, I have one common.js file for stuff that is always needed on every single page. And then I have one js file specifically for that page.
My problem is that variables declared in the common.js file needs to be accessed in the second js file as well, but I am running into some issues because the script is not waiting for the data variable to be declared, and it is not allowed to use await in the top level of the script.
// common.js
let data;
async function get_data() {
data = await fetch('/get-data').then(res => res.json())
console.log(data) // works!!!
}
get_data();
console.log(data) // does not work!!!
// homepage.js
console.log(data) // does not work!!!
So what I am asking is how can I make the two console.log(data) calls that aren't working, work!
Create a global Promise that resolves to data, and then call .then on that Promise whenever you need to consume it.
// common.js
window.dataProm = fetch('/get-data').then(res => res.json());
dataProm
.then((data) => {
console.log(data);
})
// .catch(handleErrors);
// homepage.js
dataProm
.then((data) => {
console.log(data);
})
// .catch(handleErrors);
Assign the resulting promise to a globally scoped variable.
// common.js
async function get_data() {
const res = await fetch('/get-data');
if (!res.ok) {
throw res;
}
return res.json(); // return the data
}
// Assign to a variable
const dataPromise = get_data();
dataPromise.then(console.log);
// homepage.js
dataPromise.then(console.log); // why does everyone log everything ¯\_(ツ)_/¯
Three (3) node javascript solutions that doesn't rely on window.
There are a few viable approaches here. One being a global variable, another being through classes and/or passing an instance of the function/class to the respective files.
But in general, what I think you're looking for is the static keyword in other languages. Well, it exists in JavaScript as well.
Static keyword
Benefits of this approach is that you don't have to create a new instance of the class and pass it around as a reference (see last example for that).
Essentially, everywhere you want to get the shared resource value. Just import the common file and use the getStaticProperty method (in this example).
common.js
export default class Common {
static staticProperty = 0;
static getStaticProperty() {
return this.staticProperty;
}
static setStaticProperty(val) {
this.staticProperty = val;
}
}
a.js
import Common from './common';
export default function a() {
Common.setStaticProperty(321); // here we set the value
}
b.js
import Common from './common';
export default function b() {
console.log(Common.getStaticProperty()); // prints 321
}
index.js
import a from './a';
import b from './b';
a();
b();
Full demo here
Global variable
common.js
let globalValue = 0;
function setSharedValue(val) {
globalValue = val;
}
function getSharedValue() {
console.log('global value', globalValue);
}
export { setSharedValue, getSharedValue };
a.js
import { getSharedValue, setSharedValue } from './common';
function runA() {
setSharedValue(3); // here we set the value to '3'
getSharedValue(); // prints 3
}
export default runA;
b.js
import { getSharedValue } from './common';
function runB() {
console.log('from B');
getSharedValue(); // also prints 3
}
export default runB;
index.js
import a from './a';
import b from './b';
a(); // 3
b(); // from b, 3
Full demo here
Classes (and pass by reference)
common.js
export default class Common {
constructor() { // redundant
this.sharedValue = 0;
}
getSharedValue() {
return this.sharedValue;
}
setSharedValue(value) {
this.sharedValue = value;
}
}
a.js
export default function A(commonInstance) {
const sharedValue = commonInstance.getSharedValue();
console.log('shared value', sharedValue);
}
index.js
import Common from './common';
import A from './a';
const shared = new Common();
shared.setSharedValue(55); // set the common value to 55.
A(shared); // prints 55
Full demo here
In summary, you can apply these approaches to variables, functions and classes in order to get a shared variable across different javascript files.

How to mock call to constructor of class in 3rd party module called from the same module using jest

I have a 3rd party module like this
class Test {
async doSomething() {}
}
export const testObject = new Test(); <--- I want to mock this part because constructor requires some input which I don't want to provide as it is not required for tests
another module which imports the above module
import { testObject } from 'module1';
function foo() {
testObject.doSomething()
}
Now I am trying to write unit tests like below
describe('test', ()=> {
test('', ()=> {
foo()
})
})
new Test() depends on some outside input which I don't want to provide so when i run tests, it fails because of missing input and I am not sure how to stop new Test() from being executed as is and instead a mock functions should be run instead
Try something like this. If you run this test it'll pass:
Class file.
class SoundPlayer {
foo: string
constructor() {
this.foo = 'bar'
}
playSoundFile(fileName: any) {
console.log('Playing sound file ' + fileName)
}
}
export const testObject = new SoundPlayer()
Function file
import { testObject } from './test'
export default function test() {
testObject.playSoundFile('testing')
}
Test file
import { testObject } from '../test'
import test from '../test1'
jest.mock('../test')
it('should run test', () => {
test()
expect(testObject.playSoundFile).toHaveBeenCalledTimes(1)
})
This is a very basic example and there are 4 different ways you can mock.
Check out the Jest documentation: https://jestjs.io/docs/es6-class-mocks#the-4-ways-to-create-an-es6-class-mock

Vue creating a plugin

I feel a bit like I'm missing something very simple, but I've been trying different stuff out and searching all over the place and can't figure out how to use a method from a custom plugin in my Vue application.
In 'vuePlugin.js' I have something like:
const myPlugin = {};
myPlugin.install = function(Vue, options){
Vue.myMethod = function(){
console.log("It worked!");
}
}
In my main.js I have:
import myPlugin from './js/vuePlugin.js'
Vue.use(myPlugin);
Then in my App.vue I have:
export default {
name: 'app',
props: {},
data () {
return{ someData: 'data' }
},
beforeCreate: function(){
myMethod();
}
}
With this I get an error that "myMethod is not defined".
I've tried saying:
var foo = myPlugin();
console.log(foo);
In my console I get an object called "install" with arguments:
"Exception: TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context. at Function.remoteFunction"
All of the documentation seems to just show how to create the plugin and "use" it, but not actually how to access anything in it. What am I missing here?
You have to export your object to be used in vuejs as follows
file vuePlugin.js
const myPlugin = {}
myPlugin.install = function (Vue, options) {
Vue.myMethod = function () {
console.log('It worked!')
}
Vue.prototype.mySecondMethod = function () {
console.log('My second Method ')
}
}
export default myPlugin
while calling the method you cannot call the method directly, you have to use as following code shown
file App.vue
export default {
name: 'app',
props: {},
data () {
return{ someData: 'data' }
},
beforeCreate: function(){
Vue.myMethod(); // call from Vue object , do not directly call myMethod()
this.mySecondMethod() // if you used prototype based method creation in your plugin
}
}
hopes it will help you

Injected module is undefined when calling module function

I'm trying to make a website where i use Aurelia and Javascript and ES6.
I have a simple class (Status) that needs to get some data on a interval from a server.
Update
I have added CalcData to the injector as sugessted by Fabio Luz, but i still get the same error. Good call btw ;).
The class looks like this:
import {inject} from "aurelia-framework"; // for the inject decorator
import { StatusData } from "./statusData"; // MovieData, the module that will be injected
import { CalcData } from "./Calc"
#inject(StatusData, CalcData) // Inject decorator injects MovieData
export class Status {
constructor(StatusData, CalcData) {
this.statusData2 = StatusData;
this.CalcData = CalcData;
}
activate() {
setInterval(this.updateCalc, 3000);
}
updateCalc() {
this.CalcData.hello()
.then(statusData => this.statusData2 = statusData);
}
updateStatus() {
return statusData2.getX()
.then(statusData => this.statusData2 = statusData);
}
update() {
return 1;
}
}
The updateCalc function is called but when this happens the browser says it that CalcData is undefined.
Uncaught TypeError: Cannot read property 'hello' of undefined
at updateCalc (status.js:17)
updateCalc # status.js:17
status.js:17 Uncaught TypeError: Cannot read property 'hello' of undefined
at updateCalc (status.js:17)
updateCalc # status.js:17
The CalcData class looks like this:
import { inject } from "aurelia-framework"; // for the inject decorator
import { HttpClient } from "aurelia-http-client"; // for the http client that will be injected
let baseUrl = "/movies.json";
#inject(HttpClient)
export class CalcData {
constructor(httpClient) {
this.http = httpClient;
}
hello() {
return this.http.get(baseUrl)
.then(response => {
return response.content;
});
}
}
I can't seem to find the problem, i have looked around but can't find a solution. I must say that i'm new to Aurelia.
Any help is much appreciated!
Your problem is down to capitalization, most likely.
Let's look at the beginning of your code:
import {inject} from "aurelia-framework"; // for the inject decorator
import { StatusData } from "./statusData"; // MovieData, the module that will be injected
import { CalcData } from "./Calc"
#inject(StatusData, CalcData) // Inject decorator injects MovieData
export class Status {
constructor(StatusData, CalcData) {
this.statusData2 = StatusData;
this.CalcData = CalcData;
}
Notice that your constructor is taking parameters whose names exactly match the names of the classes you want to inject. This is causing confusion for the runtime, as you are likely ending up setting this.Calcdata to the class CalcData (and the same for StatusData). The class does not have a function called hello(), only instances of the class have that function. If you change the parameter names to not exactly match, your issues should go away.
#inject(StatusData, CalcData) // Inject decorator injects MovieData
export class Status {
constructor(statusData, calcData) {
this.statusData = statusData;
this.calcData = calcData;
}
I've also lower-cased the property names to match JavaScript naming conventions.
Seems like i had to bind "this" to pass the object reference. When calling this in hello it how read gets the right object.
E.g.
import {inject} from "aurelia-framework";
import {StatusService} from "./statusService"
#inject(StatusService)
export class Status{
message = 'unknown yet';
statusService: StatusService;
constructor(statusService){
this.statusService = statusService;
}
activate(){
setInterval(this.updateStatus.bind(this), 3000);
}
updateStatus = function () {
this.message = this.statusService.getX();
}
}

How to mock a method thats imported inside of another import

I'm testing in a ES6 babel-node environment. I want to mock a method thats used inside of the method I'm importing. The challenging part seems to be that the method I want to mock is imported into the file where the method I want to test resides. I've explored proxyquire, babel-plugin-rewire but I can't seem to get them to work on methods imported inside of other imports. From reading through various github issues I get the feeling that this might be a known limitation/frustration. Is this not possible or am I missing something?
No errors are produced when using proxyquire or babel-plugin-rewire. The method just doesn't get mocked out and it returns the methods normal value.
Here's a generic example of the import situation.
// serviceLayer.js
getSomething(){
return 'something';
}
// actionCreator.js
import { getSomething } from './serviceLayer.js';
requestSomething(){
return getSomething(); <------- This is what I want to mock
}
// actionCreator.test.js
import test from 'tape';
import {requestSomething} from 'actionCreator.js'
test('should return the mock' , (t) => {
t.equal(requestSomething(), 'something else');
});
I'm answering my own question here... Turns out I was just using babel-plugin-rewire incorrectly. Here's an example of how I'm using it now with successful results.
// serviceLayer.js
export const getSomething = () => {
return 'something';
}
// actionCreator.js
import { getSomething } from './serviceLayer.js';
export const requestSomething = () => {
return getSomething(); <------- This is what I want to mock
}
// actionCreator.test.js
import test from 'tape';
import { requestSomething, __RewireApi__ } from 'actionCreator.js'
__RewireApi__.Rewire('getSomething' , () => {
return 'something else''
});
test('should return the mock' , (t) => {
t.equal(requestSomething(), 'something else');
});

Categories