Pass global variable to on event callback function in Javascript? - javascript

In the following code, I'm trying to get mydata passed to the callback. This is a sample problem from a bigger problem I'm having. I'm assuming this is a scope issue. What is wrong with my code and/or what should I do?
var EventEmitter = require('events').EventEmitter;
var myevent = new EventEmitter();
var mydata = 'my data!';
function myfunc (data, mydata) {
console.log(data);
console.log(mydata);
};
myevent.on('data', function(data, mydata) {myfunc(data,mydata)});
myevent.emit('data', "data!");
returns:
data!
undefined
I'd like it to return:
data!
my data!

The parameter mydata in the callback's parameter list is hiding the global variable of the same name.
As you passed no parameter in that position, its value is undefined.
Either:
change the name of the parameter, or
remove the parameter, or
pass the required value, e.g. myevent.emit('data', "data!", mydata);
p.s:
myevent.on('data', function(data, mydata) {myfunc(data,mydata)});
would be better just written as:
myevent.on('data', myfunc);

i'm going to make a wild guess (since i am not familiar with EventEmitter) and say that emit's first parameter is the name of the event, and the remaining parameters are passed to the handler.
if that is the case, you're not passing anything to the second callback parameter, which is why it comes in as undefined. try this instead:
myevent.emit('data', "data!", "mydata!");
note: i am ignoring your shadowing issue as it is not related to the problem, just a bad practice.

Modified code: You can access a global variable. from anywhere you do not need to pass it as parameter. even you pass a parameter. you can access a global variable using window.mydata since you are using nodejs you can access a global variable using global.mydata
var EventEmitter = require('events').EventEmitter;
var myevent = new EventEmitter();
var mydata = 'my data!';
function myfunc (data) {
console.log(data);
console.log(mydata);
};
myevent.on('data', myfunc);
myevent.emit('data', "data!");

Related

How to De-serialize reference function in javascript

I want to parse the function I get and execute them. I am trying to de-serialize a function's reference I get from my application's state.
There are two types params I get to parse.
1. Plain function.
2. Function's reference from another class.
For No.1 I got a solution. I use
function foo() {
alert('native function');
return 'Hello, serialised world!';
}
// Serializing
var serializedFunc = foo.toString();
// Deserializing
var actualFunction = new Function('return ' + serializedFunc)();
But for No.2 If I follow the above solution, I get reference error.
var actualFunction = new Function('return ' + AppControllerHelper.testFunction)();
I get reference error.
I know the cause of this error. This error occurs because, the deserialized form of the function looks something like this (given below). It can execute the plain function, but when executing a function's reference. It is unable to find the AppControllerHelper inside the scope and so it throws the error.
// Case No 1. - Executes the body of the anonymous function when called with no err.
(function anonymous(){
return function() { function foo() { alert('native function'); return 'Hello, serialised world!';} }
})
// case no. 2 - When trying to execute it looks for AppControllerHelper and since not found it throws
reference err.
(function anonymous(){
return function() { AppcontrollerHelper.testFunction }
});
Could some one suggest me good solution for this.
Thanks in Advance.
You probably don't need/want to do that in JS.
Take a look at the this keyword and how it works in JS and the methods call(), apply() and bind().
MDN this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
methods: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
This is an example of manually serializing and deserializing a function:
https://gist.github.com/briancavalier/4a820b32e0d2abca89f7
However, I don't think it's a good option for multiple reasons.
As #GBra has mentioned, we don't have to serialize and deserialize the functions.
I used the concept of bind() in javascript to overcome my challenge. with the bind() function I can store the function in a variable and use it later.
let sampleObject = {
foo: function() { console.log("this is a test function") }
}
// passing 'sampleObject' as param will put the 'this' to sampleObject.
let bindFunction = sampleObject.foo.bind(sampleObject);
bindFunction();

How can I pass a parameter to a subsequent function call?

I've a question about subsequent function calls or somehow. I've this code here:
let socket = new WebSocket("localhost:8181");
socket.subscribe("abc").bind("test", function (response) {
console.log(response);
});
subscribe(channel) {
//Here I do some things
return this;
}
bind(eventName, callback) {
//Here I need the "abc" value
}
Currently I'm calling a second function after another to first subscribe something and then bind it. The problem is that I need the value passed to the subscribe function in the following bind function.
Currently I'm returning this because otherwise .bind() would be undefined because of the scope bla bla so because of this I can't just return the channel. Does someone has an idea how I can get this done without changing the function call structure?
You can't return this and also pass a variable. I think your best bet may be wrap your subscribe call in a closure so that you can keep local state.
function createAndSubscribe(abc) {
// You can create other local variables here
let otherLocal = 'foo';
let socket = new WebSocket("localhost:8181");
socket.subscribe(abc).bind("test", function (response) {
// Use abc or foo here
});
}
createAndSubscribe('abc');
Every time you call the function createAndSubscribe, it creates a unique closure that holds the value of abc and any other variables that you create.

how can I store my data in a global variable?

$(function(){
var astronautsData;
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
}
alert(astronautsData.people[0].name)
});
I would like to be able to use the data in every function I make, that's why I tried to put it in the variable astronautsData, but unfortunately astronautsdata is undefined.
You can access astronautsData inside doSomething.your alert() will get executed
before getJSON. that's why you are getting undefined.
$(function(){
var astronautsData;
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
alert(astronautsData.people[0].name)
}
});
Here you must understand one thing that getJSON is 'async'. Your alert method trying to show the data which gonna come in future. In order to solve this problem, you must use 'then', 'done' or 'fail' like below.
$(function(){
var astronautsData;
//Assign your getjson request
var jsonRequest = $.getJSON('http://api.open-notify.org/astros.json');
//This function runs once the getJSON method is success
jsonRequest.done(function(data){
astronautsData = data;
});
//This function runs after the success of getJSON
jsonRequest.then(function(){
//Here you have to do your alert ( This alert will give data )
alert(astronautsData);
});
//This alert will give undefined value as this line of code and getjson request runs parallelly
alert(astronautsData);
});
Your .getJSON is asynchronous.
Try using a Promise to wait for your call to be done :
prom = new Promise((resolve, reject) => {
$.getJSON('http://api.open-notify.org/astros.json', function(){
astronautsData = data;
resolve('Ajax done');
});
});
prom.then((successMessage) => {
console.log(successMessage);
alert(astronautsData.people[0].name)
});
Exposing variables in window/global scope is bad in my opinion. You should wrap it in a function (like a class of sorts) and expose it like this:
function Values(type) {
this.value1 = "something";
}
From this point you can use prototype to define additional functions on "Values" like so:
Values.prototype.doStuff = function() {
return this.value1 + ' addsomething';
};
Inside of the prototype function you can define/return promises or do whatever you want including assigning values to the instance. You can also assign the instance to a global variable to make it a singleton of sorts. Granted your still using a global variable for that but its the instance of Values assigned to the variable not the actual values that are stored.
This is a bit of an over simplification perhaps, but in a way this is how the global variables for lodash or jquery work, although they have a LOT more going on to check for existing global variables and such before attempting to define it on global scope as typically you want to avoid that.
you can use var at global scope (outside of all functions) to declare a global variable:
<script>
var astronautsData;
$(function(){
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
}
alert(astronautsData.people[0].name)
});
</script>
use global.astronautsData if you want it to be global

Knockout subscribe scope

Is there any possibility to change the scope of the subscribe in Knockout?
I have something like this:
element =
{
type: ko.observable()
name: ko.observable()
content: ko.observable()
}
element.type.subscribe(this._typeChanged.bind(element))
Basically I want to have an access to the object which property I am subscribed to. Binding like in my code does nto work since it binds to the whole VeiwModel and not the object.
Maybe the knockout handle that when you subscribe an observable you can pass 2 parameters the first is the callback and the second is the scope/context, try something like this:
element.type.subscribe(this._typeChanged, element)
The subscribe function accepts three parameters: callback is the function that is called whenever the notification happens, target (optional) defines the value of this in the callback function, and event (optional; default is "change") is the name of the event to receive notification for.
Ref. http://knockoutjs.com/documentation/observables.html
The problem is the way in which you're creating your view model. The view model shuld be self-contained, including the functions that operate on it. It should be something like this:
var ViewModel = function() {
var self = this;
self.type = ko.observable();
self.name = ko.observable();
self.content = ko.observable();
self.type.subscribe(function(newVal) {
// here you have access to all the viewmodel properties through self
});
return self;
};
This is a constructor using the var self=this; pattern.To use the view model you need to instantiate it, i.e. var vm = new ViewModel(). (You can omit the new).
Of course, you can also define a function, and bind it to self, or receive a callback in the constructor, and bind it to self. In that case, the function implementation will have the view model accesible via this, and not self, which will be undefined inside the function body.
var doSomethignWithVm = function(newVal) {
// acces viewmodel via this
// you can also use newVal
};
You modify the constructor to receive this as a callback:
var ViewModel = function(doSomethingCallback) {
self.type.subscribe(callback.bind(self));
};
This pattern doesn't make much sense because your callback is supposed to have knowledge of your view model. In that case it makes more sense to include the subscription functionality directly inside the model.
EDIT
Note: as I've mentioned in a comment to Joel Ramos Michaliszen's answer, both of this codes are equivalent:
self.type.subscribe(callback.bind(self));
self.type.subscribe(callback.bind, self);
You can check that by seeing the source code of subscribable in knockout's gitbhub, in the file knockout/src/subscribales/subscribable.js. If you look for subscribe implementation you'll see this:
subscribe: function (callback, callbackTarget, event) {
// ...
boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;
I.e. if you provide a second argument, it's used tob bind the function passed in the firt argument to it.
Although I get that I may have the wrong approach top this I am also in a stage where I will not be able to do any breaking changes to the app.
I figured out that I could use lodash to help me with this.
I ended up using partial function to append the element as a parameter in the subscribe callback:
element.type.subscribe(_.partial(this.typeChanged, element))
or in coffeescript
element.type.subscribe $_.partial #typeChanged, element
Now the chartTypeChanged has 2 parameters on the input instead of one.

Function parameter not getting the value directly

Can someone please explain why the function not getting the value of the object in the first way?
I got the Backbone.View:
var some.view = Backbone.View.extend({
elements = {},
//...
//some init, filling up elements...
//...
stopTask: function() {
// Calling the function with parameters explained later
stopThisTask(...);
}
});
And the function:
function stopThisTask(task){
console.log(task);
}
When I call stopThisTask in the following way, the task parameter is undefined
stopThisTask(this.elements);
However, when I do it like this, the task has the value
var tmp = this.elements;
stopThisTask(tmp);
Can someone please explain why is that?
If I know right the variables are passed by value, and the obects are passed by references. However, does that mean in some way I loose the reference for the elements object?
I'm suspecting that the this.elements gets resolved inside the stopThisTask function, so this will point to stopThisTask instead of to the caller of stopThisTask.
By explicitly setting the tmp parameter in the caller, you guarantee the correct this scope is used.
Should be equivalent to
stopThisTask.call(this, this.elements);

Categories

Resources