Event handling inside constructor - javascript

I'm really sorry, but i can't figure out why it doesn't work. printStr() can access variable only defined in Foo constructor, but not in private function, that got triggered on mousedown event. Is there any way to access string without declaring printStr inside getBotheredByBrendanEich func?
function Foo(elem) {
elem.on('mousedown', getBotheredByBrendanEich);
function getBotheredByBrendanEich() {
var string = 'its just werks!';
elem.on('mouseup', printStr);
}
function printStr() {
console.log(string);
}
}
var test = new Foo($('#test'));

Your variable string is a local variable inside of the function get...() and is ONLY available inside of that scope. Local variables are only available within the function they are declared in, which in this case is your get...() function
If you want it available in a broader scope so that printStr() can use it, then you have to declare it at a higher scope.
You could solve this by using an anonymous function declared in the same scope:
function Foo(elem) {
elem.on('mousedown', getBotheredByBrendanEich);
function getBotheredByBrendanEich() {
var str = 'its just werks!';
elem.on('mouseup', function() {
console.log(str);
});
}
}
var test = new Foo($('#test'));
Or, you could pass the argument to the event handler with .bind():
function Foo(elem) {
elem.on('mousedown', getBotheredByBrendanEich);
function getBotheredByBrendanEich() {
var string = 'its just werks!';
elem.on('mouseup', printStr.bind(this, string));
}
function printStr(arg) {
console.log(arg);
}
}
var test = new Foo($('#test'));
Or, you could move the variable to a higher scope so it can be shared:
function Foo(elem) {
elem.on('mousedown', getBotheredByBrendanEich);
var str = 'its just werks!';
function getBotheredByBrendanEich() {
elem.on('mouseup', printStr);
}
function printStr() {
console.log(str);
}
}
var test = new Foo($('#test'));
In all cases though, this structure is troublesome because you've adding a new mouseup event handler everytime the mousedown event occurs. This means you will get multiple mouseup handlers after only a couple clicks. This is rarely ever what you really want to do.
I would suggest this which will not suffer from that problem:
function Foo(elem) {
var str = 'its just werks!';
elem.on('mousedown', function() {
// whatever code you want here
});
elem.on('mouseup', function() {
console.log(str);
});
}
var test = new Foo($('#test'));
One more comment. Your code doesn't show any reason to actually use a constructor here. It appears like you could just implement a normal function call since there is no object instance data.

Related

Make Variables Behave Like Global Variables

I'm wondering if it's possible to move a set of variables from the global scope to a nested scope. Is it possible to use a closure to achieve this in the following context? It must be, right?
The let variables probably shouldn't be within the renderInfo() scope because renderInfo() is called multiple times at load, and this cannot be avoided. Each time renderInfo() is called, render() renders multiple elements, all of which have a click event listener added to them. Hence the variables also can't be here with the way the code is currently structured.
I've tried turning clickToSort() into a closure, but I run into issues every time. I can't figure out how to allow all of the elements with the click event listener to share access to the let variables.
let
sortNameAscending =
sortFreeAscending =
sortSizeAscending = true
// Called multiple times at load.
function renderInfo(a,b,c,d) {
// Renders multiple elements, and adds an event listener to them, each call.
function render(){
// The event listener is added to multiple elements
// that are also rendered herein.
ele.addEventListener('click', (e)=>clickToSort(e, cls, 'aString'))
}
// This function is added to the click event of tons of elements.
function clickToSort(e, cls, dataProperty) {
// How do I move the let variables from the global
// scope to here, so that they behave as if they
// are in the global scope? Is it possible with a
// closure?
// let
// sortNameAscending =
// sortFreeAscending =
// sortSizeAscending = true
// I imagine the following code should be wrapped in
// its own scope, but the scope must have access to
// the arguments of clickToSort(), and the let variables
// which should behave as if they are global.
if (cls.includes('whatever')) {
sortNameAscending = !sortNameAscending
} else if (cls.includes('whatever2')) {
sortFreeAscending = !sortFreeAscending
} else {
sortSizeAscending = !sortSizeAscending
}
}
}
I've tried the following, but it doesn't wanna work.
let
sortNameAscending =
sortFreeAscending =
sortSizeAscending = true
function renderInfo(a,b,c,d) {
function render(){
// The event listener is added to multiple elements
// that are also rendered herein.
ele.addEventListener('click', (e)=>clickToSort(e, cls, 'aString'))
}
function clickToSort(e, cls, dataProperty) {
let
sortNameAscending =
sortFreeAscending =
sortSizeAscending = true
;(function whatevs(){
if (cls.includes('whatever')) {
sortNameAscending = !sortNameAscending
} else if (cls.includes('whatever2')) {
sortFreeAscending = !sortFreeAscending
} else {
sortSizeAscending = !sortSizeAscending
}
)()
}
}
I'm not sure why, although it probably has something to do with the fact that I've bound the clickToSort() function to the elements, instead of perhaps returning a function?
You could wrap the whole function into an immediately invoked function expression. That would ensure closure on your three variables while letting your calls share the same data.
In your anonymous function, you can declare your enclosed variables and return the function which was initially called renderInfo. When your code is executed, those three variables will be declared and kept inside the anonymous function's scope, then renderInfo will be given the value of a function.
// Called multiple times at load.
const renderInfo = (function() {
let
sortNameAscending =
sortFreeAscending =
sortSizeAscending = true
return function(a, b, c, d) {
// Renders multiple elements, and adds an event listener to them, each call.
function render() {
// The event listener is added to multiple elements
// that are also rendered herein.
ele.addEventListener('click', (e) => clickToSort(e, cls, 'aString'))
}
// This function is added to the click event of tons of elements.
function clickToSort(e, cls, dataProperty) {
if (cls.includes('whatever')) {
sortNameAscending = !sortNameAscending
} else if (cls.includes('whatever2')) {
sortFreeAscending = !sortFreeAscending
} else {
sortSizeAscending = !sortSizeAscending
}
}
}
})()
A simple example of using an IIFE (Immediately Invoked Function Expression) to create a closure is the following:
const add = (function() {
let sum = 0;
return function() {
return ++sum;
}
})()
console.log(add())
console.log(add())
console.log(add())
console.log(add())

JS Function returning function for later use - arguments undefined

I am trying to create a function that can then return many functions based on an input. Here is an example of the problem I am facing.
var giveFunction = function(text) {
return function(text) {
console.log(text)
}
}
var test = giveFunction('this is a test');
test()
Running test() at the end prints undefined instead of 'this is a test.' Is there any way around this problem?
The inner function should not contain any parameter,
var giveFunction = function(text) {
return function() {
console.log(text)
}
}
Let it create a closure. If it has a parameter then that would be read during execution and undefined would be printed as you are not calling that function with any arguments.
If you want your code to be working then you have to use bind for that,
var giveFunction = function(text) {
return function(text) {
console.log(text)
}.bind(null, text)
}
var test = giveFunction('this is a test');
test(); //'this is a test'
Lets go one step further and ask why?
var outerFunction = function(outerParameter) {
return innerFunction function(innerParameter) {
// in here we have access to anything in this function and the outer function
// all the way to out the the global scope
// therefore, we dont need to pass innerParameter in again as a parameter! ( in your case we 'next')
}
/// now over here, outside of innerFunction, we do NOT have access to innerParameter!
}
So applying the above principles to your code we have:
var giveFunction = function(text) {
return function() {
console.log(text)
}
}
var test = giveFunction('this is a test');
test()
which now works!
Finally, checkout the most upvoted post under the javascript tag:
How do JavaScript closures work?

Using onclick() inside another function

function layoutMod() {
standardId = document.getElementById("standard");
fancyId = document.getElementById("fancy");
standardId.onclick = function() {
standard();
};
fancyId.onclick = function() {
fancy();
};
};
How can I use the onclick events defined above in a function??? Is it a good practice to load the function at page load?? I need to define in a function the onclick event beacuse I don't want to use global variables.
What you've written should work. However, you should note that by not using the var keyword, you're still creating global variables inside of your function. I would suggest...
function onloadHandler() {
document.getElementById("standard").onclick = function() {
// Do something
};
document.getElementById("fancy").onclick = function() {
// Do something else
};
};
It can get messing when you nest functions inside of each other. In this case, I would suggest removing the outer function so that your code looks like this:
document.getElementById("standard").onclick = function() {
standard();
};
document.getElementById("fancy").onclick = function() {
fancy();
};
The code does not need to be in a function, it will automatically be run on page load. Since you don't want global variables, just don't use variables at all.

remove listener defined in function thats out of scope

I have a module that has to recording functions I want to add. My problem is that because this.audio.stdout has a listener set for another function, I can only remove the listener activated when the start function is called without screwing up other processes. Because the value of filename changes based on when the function was called I have to define the callback in scope of when that value was set. This works for beginning recording with start() but when I call stop(), which removes the listener, the program doesn't know what to do because the callback is out of scope. What would be the proper way to do this?
function Record(rx) {
this.rx = rx;
this.audio = spawn('audio_client');
}
Record.prototype.start = function () {
var self = this;
self.filename= new Date().getTime()+'_'+this.rx
function record(data) {
console.log(self.filename);
}
this.audio.stdout.on('data', record);
}
Record.prototype.stop = function () {
this.audio.stdout.removeListener('data',record);
}
UPDATE:
Sorry I didn't understand what you were asking at first. I looked at this for a bit and this is the best I could come up with. It's not ideal to create the record method for each instance in the constructor like this, but again, this is the best I could come up with.
function Record(rx) {
this.rx = rx;
this.audio = spawn('audio_client');
var self = this;
this.record = function (data) {
console.log(self.filename);
};
}
Record.prototype.start = function () {
this.filename= new Date().getTime()+'_'+this.rx
this.audio.stdout.on('data', this.record);
};
Record.prototype.stop = function () {
this.audio.stdout.removeListener('data', this.record);
};
UPDATE #2:
Better still since you are specific to node, would be this.record = this.record.bind(this);.

JS Function within a function within that function and so on

Ok, I have being trying to find a solution for this for the past 3 hours...
I want to be able to create my own library, accessible function within function with function etc.
Here's what I want to do...
var outer=function()
{
this.inner=function()
{
this.innermost=function()
{
alert("innermost");
}
}
}
var outer=new outer;
function start()
{
//I want to call it like this but fails!
outer.inner.innermost();
}
Now this fails when I try to call the innermost. But if I just have a a function within a function, it works. For example:
var outer=function()
{
this.inner=function()
{
alert("inner");
}
}
var outer=new outer;
function start()
{
// this works
outer.inner();
}
All the examples I've found only show a function within a function.
I want to be able to create my own library of functions. With an easy way to access them, e.g.:
MyLib.SubLib.SubLib2.function
MyLib.SubLib.SubLib2.property
Any help on the matter would be greatly appreciated. Would I have to learn and use prototypes?
First of all, this is how you do it:
var outer = function() {
this.inner = {
innermost: function() {
alert("innermost");
}
}
}
var outer = new outer;
outer.inner.innermost();
The reason why it didn't work the way you did it is because you define a function inner - so outer.inner is a function. You could do var inner = new (outer.inner)(); and then call inner.innermost(); but that's obviously ugly and not what you want.

Categories