How do you perform operations on an existing closure? - javascript

Creating the closure is easy but using it is confusing for me. Here is my closure. Once I have it I need to be able to call operations on it like doWork, calculateThis, doAnimation, etc. but there doesn't seem to be a way to access functions inside the closure.
function worker(input) {
return function () {
doWork = function () {
alert("doing work");
};
}
}
function caller() {
var myWorker = worker();
myWorker.doWork(); // this fails
}
*The question you're asking appears subjective and is likely to be closed. - Thanks again stackoverflow

I believe this is what you are asking for:
function worker(input) {
return {
doWork: function () {
alert("doing work");
},
doAnimation: function() {
alert("animating");
}
}
}
You can now call it using your code:
var myWorker = worker();
myWorker.doWork();
myWorker.doAnimation();
Note that your code is not really using closures, but this one does:
function worker(input) {
return {
doWork: function () {
alert("doing work: " + input);
},
doAnimation: function() {
alert("animating: " + input);
}
}
}
var workerA = worker('A');
var workerB = worker('B');
workerA.doWork();
workerB.doAnimation();
Can you see the difference?

You are trying to execute a method work() but in your example you return a function, not an object with a property "work".
Here's what you're probably after:
function worker(input) {
return {
work: function () {
alert("doing work");
};
}
}

Related

How to execute (route) specific Javascript functions in one file, based on url, without a framework and interfering

Well, that's a loaded question (for search purposes), and potentially stupid.
I am experimenting for learning and I'd like to know what would be a great way to accomplish this.
All the reading I've done on routing addresses just the HTML part, and not the Javascript functionality once it loads.
Let's say this is the script file.
let path = window.location.pathname;
if (path.includes("/foo")) initFoo();
if (path.includes("/bar")) initBar();
function initFoo(){
console.log("foo");
function doSomething(){
console.log("something 1");
}
}
function initBar(){
console.log("bar");
function doSomething(){
console.log("something 2");
}
}
How can doSomething() be called from outside? The function is not available once the init() executes. If it's not inside an init(), then the functions collide.
Is this a classic OOP moment, where I'd have to create a Foo() and Bar() class where doSomething() is a method?
How would the code solving this look like?
Simple answer, it is not accessible, because it's in other scope.
More verbose answer, solution would be to use closure to get reference to this function. For example by returning doSomething inside of initBar
function initBar(){
console.log("bar");
function doSomething(){
console.log("something 2");
}
return doSomething;
}
So you can call it then as
const func = initBar();
func();
I think the answer to this depends on how you plan to apply this approach to whatever scale you're targeting for your Proof of Concept.
Having classes Foo() and Bar() each with their own doSomething() is definitely a feasible approach, but may not be necessary.
Are you able to assume that by visiting /foo that doSomething() will always be called?
Go with Dominik's answer:
let path = window.location.pathname;
if (path.includes("/foo")) initFoo()();
if (path.includes("/bar")) initBar()();
function initFoo(){
console.log("foo");
function doSomething(){
console.log("something 1");
}
return doSomething;
}
function initBar() {
console.log("bar");
function doSomething() {
console.log("something 2");
}
return doSomething;
}
Or might your init functions have more than one closure that you need to target?
In this case, you may be able to target your closures with a query parameter in your route:
/foo?method=doSomething
let path = window.location.pathname;
let params = Array.from(
(new URLSearchParams(window.location.search)).entries()
);
function getMethodFromParams(defaultMethod = 'doSomething') {
let [ method ] = params.find(function([ value, key ]) {
return key === 'method';
});
return method !== undefined && method.length > 0
? method
: defaultMethod;
}
let method = getMethodFromParams();
let action;
if (path.includes("/foo")) action = initFoo()[method];
if (path.includes("/bar")) action = initBar()[method];
action();
function initFoo() {
const method = getMethod();
console.log("foo");
function doSomething() {
console.log("something 1");
}
function doSomethingElse() {
console.log("something else 1");
}
return {
doSomething,
doSomethingElse
};
}
function initBar() {
const method = getMethod();
console.log("bar");
function doSomething() {
console.log("something 2");
}
function doSomethingElse() {
console.log("something else 2");
}
return {
doSomething,
doSomethingElse
};
}

How to create a custom chainable delay function in JavaScript using prototype, IIFE, currying or using new keyword

How can I create a custom chainable delay function in JavaScript using prototype or currying or using new keyword?
Original question is
var foo = function () {
console.log("bingo!");
};
function bar() {
console.log("Wow!");
}
// make below two lines work
foo.delay(300); // after 0.3s: "bingo!"
bar.delay(600); // after 0.6s: "Wow!"
// This returns undefined, how to fix it?
My attempt so far.
function delay(time) {
setTimeout(this, time);
}
var foo = (function () {
console.log();
console.log("bingo!");
return {
delay: delay.bind(this)
}
})();
function bar() {
console.log("Wow!");
return {
delay: delay.bind(this)
}
};
// bar.prototype.delay = function() { return console.log("bar.prototype.delay"); }
foo.delay(300); // after 0.3s: "bingo!"
bar.delay(600); // after 0.6s: "Wow!"
Lastly, can I ask you where would be a good place to study these kind of topics to be more fluent in JavaScript? Thank you in advance.
You have a problem with this code:
setTimeout(this, time); // The first param must be the function to be executed after `n` ms.
Here you need to pass the time value to the function delay, you could pass the implicit argumentsarray.
return {
delay: delay.bind(this) // Here you need to pass the `time` value.
}
This is an approach to bind the delay function.
return {
delay: delay.bind(this, function() {
console.log("Wow!");
}, ...arguments)
}
Important: You don't to bind the function delay to pass the context this value. That binding it's necessary if the function delay will use the context this.
function delay(fn, time) {
setTimeout(fn, time);
}
var foo = (function() {
return {
delay: delay.bind(this, function() {
console.log("bingo!");
}, ...arguments)
};
})();
var bar = (function() {
return {
delay: delay.bind(this, function() {
console.log("Wow!");
}, ...arguments)
};
})();
// bar.prototype.delay = function() { return console.log("bar.prototype.delay"); }
foo.delay(300); // after 0.3s: "bingo!"
bar.delay(600); // after 0.6s: "Wow!"

Pass a function as a parameter that may not exist yet in Javascript

Is it possible to pass a callback function that does not exist yet? My goal is to have a common function that will wait for another callback function to exist, when it does exist, it should execute it. This is what I have so far, but I can't figure out how to pass the function in that doesn't exist as a function yet.
function RunTemplateFunction(callback, userInfo) {
if ($.isFunction(callback)) {
callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(callback)) {
clearInterval(myInterval);
callback(userInfo);
}
}, 200);
}
}
I run the function like this:
RunTemplateFunction(MyFunctionToRun, GetUserInfo());
I get MyFunctionToRun is undefined for obvious reasons, I also tried the workaround of passing the function as a string and then convert the string to a function using eval(). But that throws the same error. I also thought of using the new function(), but that actually creates a new function.
Any help is appreciated. thank you.
If you call RunTemplateFunction by undefined there is no way we can see, is callback is defined or not, as we don't have reference to anything.
If you can modify the declaration to accept object as below, we can achieve what we want
function RunTemplateFunction(options, userInfo) {
if ($.isFunction(options.callback)) {
console.log('called1',userInfo);
options.callback(userInfo);
} else {
var myInterval = setInterval(function () {
if ($.isFunction(options.callback)) {
console.log('Called dynamically!!');
clearInterval(myInterval);
options.callback(userInfo);
}
}, 200);
}
}
var options = {}
RunTemplateFunction(options,{user:122});
options.callback = function(){
console.log("I'm called!!");
}
This will print
Called dynamically!!
I'm called!!
EDIT:
We can also call callback function in following way without setInterval, it will look different but options.callback variable is replaced by template.callMe function and its instantaneous also.
function TemplateRunner(userInfo){
this.callMe = function(cb){
this.templateFunction(cb);
}
this.templateFunction = function(callback){
callback(userInfo);
}
}
var template = new TemplateRunner({user:100})
template.callMe(function(user){
console.log('call me1',user);
});
template.callMe(function(user){
console.log('call me2',user);
})
This will print
call me1 {user: 100}
call me2 {user: 100}

Disable a JavaScript function after it runs

I presume it is possible to create a JavaScript function that disables it self after it is done running.
Is possible? How can this effect be achieved?
Wrap arbitrary runnable in following manner:
function once(subject) {
var first = true;
return function() {
if (first) {
first = false;
return subject();
} else {
return null;
}
};
}
var wrapper = once(function() {alert("No more!");});
wrapper(); // alerts
wrapper(); // noop
Runnable will only be executed on first invocation of wrapper.
You can convert a function of arbitrary arguments to an argumentless runnable.
If you want the functionality to be happen only once you can use the following function
function once(fn, context) {
var result;
return function() {
if(fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
// Usage
var canOnlyFireOnce = once(function() {
console.log('Fired!');
});
canOnlyFireOnce(); // "Fired!"
canOnlyFireOnce(); // nada
Courtesy: https://davidwalsh.name/essential-javascript-functions
something like this?
function a(){ alert(1); a = null;}
invoke a() once, second time it will say
Uncaught TypeError: a is not a function
if the function is anonymous, then make it IIFE
(function(){ alert(1);})();
var _flag = true; // Have a flag variable.
function oneTimer(){
// Check flag is set to true or not
if(!_flag) return;
_flag = false;
// Your function definition here.
}
As commented, if you want to execute a function only once, you should try IIFE. These functions are invoked immediately and cannot be called afterwards.
Following is a sample code.
(function test() {
console.log("test");
(function innerFunc() {
console.log("Inner Function");
})();
try {
innerFunc();
} catch (ex) {
console.log(ex)
}
})();
try {
test();
} catch (ex) {
console.log(ex)
}
Pretty easy, just assign an empty function to the function:
function once() {
alert('once');
once = function () { };
}
once();
once();

jQuery plugin public method/function

I am trying to achieve something like the following but dont know whats wrong:
$.a = function() {
// some logic here
function abc(id) {
alert('test'+id);
}
}
$.a.abc('1');
I tried using the return function, but that doesnt seem to work either. Can someone please help.
Thank you for your time.
Since $.a must be a function in itself, you'll have to add the abc function as a property to the $.a function:
$.a = function () {
// some logic here...
};
$.a.abc = function (id) {
alert('test' + id);
};
If abc must be defined from within the $.a function, you can do the following. Do note that $.a.abc will not be available until $.a has been called when using this method! Nothing inside a function is evaluated until a function is called.
$.a = function () {
// Do some logic here...
// Add abc as a property to the currently calling function ($.a)
arguments.callee.abc = function (id) {
alert('test' + id);
};
};
$.a();
$.a.abc('1');
$.a = (function(){
var a = function() {
//...
};
a.abc = function() {
//...
}
return a;
})();

Categories

Resources