ESLint throws no-undef even if variable is in IF statement - reactjs

I am using React and I am not able to build my application as long as I have undefined variable. I am using that variable only in IF statement (if it's defined, use it).
if (something)
const newItem = 'wow!';
if (typeof newItem === "undefined")
console.log('newItem undefined')
else
console.log(newItem); //ESLint: Line YY:XX: 'newItem' is not defined no-undef
How can I avoid this behavior?

An if statement creates a lexical scope. In fact, any time you see {} in javascript, that creates a scope. What that means is that variables declared with let or const in that scope cannot be accessed outside of that scope.
if (something) {
const newItem = 'wow!';
// newItem exists here
}
// newItem does not exist here
What you want to do is declare the variable in the scope where you want to access it, and then just assign to that variable in your if statement:
let newItem;
if (something) {
newItem = 'wow!';
}
// newItem exists here, and has a value of either 'wow!' or undefined.
Note that I had to change the variable declaration from const to let because we need to assign a value to the value after its creation, so it can no longer be a constant.

Related

TypeScript difference between any[] and [] when initialize data type

I used *ngIf to judge the array length in html
<div *ngIf="apps.length === 0">
and define the apps in .ts file
public apps: any[];
and apps was retrieved from the rest api data:
ngOnInit() {
const refSpinner = this._simsSpinnerService.showSpinner('my-apps-spinner');
const getMyApps = this._myAppsService.getMyApps().pipe(share(), finalize(() => { this._simsSpinnerService.stopSpinner(refSpinner); }))
this._subscriptions.push(getMyApps.subscribe({
next: (data) => {
if (data && data instanceof Array) {
debugger
this.apps = data;
}
},
error: (err) => MessageService.addError(err)
}));
}
The console will print error message:
ERROR TypeError: Cannot read properties of undefined (reading 'length')
at MyAppsComponent_Template (my-apps.component.html:13:30)
I add debugger and found the this.apps is undefined before the data was assigned to it.
Then I changed the way to init data type like:
public apps = [];
And the error was disappeared, found that this.apps is an array before the data was assigned to it.
I searched and found that
any[] is an array where the item is of type any.
But why is it undefined? Shouldn't it be a array of any elements in it?
I believe this is because the original code used a declaration, while the update code has initialization.
Declaration
Declaration tells the compiler the variable name and type. It does not give the variable a value (or rather, it gives it undefined). In other words, it declares what the variable is.
public apps: any[]; // apps = undefined
Initialization
To actually give the variable a value other than undefined, we have to initialize it.
public apps = []; // apps = []
The compiler can then infer the type of the variable apps, which is, in this case, Array<any>
This alone isn't enough to explain why the compiler errors, however. Because you can keep a variable uninitialized as long as you give it a value later. However, you attempt to read the variable's length with <div *ngIf="apps.length === 0">, which results in an error (as undefined has no property length)

How does "arguments" keyword work in Javascript?

I came across this little exercise and I am not really sure how the "arguments" keyword works here and also why (...arr) is placed where it is as it is outside of the a's declaration parentheses...
var arr = ["tic", "tac", "toe"];
var a = (
function() {
return arguments[2];
}
)(...arr);
console.log(a);
Could you please explain or point me to a relevant source as I am not sure what I am actually looking for? Thank you.
arguments is the array of arguments passed to the current function. In the above code example, the function within the parentheses is being called with ...args as the arguments.
In JS, you need not name a function to call it. The above code is equivalent to the following:
var arr = ["tic", "tac", "toe"];
var callme = function() {
return arguments[2];
}
var a = callme(...arr);
console.log(a);
The arguments in the function call are being passed with "spread syntax."
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
So the function is being called with the values of arr as it's arguments, and is returning the third argument arguments[2].

Variable becoming undefined in Promise function

I have an array (targets) in global scope, the values of which I am passing to an external function [third party library, externalConverter] that does some text conversion. The values of this array are being passed in to the convert function and the conversion is happening fine.
const targets = [‘box’, ’box1’, ’box2’, ’box3’]
for (var i = 0; i < targets.length; ++i) {
console.log(targets[i]); // this is coming out fine
externalConverter
.convert(data.text, targets[I])
.then(results => {
data.convertedText.push({
[targets[i]]: results[0]
});
//above convertedText array comes out as
//{“undefined: ”, “nice converted text”}, ...
})
}
Inside the result of the Promise, I am trying to access the targets values but getting undefined values inside the function above. I am not sure why targets is suddenly becoming undefined
Any ideas?
The value of i will have progressed to its final value (i.e. targets.length) before any of the then callbacks have executed, and so any use of i as index will be out of range.
Use let i instead of var i to make separate instances of i that will not have this problem.

Confused about how to use mutating

I have a simple struct called Card...
struct Card {
var order: Int? = -1
var data : [String: String]
var original : String?
And a collection object called Deck that looks like...
struct Deck {
var cards : [Card]
Deck has the reading and writing methods, which basically boils down to splitting up strings read in from a text file, and then pushing it bit by bit into the previous empty data. Here's an example...
mutating func parseGRCard(var c: Card) {
c.data["I1"] = c.original![2...4].trim()
c.data["I2"] = c.original![5...9].trim()
}
To read the file, I get each line, make a Card, and then call the parse methods on it...
let nc = Card(order: i, original: c)
parseGRCard(nc)
cards.append(nc)
When I step through this func, I see that mc's original has the expected data, the original line from the text file. I then watch parseGRCard read it and add the items to data, which now has two items. But when when it returns and nc is appended, data is empty.
I thought mutating was supposed to handle these things, but apparently I'm missing something fundamental here.
I changed your code a bit to make it compile and make it more illustrative.
append is mutating because it mutates cards.
It's parameter c is an inout parameter so that the passed Card is passed back after the function. Since Structs are value types and not reference types a new copy is actually passed to the function. This behaviour has nothing to do with the function being a mutating function.
struct Card {
var placeInDeck: Int = 0
}
struct Deck {
var cards : [Card] = []
mutating func append(inout c: Card) {
c.placeInDeck = cards.count
cards.append(c)
}
}
var cardZero = Card()
var cardOne = Card()
var deck = Deck()
deck.append(&cardZero)
deck.append(&cardOne)
cardZero.placeInDeck // 0
cardOne.placeInDeck // 1
In this case the function is not mutating because no properties from Deck are altered. The c parameter is a variable which just makes it mutable inside the scope from the function. Beware, this will be removed from Swift. When the function ends, this mutable copy of Card will not update it's original instance outside the scope of the function. The updated Card will not persist.
struct Card {
var placeInDeck: Int = 0
}
struct Deck {
var cards : [Card] = []
func updateCount(var c: Card) {
c.placeInDeck = 1
}
}
var cardZero = Card()
var cardOne = Card()
var deck = Deck()
deck.updateCount(cardZero)
deck.updateCount(cardOne)
cardZero.placeInDeck // 0
cardOne.placeInDeck // 0
From Apple's documentation methods, we can read the following regarding the mutable keyword:
However, if you need to modify the properties of your structure or
enumeration within a particular method, you can opt in to mutating
behavior for that method. The method can then mutate (that is, change)
its properties from within the method, and any changes that it makes
are written back to the original structure when the method ends.
I agree that it is could be possible to interpret the bold-marked part as as "the properties of the method, i.e., it's parameters?". From your example above, it would seem as if you have done this interpretation.
But the mutable keyword only tells us that the associated function is allowed to change (mutate) variable member values of the struct (in this case) that owns the method.
struct SingleIntegerValueStruct1 {
var myInt = 1
func LetsTryToMutateTheInteger () {
myInt += 1 // compile time error; myInt immutable
}
}
Whereas if we use the mutating keyword
struct SingleIntegerValueStruct {
var myInt = 0
mutating func LetsTryToMutateTheInteger () {
myInt += 1 // ok, mutating function
}
}
var a = SingleIntegerValueStruct(myInt: 1)
print("\(a.myInt)") // 1
a.LetsTryToMutateTheInteger()
print("\(a.myInt)") // 2
However, a struct type is and will always be a value type. So when when a struct type is passed to any function, the function will not be able to mutate the caller parameter, as it is only given a copy of it.
let nc = Card(order: i, original: c)
parseGRCard(nc) // passes _copy_ of struct typ nc to parseGRCard
cards.append(nc) // nc in this scope is stil unchanged
For wanting to use a "stand-alone" function that could mutate its input parameter, where the input is a struct, you could, as discussed in the comments, us the inout keyword on the function parameter.
We extend our example from above to include such a case:
struct SingleIntegerValueStruct {
var myInt = 0
mutating func LetsTryToMutateTheInteger () {
myInt += 1 // ok, mutating function
}
}
// "b" here is a _copy_ of "a" (in parameter), and the function
// thereafter returns a _copy_ of "b" (with state of "b" as its
// final state in the function)
func standAloneInOutFunction(inout b: SingleIntegerValueStruct) {
b.LetsTryToMutateTheInteger()
}
var a = SingleIntegerValueStruct(myInt: 1)
print("\(a.myInt)") // 1
a.LetsTryToMutateTheInteger()
print("\(a.myInt)") // 2
standAloneInOutFunction(&a)
// value copy a->b, modify(b), value copy back b->a
print("\(a.myInt)") // 3
Note however that the inout keyword does not mean that we pass by reference (as for class instances), but we simply send a value copy in and takes another value copy back, that we finally assigns to the original value type calling parameter (a).
From the Apple documentation on this keyword:
... An in-out parameter has a value that is passed in to the function,
is modified by the function, and is passed back out of the function to
replace the original value.

How to access global variable in function hook in javascript?

I want to use global variable 'x' in the below hook funcion.
var x = 10; //global variable
var oldA = a;
a = function a(param){
alert(x); //showing error: x is undefined
return oldA(param);
}
How to resolve the error?
Your code works fine for me, but you might want to resolve x to the global variable explicitly by using window.x.
When not in a browser environment, or an environment where the global object isn't called window, try:
(window || root || global || GLOBAL || this || self || {x: undefined}).x
The {x:undefined} object literal is just to make sure the expression doesn't throw up errors.I've listed pretty much all names I know of that are given to the (strictly speaking nameless) global object, just use the ones that might apply to your case.
On the other hand, if the global variable x might be reassigned by the time the function (a) gets called, a closure would be preferable:
a = (function (globalX)
{
return function a(param)
{
console.log(globalX);
return oldA(param);
};
}(x || window.x));//pass reference to x, or window.x if x is undefined to the scope
Of course, if you're in strict mode, you need to be careful with implied globals, too.
That's all I can think of that is going wrong with your code, some more details might provide us with a clue of what's actually happening...
To access global Js variable inside function, don't use Var in function scope and mention var in global scope.
Eg.
<script>
var foo = "hello";
function fxn() {
alert(foo);
foo = "bai";
}
fxn();
alert(foo+"out side");
</script>

Resources