Trying to understand closures (JavaScript) - javascript

function myFunc(inputFunc){
var called = false;
return function() {
if (!called) {
called = true;
var storedResult = inputFunc();
return storedResult;
}
else
return storedResult;
};
}
In the above code, I don't understand what purpose it serves to have the if-else statement returned in a function. Wouldn't it be the same effect if I just had the following instead?
function myFunc(inputFunc){
var called = false;
if (!called) {
called = true;
var storedResult = inputFunc();
return storedResult;
}
else
return storedResult;
}

Wouldn't it be the same...
Not really, the outer function returns a function, enclosing the called variable in it's scope so it doesn't change in later calls
Here's how the first code snippet would work
var instance = inputFunc();
var storedResult = instance(); // returns the result
var runItAgain = instance(); // probably returns `undefined`
Your second version wouldn't do any of that, it would just be
var storedResult = inputFunc(); // result
var runItAgain = inputFunc(); // result again, the "called" variable is always false
In other words, the first version returns the result once, and only once, here's a snippet
function myFunc(inputFunc) {
var called = false;
return function() {
if (!called) {
called = true;
var storedResult = inputFunc();
return storedResult;
} else
return storedResult;
};
}
var instance = myFunc(function() {
return 'result';
});
var log = [];
log.push( instance() ); // result
log.push( instance() ); // undefined
log.push( instance() ); // undefined
log.push( instance() ); // undefined
document.body.innerHTML = '<pre>' + JSON.stringify(log, null, 4) + '</pre>';

Related

Get return value of worker.onmessage inside a function?

I have created a Caching (Memoized) function which takes another function as a parameter
The following is the function which is being cached. The function utilises a worker. The issue here is that if
var hello = GetSubRegion(1233) ,then hello is undefined because the function inside onmessage returns a value but not the parent GetSubRegion function.
function GetSubRegion(selectedMainRegion){
if (typeof(subRegWorker) != "undefined") {
subRegWorker.terminate();
}
subRegWorker = new Worker("subRegWorker.js");
subRegWorker.onmessage = function(e) {
var workData = e.data;
jQuery("#_sub_region").html(workData);
subRegWorker.terminate();
return workData;
}
var result = subRegWorker.postMessage(selectedMainRegion);
return result;
}
The following is the caching function. Due to the above issue, there is no value returned for let result = fun(n) , and hence nothing is cached.
function memoizer(fun){
let cache = {}
return function (n){
if (cache[n] != undefined ) {
return cache[n]
} else {
console.log(n);
let result = fun(n)
cache[n] = result
return result
}
}
}
How to solve this ?
The following is how I am calling the cached function.
jQuery("#_main_region").change(function() {
var getCacheSub = memoizer(GetSubRegion);
var inputMainRegion = jQuery('#_main_region').find(":selected").val();
getCacheSub(inputMainRegion);
});
The caching issue was solved as follows, the changed code is market as comment -
var cache = {};
function memoizer(fun){
return function (n){
if (cache[n] != undefined ) {
jQuery("#_sub_region").html(cache[n]); // This was changed
return cache[n]
} else {
console.log(n);
cache[n] = result
return result
}
}
}
function GetSubRegion(selectedMainRegion){
if (typeof(subRegWorker) != "undefined") {
subRegWorker.terminate();
}
subRegWorker = new Worker("subRegWorker.js");
subRegWorker.onmessage = function(e) {
var workData = e.data;
cache[n] = workData // This was changed
jQuery("#_sub_region").html(workData);
subRegWorker.terminate();
return workData;
}
subRegWorker.postMessage(selectedMainRegion);
}

Can't have access to a variable using call in Javascript

I'm studying Javascript and learning how to use call. I created this script and I don't know why I can't have access to this variable Time.
var MyObject;
(function(MyObject) {
var Runner = (function() {
function Runner(time) {
this.time = time;
}
var myFunctionArray = [];
Runner.prototype.execute = function() {
myFunctionArray[0]();
}
Runner.prototype.newTest = function(index, execute) {
var test = function() {
return execute.call(this);
}
myFunctionArray.push(test);
}
return Runner;
})();
MyObject.Runner = Runner;
})(MyObject || (MyObject = {});
var myNewObj = new MyObject.Runner(1000); myNewObj.newTest('1', function() {
console.log(this.time) //output: undefined
});
So how can I get time value inside newTest function?
Issue is in newTest function
Runner.prototype.newTest = function(index, execute) {
var test = function() {
return execute.call(this);
}
myFunctionArray.push(test);
}
Here this is pointing to test and not Runner. You will have to save context in a variable and then set it in call.
Runner.prototype.newTest = function(index, execute) {
var self = this;
var test = function() {
return execute.call(self);
}
myFunctionArray.push(test);
}
.call + self
var MyObject;
(function(MyObject) {
var Runner = (function() {
function Runner(time) {
this.time = time;
}
var myFunctionArray = [];
Runner.prototype.execute = function() {
myFunctionArray[0]();
}
Runner.prototype.newTest = function(index, execute) {
var self = this;
var test = function() {
return execute.call(self);
}
myFunctionArray.push(test);
}
return Runner;
})();
MyObject.Runner = Runner;
})(MyObject || (MyObject = {}));
var myNewObj = new MyObject.Runner(1000);
myNewObj.newTest('1', function() {
console.log(this, this.time) //output: undefined
});
myNewObj.execute()
.bind
As commented, you can even use .bind
var MyObject;
(function(MyObject) {
var Runner = (function() {
function Runner(time) {
this.time = time;
}
var myFunctionArray = [];
Runner.prototype.execute = function() {
myFunctionArray[0]();
}
Runner.prototype.newTest = function(index, execute) {
myFunctionArray.push(execute.bind(this));
}
return Runner;
})();
MyObject.Runner = Runner;
})(MyObject || (MyObject = {}));
var myNewObj = new MyObject.Runner(1000);
myNewObj.newTest('1', function() {
console.log(this, this.time) //output: undefined
});
myNewObj.execute()
When you declare your Runner function, you've actually declared a function that takes no arguments that then itself declares a function called Runner that takes one argument.
Actually In this code snippet :
Runner.prototype.newTest = function(index, execute) {
var test = function() {
return execute.call(this);
}
myFunctionArray.push(test);
}
this will reference to test variable (as per constructor invocation pattern)
So, to pass right variable cache the value of this in another variable and then pass that to function.

how to return value inside of forEach loop in JavaScript

I got stuck with my code.
I wrote this sample code only for the purpose to reproduce my problem, so this code is not practical at all but I hope you get my point.
In the code below, for the last value to be output, I expect it to be 3, but it's undefined.
How am I supposed to write if I want the last value to be 3 in this case??
This is just a sample code, but in the actual code, I fetch content from amazon api and when it returns api error, I want to run the same function again after 1000 milli seconds.
var list = [1,2,3];
var someClass = new SomeClass();
list.forEach(function(value) {
var result = someClass.getSomething(value);
console.log("outside: " + result);
});
function SomeClass() {
var flag = false;
this.getSomething = function(something) {
if (something === 3 && flag === false) {
flag = true;
this.getSomething(something);
//I need to return here, so the succeeding code is not read.
return;
}
console.log("inside: " + String(something));
return something;
}
}
Log
inside: 1
outside: 1
inside: 2
outside: 2
inside: 3
outside: undefined // I expect this value to be 3!!!
You have a test:
if (something === 3 && flag === false) {
//...
return;
If you want to return 3 then don't have a return statement with nothing after it. return means return undefined. Put return 3 or return something.
You probably want to return from your recursive call though:
return this.getSomething(something);
Here's the problem:
function SomeClass() {
var flag = false;
this.getSomething = function(something) {
if (something === 3 && flag === false) {
flag = true;
this.getSomething(something); // not returning this
return; // returning undefined
}
console.log("inside: " + String(something));
return something;
}
}
Here's the fix:
function SomeClass() {
var flag = false;
this.getSomething = function(something) {
if (something === 3 && flag === false) {
flag = true;
return this.getSomething(something);
}
console.log("inside: " + String(something));
return something;
}
}
change the code to
if (something === 3 && flag === false)
{
flag = true;
return this.getSomething(something);
}
"return;" returns undefined
It returns undefined in your code because you return; in the if clause.
return this.getSomething(something) within the if clause
var list = [1, 2, 3];
var someClass = new SomeClass();
list.forEach(function(value) {
var result = someClass.getSomething(value);
console.log("outside: " + result);
});
function SomeClass() {
var flag = false;
this.getSomething = function(something) {
if (something === 3 && flag === false) {
flag = true;
return this.getSomething(something);
}
console.log("inside: " + String(something));
return something;
}
}
forEach loop doesn't return a value.
You can create a global variable and assign values to it.

Simplify the code by using cycle function

I have multiply functions which are using the same cycle code and i'm wondering is it possible to simplify the code by having one cycle function so i could execute the code just by calling wanted function names.
Now:
for(var i=0;i<all;i++){ someFunction(i) }
Need:
cycle(someFunction);
function cycle(name){
for(var i=0;i<all;i++){
name(i);
}
}
I tried to do this by using "window" and i get no error but the function is not executed.
var MyLines = new lineGroup();
MyLines.createLines(); // works
MyLines.addSpeed(); // doesn't work
var lineGroup = function(){
this.lAmount = 5,
this.lines = [],
this.createLines = function (){
for(var i=0,all=this.lAmount;i<all;i++){
this.lines[i] = new line();
}
},
this.addSpeed = function (){
// no error, but it's not executing addSpeed function
// if i write here a normal cycle like in createLines function
// it's working ok
this.linesCycle("addSpeed");
},
this.linesCycle = function(callFunction){
for(var i=0,all=this.lAmount;i<all;i++){
window['lineGroup.lines['+i+'].'+callFunction+'()'];
}
}
}
var line = function (){
this.addSpeed = function (){
console.log("works");
}
}
window['lineGroup.lines['+i+'].'+callFunction+'()'];
literally tries to access a property that starts with lineGroups.lines[0]. Such a property would only exist if you explicitly did window['lineGroups.lines[0]'] = ... which I'm sure you didn't.
There is no need to involve window at all. Just access the object's line property:
this.lines[i][callFunction]();
i get no error but the function is not executed.
Accessing a non-existing property doesn't generate errors. Example:
window[';dghfodstf0ap9sdufgpas9df']
This tries to access the property ;dghfodstf0ap9sdufgpas9df, but since it doesn't exist, this will result in undefined. Since nothing is done with the return value, no change can be observed.
Without a name space use:
window["functionName"](arguments);
SO wrap it up and use it thus:
cycle(someFunction);
function cycle(name){
for(var i=0;i<all;i++){
window[name](i);;
}
}
With a namespace, include that:
window["Namespace"]["myfunction"](i);
Note that this is likely a bit of overkill but using a function to make a class object (you can google the makeClass and why it is/could be useful) you can create instances of the object.
// makeClass - By Hubert Kauker (MIT Licensed)
// original by John Resig (MIT Licensed).
function makeClass() {
var isInternal;
return function (args) {
if (this instanceof arguments.callee) {
if (typeof this.init == "function") {
this.init.apply(this, isInternal ? args : arguments);
}
} else {
isInternal = true;
var instance = new arguments.callee(arguments);
isInternal = false;
return instance;
}
};
}
var line = function () {
this.addSpeed = function () {
console.log("works");
};
};
var LineGroup = makeClass();
LineGroup.prototype.init = function (lineNumber) {
this.lAmount = lineNumber?lineNumber:5,
this.lines = [],
this.createLines = function (mything) {
console.log(mything);
var i = 0;
for (; i < this.lAmount; i++) {
this.lines[i] = new line();
}
},
this.addSpeed = function () {
console.log("here");
this.linesCycle("addSpeed");
},
this.linesCycle = function (callFunction) {
console.log("called:" + callFunction);
var i = 0;
for (; i < this.lAmount; i++) {
this.lines[i][callFunction]();
}
};
};
var myLines = LineGroup();
myLines.createLines("createlines");
myLines.addSpeed();
//now add a new instance with 3 "lines"
var newLines = LineGroup(3);
newLines.createLines("createlines2")
console.log("addspeed is a:" + typeof newLines.addSpeed);
console.log("line count"+newLines.lAmount );
newLines.addSpeed();

Why won't this object method return a boolean value Javascript

My app's js file includes this bit here:
var drawer = document.getElementById('b_001');
drawer.isOpen = function() {
this.classList.contains('open');
};
When I call it in the console, drawer.isOpen(), I expect a boolean value, true or false. However, undefined is returned instead. Why is this?
you need a return statement
return this.classList.contains('open');
You'll have to return it:
drawer.isOpen = function() {
return this.classList.contains('open');
//^ here
};
If a function doesn't return anything, the return value is considered undefined, as this snippet demonstrates:
var report = document.querySelector('#result');
report.innerHTML += doStuff(5); // nothing returned
report.innerHTML += '<br>'+addFive(5); // a result is returned
function doStuff(val) {
val = val || 0;
val += 5;
}
function addFive(val) {
val = val || 0;
val += 5;
return val;
}
<div id="result"></div>

Categories

Resources