Reputation: 87
I dont get why this function's console.log returns the value, and the typeof correctly, but its return value is invalid to use in another function
I'm attempting to use bubble event to collect the value of the clicked button.
<DIV class = "keys">
<button class = "key" id = "rock" value = "rock">Rock</button>
<button class = "key" id = "paper" value = "paper">Paper</button>
<button class = "key" id = "scissors" value = "scissors">Scissors</button>
</DIV>
Here is the JS:
const bubbleBar = document.querySelector(".keys");
bubbleBar.addEventListener("click", playerPlay);
bubbleBar.addEventListener("click", display);
function playerPlay(e){
let playerChoice = ""
console.log(e.target.value); //debugs correctly
playerChoice = e.target.value;
console.log(playerChoice, typeof playerChoice); //debugs correctly
return playerChoice; // apparently returns nothing
}
function display(){
console.log(playerPlay) // displays function playerPlay(e), not the result of the first function.
}
Upvotes: 2
Views: 2860
Reputation: 3230
Nested scopes can often be confusing, and where things return to isn't always clear. Here's some examples fo reference:
function simple(){ return 'foo' }
Returns "foo"
when simple
is called like simple()
(or simple("args", "aren't", "used", "but still are passed")
or simple.call()
)
function nested(){
return function inner(){
return 'foo'
}
}
nested
, when called, returns a function, but that function does not run immediately. so to get "foo"
you would need to call it like this:
let outerResult = nested() // creates and returns a function
outerResult() // returns "foo"
//or more concisely
nested()() // calls both functions in order.
Here we see that return
is always going to return to the function it is "closest" too, the inner-most function. return
can't skip out of the function it is in.
function loop(){
let values = [1,2,3]
for (let value of values){
return value
}
}
Returns 1
, and the loop does not run another time. So in this case the block does not change the scope of return.
function callbackLoop(){
let values = [1,2,3]
values.forEach(value => { return value })
}
This code has a bug. You might expect that this code would work the same as the regular loop, but it doesn't, and in fact, it can't. There is no way for the return in the function value => { return value }
to cause the callbackLoop
function to return. It can only return itself, same as the nested
example. Sometimes functions that take callbacks will pass along the callback return value, but they don't have to if they don't want to. Since forEach
is designed for side effects (functions that don't have return values) it doesn't do this, and neither does addEventListener
, because it also is designed for side effects.
An example of a function that takes a "pure function" callback, instead of side effects, is Array.prototype.map
:
const result = [1, 4, 9, 16].map(x => {return x * 2});
// `map` returns: [2, 8, 18, 32]
// (it gets the return value of the callback function for
// each item in the array, and uses that)
A "pure function" is a function that operates on only the inputs (x
) in this case, and makes no changes to any variables. Multiplication "creates" a new value, and that is what is returned. The original x
is not "mutated" (it is left unchanged). In order for pure functions to be useful, they need to return a value, and that value needs to be used in some way.
Upvotes: 0
Reputation: 14800
As stated in comments, returning a value from an event handler doesn't do anything with that value. The value is used to determine further event processing.
If you want the value you will have to store it somewhere from within the handler.
This code saves the value in a global variable chosenValue
and also sets the value as the text within a <span>
— what you actually do to store the value will depend on how you plan to make use of the value later.
let chosenValue;
const bubbleBar = document.querySelector(".keys");
bubbleBar.addEventListener("click", playerPlay);
bubbleBar.addEventListener("click", display);
function playerPlay(e) {
e.preventDefault();
let playerChoice = ""
console.log(e.target.value); //debugs correctly
playerChoice = e.target.value;
console.log(playerChoice, typeof playerChoice); //debugs correctly
document.getElementById('playerChoice').innerText = playerChoice;
chosenValue = playerChoice;
console.log(`chosenValue variable value is now ${chosenValue}`);
}
function display(e) {
e.preventDefault();
console.log(e.target.value);
}
<div class="keys">
<button class="key" id="rock" value="rock">Rock</button>
<button class="key" id="paper" value="paper">Paper</button>
<button class="key" id="scissors" value="scissors">Scissors</button>
</div>
<div>
Player's Choice: <span id="playerChoice">none</span>
</div>
Upvotes: 2