Scope at let to a if statement - javascript

Lots of times I am needing to delcare a variable just for a truthy if statement.
For example:
let entry;
entry = entries.find(....);
if (entry) {
// use entry
}
// i dont need entry here
I tried combintations similar to for (let i=0; ...) like this:
if (let entry = entries.find(....)) {
// user entry
}
But it's not working. If I use var instead of let it works but the variable it hoisted so its not limited to that if statement block.

Since let creates a block scope, you need to create another block around it to limit its scope.
A block statement is used to group zero or more statements. The block is delimited by a pair of curly brackets.
let x = 1;
{
let x = 2;
}
console.log(x); // logs 1
Alternatively you can use an Immediately Invoked Function Expression:
(function () {
let entry = 6;
if (entry) {
console.log(entry);
}
})()
// Variable entry is not accessible from the outside scope

This is probably an idiom that was never made for JS, but just for kicks, here's a helper that could be used, although the other answer is probably more correct.
This was inspired by Clojure's when-let that does exactly what you're looking for, but doesn't require a function since it's a macro:
function ifDo (maybeTrueVal, doF) {
if (maybeTrueVal) {
doF(maybeTrueVal);
}
}
ifDo(entries.find(....), (truthyVal) => {
console.log(truthyVal);
});

Related

JS Hint: Functions declared within loops & The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype

I was looking for some help in understanding and improving code on some feedback I'm receiving from JSHINT when I run my JavaScript through it I get these errors:
Functions declared within loops referencing an outer scoped variable may lead to confusing semantics. (foodIndex, i, basketItem, addItemToBasket, food)
for this code -
addToBasket[i].addEventListener("click", e => {
foodIndex = i;
if (!basketItem.includes(foodIndex)) {
basketItem.push(foodIndex);
addItemToBasket(food[i], i);
} else {
return;
}
});
}
Then I get the above warning and:
The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.
for code:
// show previously stored basket data
let storedBasketItems = JSON.parse(localStorage.getItem("foodInBasket")) || {};
for (const key in storedBasketItems) {
// get corresponding food index
food.forEach(function (food, i) {
if (food.name === storedBasketItems[key].name) foodIndex = i;
});
if (!basketItem.includes(foodIndex)) {
basketItem.push(foodIndex);
food[foodIndex].inBasket = storedBasketItems[key].inBasket;
updateModal(foodIndex);
}
}
Full example of code here
Thanks
It's telling you that this:
for (const key in storedBasketItems) {
// ...
should be
for (const key in storedBasketItems) {
if (storedBasketItems.hasOwnProperty(key)) {
// ...
and that if you use var to declare variables, that it has problems inside loops because var is function-scoped, not block-scoped. (But you look to be using const and let, so this isn't a problem; this is a false positive by JSHint.)
Another way to avoid the in warning is to iterate over the Object.entries of the object instead:
for (const [key, value] of Object.entries(storedBasketItems)) {
// do stuff with key and value
}
You could also avoid the scope warning by using loops instead of forEach callbacks, eg, change:
food.forEach(function (food, i) {
to
for (const [i, food] of food.entries()) {
You could also look into ESLint, which I personally find to be significantly more useful than JSHint when improving code quality.

JavaScript arrow function to count time it gets called but does not take any parameter

I receive a challenge to create a function (arrow function) that count the times it gets called or invoked. BUT, this function can't take any parameter or interact with outside scope likes the normal way below.
Normal way:
var count = 0;
var countTimesCalled = (count) => {
count+=1;
return count;
}
console.log(countTimesCalled(count))
Is it possible to have created a function that does not take any parameter and not interact with outside scope to count the times it gets called? Where to store the times (var count) on runtime and after runtime?
Please help!
Use an IIFE to hold the count variable in a local scope:
var countTimesCalled = (() => {
var count = 0;
return () => ++count;
})();
console.log(countTimesCalled());
console.log(countTimesCalled());
console.log(countTimesCalled());
not interact with outside scope
That is not possible, but you could do something that looks kind of like it does that:
var countTimesCalled = (count => _ => ++count)(0);
console.log(countTimesCalled());
console.log(countTimesCalled());
console.log(countTimesCalled());
In reality there are two arrow functions there, an outer one to hold the count variable that is called once, and an inner one that is returned and referenced by countTimesCalled. That inner one is interacting with a scope outside of itself, but only as far out as the outer arrow function.
You could use .bind to capture state, if you really wanted to avoid accessing another closure scope entirely, e.g.
var countTimesCalled = function() {
return this.counter++
}.bind({ counter: 1 });
Set an attribute to the function, i.e: countTimesCalled.i
var countTimesCalled = () => (countTimesCalled.i = (countTimesCalled.i || 0) + 1);
console.log(countTimesCalled())
console.log(countTimesCalled())
console.log(countTimesCalled())

Table data is not appending when in a function

Whenever I write my code iteratively the program runs as it is supposed to, but when I place in a function like this it breaks.
function create_tableElements() {
Let myArticle = document.createElement(‘tr’);
Let rank = document.createElement(‘td’);
}
function assign_tableElements() {
Let count = 1
rank1 = count;
rank.textContent = rank1;
heroes_name.textContent = heroes[i].name;
}
function append_tableElements() {
myArticle.appendChild(rank);
myArticle.appendChild(heroes_name);
}
Does anyone know why this may happen? Is there a way for me to call a function within a function? I am using a for loop to loop through JSON. Now if I do not place in a function and just write the code, it will run perfectly fine. Just working on readability, and organizing my code better
There's a couple issues with the code you pasted (Let instead of let or the fancy single quotes).
I'm going to assume your phone or whatever tool you used corrected it. So let's say this is your code :
function create_tableElements() {
let myArticle = document.createElement('tr');
let rank = document.createElement('td');
}
function assign_tableElements() {
let count = 1;
rank1 = count;
rank.textContent = rank1;
heroes_name.textContent = heroes[i].name;
}
function append_tableElements() {
myArticle.appendChild(rank);
myArticle.appendChild(heroes_name);
}
Your code can't work because :
the rank variable is local to the create_tableElements function and can't be accessed by the append_tableElements function
same goes for the heroes_name function, it's local to the assign_tableElements function
You can fix this by :
either declaring these variables as global variables, outside of any function. It's not really a best practice, though.
change your function's definition so that they can access the same local variables : do you really need a function to create elements and another to append them to the DOM?
you could also use an Immediately Invoked Function Expression.
(function() {
// these variables will be visible to all the functions defined in this function, but won't be global :
let rank, myArticle, heroes_name;
function create_tableElements() {
myArticle = document.createElement('tr');
rank = document.createElement('td');
}
function assign_tableElements() {
let count = 1;
rank1 = count;
rank.textContent = rank1;
heroes_name.textContent = heroes[i].name;
}
function append_tableElements() {
myArticle.appendChild(rank);
myArticle.appendChild(heroes_name);
}
// invoking your functions :
create_tableElements();
assign_tableElements();
append_tableElements();
})();

How do I make this into a self-invoking function?

I'm not sure how to make this function into a self-invoking function. My code is looping through an array of zip codes from a JS file and sorting it from smallest to biggest and outputting it. I've found online that adding "())" at the end of the newZipCodeArray function, is supposed to self-invoke the function. However, it's not working. What am I doing wrong?
[enter image description here][1]
// Global variable
var zipCodeArray = [];
(function newZipCodeArray(currentZipCode) {
var valueFound = false;
for (zipCodeIndex = 0; zipCodeIndex <= zipCodeArray.length; zipCodeIndex++) {
if (currentZipCode === zipCodeArray[zipCodeIndex]) {
valueFound = true;
}
}
if (valueFound === false) {
zipCodeArray.push(currentZipCode);
}
}());
function newZipCodeArrayssignment12_3() {
// Instantiate variables.
var output;
var zipCodeRecords;
// Get the element.
output = document.getElementById('outputDiv');
zipCodeRecords = openZipCodeStudyRecordSet();
// Call the function to read the next record.
while (zipCodeRecords.readNextRecord()) {
currentZipCode = zipCodeRecords.getSampleZipCode();
newZipCodeArray(currentZipCode);
}
// Sort the zip code array.
zipCodeArray.sort();
}
The syntax involved in immediately-invoked (or self-invoked) functions doesn't allow it to be invoked from elsewhere. The IIFE pattern is intended to be used when the function only needs to be invoked once.
Note:
The grouping parenthesis wrapping the function change it from a declaration to an expression. And, as an expression, its name won't be added to the surrounding scope for other code to reference.
To invoke newZipCodeArray once right away and allow for it again later, you'll want to remove the parenthesis from around it and call it by name in a separate statement:
newZipCodeArray(); // first call
function newZipCodeArray(currentZipCode) {
// ...
}
function newZipCodeArrayssignment12_3() {
// ...
while (zipCodeRecords.readNextRecord()) {
// ...
newZipCodeArray(currentZipCode); // additional calls
}
// ...
}

Javascript Closures and self-executing anonymous functions

I was asked the below question during an interview, and I still couldn't get my head around it, so I'd like to seek your advice.
Here's the question:
var countFunctions = [];
for(var i = 0; i < 3; i++){
countFunctions[i] = function() {
document.getElementById('someId').innerHTML = 'count' + i;
};
}
//The below are executed in turns:
countFunctions[0]();
countFunctions[1]();
countFunctions[2]();
When asked what would be the output of the above, I said count0,count1 and count2 respectively. Apparently the answer was wrong, and that the output should all be count3, because of the concept of closures (which I wasn't aware of then). So I went through this article and realized that I should be using closure to make this work, like:
var countFunctions = [];
function setInner(i) {
return function(){
document.getElementById('someId').innerHTML = 'count' + i;
};
}
for(var i = 0; i < 3; i++){
countFunctions[i] = setInner(i);
}
//Now the output is what was intended:
countFunctions[0]();//count0
countFunctions[1]();//count1
countFunctions[2]();//count2
Now that's all well and good, but I remember the interviewer using something simpler, using a self-executing function like this:
var countFunctions = [];
for(var i = 0; i < 3; i++) {
countFunctions[i] = (function(){
document.getElementById('someId').innerHTML = 'count' + i;
})(i);
}
The way I understand the above code, we are skipping the declaration of a separate function and simply calling and executing the function within the for loop.
But when I ran the below:
countFunctions[0];
countFunctions[1];
countFunctions[2];
It didn't work, with all the output being stuck at count2.
So I tried to do the below instead:
for(var i = 0; i < 3; i++) {
countFunctions[i] = function(){
document.getElementById('someId').innerHTML = 'count' + i;
};
}
, and then running countFunctions[0](), countFunctions[1]() and countFunctions[2](), but it didn't work. The output is now being stuck at count3.
Now I really don't get it. I was simply using the same line of code as setInner(). So I don't see why this doesn't work. As a matter of fact, I could have just stick to the setInner kind of code structure, which does work, and is more comprehensive. But then I'd really like to know how the interviewer did it, so as to understand this topic a little better.
The relevant articles to read here are JavaScript closure inside loops – simple practical example and http://benalman.com/news/2010/11/immediately-invoked-function-expression/ (though you seem to have understood IEFEs quite well - as you say, they're "skipping the declaration of a separate function and simply calling and executing the function").
What you didn't notice is that setInner does, when called, return the closure function:
function setInner(i) {
return function() {
document.getElementById('someId').innerHTML = 'count' + i;
};
}
// then do
var countFunction = setInner("N"); // get the function
countFunction(); // call it to assign the innerHTML
So if you translate it into an IEFE, you still need to create (and return) the function that will actually get assigned to countFunctions[i]:
var countFunctions = [];
for(var i = 0; i < 3; i++) {
countFunctions[i] = (function(i){
return function() {
document.getElementById('someId').innerHTML = 'count' + i;
};
})(i);
}
Now, typeof countFunctions[0] will be "function", not "undefined" as in your code, and you can actually call them.
Take a look at these four functions:
var argument = 'G'; //global
function passArgument(argument){
alert(argument); //local
}
function noArguments(){
alert(argument); //global
}
function createClosure_1(argument){
return function (){
alert(argument); //local
};
}
function createClosure_2(argument){
var argument = argument; //local
return function (){
alert(argument); //local
};
}
passArgument('L'); //L
noArguments(); //G
createClosure_1('L') //L
createClosure_2('L') //L
alert(argument) //G
I think, first function is obvious.
In function noArguments you reference the global argument value;
The third and fourth functions do the same thing. They create a local argument variable that doesn't change inside them and return a function that references that local variable.
So, what was in the first and the last code snippet of your question is a creation of many functions like noArguments,
that reference global variable i.
In the second snippet your setInner works like createClosure_1. Within your loop you create three closures, three local variables inside them. And when you call functions inside countFunctions, they get the value of the local variable that was created inside the closure when they were created.
In the third one you assign the result of the execution of those functions to array elements, which is undefined because they don't return anything from that functions.

Categories

Resources