I'm still trying to understand javascript scoping. What is the simplest way to return a value from an anonymous callback function? For instance,
var test = 'outside';
callsFunction(function() { test = 'inside'; });
console.log(test);
where callsFunction calls the anonymous function. I would like this to print 'inside'.
I'm a little bit confused, but I believe this is what you're after
function callsFunction( fn )
{
fn();
}
var test = 'outside';
callsFunction(function() { test = 'inside'; });
console.log(test);
Note that any function can be invoked via the usage of (). However, there are special methods for invoking functions from different contexts, such as Function.call() and Function.apply()
At the risk of pointing out the obvious, the simplest way to have something done after a callback is to simply include it in the callback (and this is, in fact, the way to go):
var test = 'outside';
callsFunction(function() {
test = 'inside';
console.log(test);
});
A real example: let's say you want to update a div with the contents of a file from an Ajax call.
Ajax('file.html', function (data) {
// Update the div here
document.getElementById('d').innerHTML = data;
});
// Not here
Maybe what you are wanting to research is closures in JavaScript?
You didn't define callsFunction in your question, but if you make it a self-invoking anonymous function, you can return the new 'test' value:
var test = 'outside';
(function() { test = 'inside'; })();
console.log(test); // returns 'inside'
If you do define callsFunction:
var test = 'outside';
var callsFunction = function() {
test = 'inside';
return test;
};
console.log(callsFunction()); // returns 'inside'
You can get more complicated with closures.
Related
I am looking to call a function that was originally just an anonymous function, but it turned out I need this function 3 times in my code.
So I defined a function like this:
function saveButton() {
this.parentElement.parentElement.querySelector('h3').innerHTML = this.parentElement.querySelector('input[name="task-title"]').value;
this.parentElement.parentElement.querySelector('p').innerHTML = this.parentElement.querySelector('textarea').value;
this.parentElement.parentElement.querySelector('.popup').className = 'popup hidden';
this.parentElement.parentElement.querySelector('.overlay').className = 'overlay hidden';
saveWork();
};
I want to call this function in an anonymous function like this :
confirmButton.onclick = function()
saveButton();
};
But afterwards I realized that I couldn't use the this in the anonymous function. How can I call confirmButton() in the anonymous function?
confirmButton.onclick = saveButton;
or
confirmButton.onclick = function(){
saveButton.call(this);
};
although it's not a good practice to have the same name for DOM node and a function that you want to call. rename your function into something that makes more sense like buttonClick
Have you tried using function expressions?
Essentially it means assigning a function to a variable.
Read this answer to learn about the differences between function expressions and function declarations.
As for your question, most of the time it's this case:
You want to use the parent scope of a given anonymous function.
If thats the case, I would recommend this neat little trick:
var self = this;
this.saveButton = function() { // or self.saveButton...
this.parentElement.parentElement.querySelector('h3').innerHTML = this.parentElement.querySelector('input[name="task-title"]').value;
this.parentElement.parentElement.querySelector('p').innerHTML = this.parentElement.querySelector('textarea').value;
this.parentElement.parentElement.querySelector('.popup').className = 'popup hidden';
this.parentElement.parentElement.querySelector('.overlay').className = 'overlay hidden';
saveWork();
};
confirmButton.onclick = function() {
self.saveButton();
}
This trick can be used in any level of scope depth, just don't pollute the global namespace :)
By looking at the code fragment you posted, and guessing a few things, I suggest the following refactoring:
function saveButton(parentElem) {
var myParent = parentElem || this.parentElement;
myParent.parentElement.querySelector('h3').innerHTML = myParent.querySelector('input[name="task-title"]').value;
myParent.parentElement.querySelector('p').innerHTML = myParent.querySelector('textarea').value;
myParent.parentElement.querySelector('.popup').className = 'popup hidden';
myParent.parentElement.querySelector('.overlay').className = 'overlay hidden';
saveWork();
}
confirmButton.onclick = function() {
// I suppose when this function is called somewhere else,
// you actually know who is the parent element, so:
saveButton(document.querySelector('.theParentElement'));
};
// If you calling it somewhere where "this" is available,
// then simply call the function with no arguments:
saveButton();
Maybe some variation of the example above can help you. Other than that, I can't think of a better answer without looking at a greater portion of your code.
I'm a javascript newbie and trying to understand how functions work. I found a similar question here but it doesn't really answer my question.
Taking the following piece of javascript as an example
var test = function(){
console.log("kick off");
var insideTest = "variable inside test";
var init = function(){
var insideInit ="variable inside init";
console.log("inside init");
}
return{
init:init
}
}
test().init();
The above code prints the following:
kick off
inside init
But if I remove
return{
init:init
}
it gives me an error saying
Uncaught TypeError: Cannot read property 'init' of undefined
Also, even though I'm calling init method using test().init() it doesn't print inside Init if the return statement is removed.
My question is why is it necessary to return init:init to execute init method.
EDIT:
To answer why my init function is inside the test() function here is the larger picture of what i'm trying to do.
var test = function() {
var init = function() {
var a = 0;
function1();
function2();
}
var function1() = function() {
//some code
}
var function1() = function() {
//some code
}
return {
init: init
}
}
Have added inline comments. Also the init inside test will have access to variable defined outside it(init) scope which is closure. test is returning an object to access it's inner function.This specific pattern is revealing module pattern
var test = function(){
console.log("kick off");
var insideTest = "variable inside test";
// Here init is a function which is private to test function
// Any function calling test will not have access to init unless it is 'exposed'
var init = function(){
var insideInit ="variable inside init";
console.log("inside init");
}
return{
init:init // exposing the private function
}
}
When you return, you're returning an Object with a single key of init, which you've assigned the "init" function that you defined within the test function. This allows you to return multiple functions if you'd like, so you can chain calls.
If you'd prefer a different way, you could just return the function without the curly braces, ie. return init;, and then assign the return of test() to a variable. var externalInitFnc = test();
Edit: Looking back it seems that you are fuzzy on the idea of scope in Javascript. When you defined init within the test function, it is only accessible within that function. Similar to how a private variable in a Java class is only available within that same class.
I'm pretty sure this is n00b question, but I'm completely new to javascript. I'm wondering why this code only prints "hello" but when I comment out the first function, that's when I get the second function to print the other two words. How does this make sense?
var function1 = createFunction();
function createFunction()
{
console.log("hello");
}
function1();
function createFunctionPrinter(word)
{
console.log(word);
}
var printSample = createFunctionPrinter('sample');
var printNoo = createFunctionPrinter('noo');
printSample(); //should console.log('sample');
printNoo(); //should console.log('noo');
function1 is the return value of calling createFunction which is undefined because createFunction has no return statement.
undefined is not a function, so calling function1() raises an exception and execution halts.
If you want to refer to an method, you should leave the (), as the function call return undefined.
See this example
function createFunction()
{
console.log("hello");
}
var function1 = createFunction;
function1();
function createFunctionPrinter(word)
{
console.log(word);
}
var printSample = createFunctionPrinter;
var printNoo = createFunctionPrinter;
printSample('sample'); //should console.log('sample');
printNoo('noo'); //should console.log('noo');
Fixing function1 and createFunction() should be easy, provided the fact no arguments are needed for this. Simply set var function1 = createFunction without () and you it will effectively make function1 call createFunction as if that was the function's name.
createFunctionPrinter() is a bit different. My preferred approach is the use of a prototype, which will take an argument (word) when called, and then when you call its print() method, it will essentially print your text. The assignment of printSample and printNoo is similar, but you have to use the new keyword. Finally, to make the functions print, use something like printSample.print().
function createFunction() {
console.log("hello");
}
function createFunctionPrinter(word) {
this.word = word;
this.print = function() {
console.log(word);
}
}
var function1 = createFunction;
function1();
var printSample = new createFunctionPrinter('sample');
var printNoo = new createFunctionPrinter('noo');
printSample.print();
printNoo.print();
P.S.: This might not the intended use of prototypes, but I believe it will make your life easier to use them in this case.
var function1 = createFunction();
function createFunction()
{
// return a function that prints a message
return function() {
console.log("hello");
}
}
function1();
While solving a programming challenge, I wrote a function which was intended to take a function as an argument and return a function as well. The returned function was meant to execute the argument function (which was passed to first function). The function's code :-
function func1(f){
let func2 = function(){
if(/*a condition based on a global variable*/){
f();
}
}
return func2;
}
This is currently not working and it raises an Illegal Invocation Type Error. I saw this question but I don't know how to relate it's answers to my code. So, my questions are :-
Why isn't my code working?
What can I do to make it work?
EDIT
I'm invoking the function like this :-
var someFunc = func1(alert);
someFunc("foo");
someFunc("bar");
You need to handle
the context of the function call
the arguments
the returned value
Here's an implementation:
function func1(f, context){
let func2 = function(){
if( some condition ){
return f.apply(context, arguments);
} // there probably should be some "else" behavior...
}
return func2;
}
With some example uses:
var fun = func1(console.log, console);
fun("A", 25); // logs "A", 25
fun = func1(alert);
fun("foo"); // alerts "foo"
Why don't you use var instead of let
function func1(f){
var func2 = function(){
if(/*a condition based on a global variable*/){
f();
}
}
return func2;
}
How can i call a YUI function that is wrapped inside a YUI().use from javascript?
example
Below is a YUI function "runShowAnim" which executes animShow.run(); for an animation effect...
var runShowAnim = function(e) {
animShow.run();
};
I want this effect to happen when i validate something in a javascript function. I tried to call it as below. But it doesn't seem to work.
function notifyUser(message) {
document.getElementById("msgArea").innerHTML = message;
runShowAnim();
}
I achieved this by sandwiching the YUI function completely inside a function and calling that function..
var runShowAnim = function() {
YUI().use('anim', 'node', function(Y) {
var animShow = new Y.Anim({
node: '#msgArea',
to: { height: 50,opacity:1 }
});
animShow.run();
});
};
now i can call runShowAnim without any problem like in the below sample function..
function notifyUser(message) {
document.getElementById("msgArea").innerHTML = message;
runShowAnim();
}
If you want to call a function, you have to suffix the function name with () and include 0 or more comma separated arguments between them.
runShowAnim();
If the function doesn't have global scope (as yours will have if it is declared inside a function passed to use()) and not passed outside in some way then you can only do this from the same scope.
I think you're missing the parentheses.
function notifyUser(message) {
document.getElementById("msgArea").innerHTML = message;
runShowAnim(); // right here
}
YUI.thefunction()?
I think you need to call it with namespace too
something similar to
var X = function(){};
X.Y = function(){};
X.Y.Z = function(){};
X.Y.Z.foo = function(e){alert(e);}
//foo("me");<-error
X.Y.Z.foo("me");
If you want to call a function that has been defined inside the closure (the function passed as the last parameter to YUI.use) from outside it, you need to expose the function globally.
Either define a global variable outside the closure and assign your function to it, or assign your function to the window object
i.e.
var runShowAnim;
YUI().use(function(e){
runShowAnim = function(){alert('called');}
});
runShowAnim();