From the RegExp.exec page on MDN, it gives the following example of iterating through a match with the g flag set:
const regex1 = RegExp('foo*', 'g');
const str1 = 'table football, foosball';
let array1;
while ((array1 = regex1.exec(str1)) !== null) {
console.log(`Found ${array1[0]}. Next starts at ${regex1.lastIndex}.`);
// expected output: "Found foo. Next starts at 9."
// expected output: "Found foo. Next starts at 19."
}
I have two questions about this code. The first one is why the !=== null is used here, why wouldn't the while loop be properly coded as:
while (array1 = regex1.exec(str1)) { // implicitly casts to boolean?
console.log(`...`);
}
The above seems much more readable to me, but was wondering why the MDN docs used the first approach? Second, is it possible to declare and define the variable directly in the while loop? Something like:
while (let array1 = regex1.exec(str1)) { // don't need the `let array1` above?
console.log(`...`);
}
Or is that not supported in the JS language?
Why the !== null is used here...?
True, in this case it is not needed. .exec() returns either an array or null, and since arrays are always truthy there is no need to explicitly compare with null.
Is it possible to declare and define the variable directly in the while loop?
No. If you want that, then turn to the for loop, which does support this:
for (let array1; array1 = regex1.exec(str1); null) {
console.log(`...`);
}
This does indeed have the advantage that array1 has a more restricted scope. NB: I provided null to stress that the third part of the for header is intentionally unused.
Say I want to have an if statement to test if an array is empty or not,
Looking it up I have found no way to check besides array[0], which in frameworks like React and Angular give errors on the array's item not existing.
let arr = [];
if (!arr[0]) {
arr.map(val=>{
return <div>{val.name}</div>
});
}
In this example I want it to Display the JSX and if not, do not display any JSX. But doing this throws an error. Is there anyway to do this? preferably without any outside libraries.
edit: "added 'this' after 'to do'"
This checks whether the variable is defined and whether it contains anything (although in this case you'd probably not need the first check):
if ( arr && arr.length )
Also, don't forget to return arr.map(...
If you're not even certain your variable even is an array, this is what I would do:
if (Array.isArray(arr) && arr.length) { /*...*/ }
For your special case you probably don't even need the 2nd check, though, because all of the Array iterators don't run even once if the Array they are called on is empty.
Example:
const arr = [];
console.log(arr.map(Number));
console.log(arr.some(parseInt));
console.log(arr.every(parseInt));
console.log(arr.filter(Number));
None of the methods will throw an error provide arr is an array.
I spent hours just to find out that I misspelt the word .length as .lenght. It can run normally with no warning at all. Why...?
I use 'use strict' and run on Node.js 10.13.0.
Code:
'use strict';
let arr = [1, 2, 3, 4];
for(let i = 0; i < arr.lenght; i++) {
console.log(arr[i]);
}
Because when you try to get a property that doesn't exist, it returns undefined, and 0 < undefined is false.
let arr = [1, 2, 3, 4];
console.log(arr.lenght) // undefined
console.log(arr.qwerty) // undefined
console.log(arr.lenght < 9999) // false
console.log(arr.lenght > 9999) // false
arr.length = 7 // <-- it's not a good idea
for(let i = 0; i < arr.length; i++) {console.log(arr[i])}
EDIT
I said 'javascript is not a strongly typed language' and it is true. But this way of adding new properties it is a feature of prototype-based programming, as #Voo said.
I also said .length=7 it's a bad idea. After reading a little more, in this case I still think it's a little weird to increase the length property after adding elements. Maybe it's fine to truncate, delete elements or empty an array, although in the latter case I would prefer arr=[] instead of arr.length=0.
There are some interesting examples about length property in the Mozilla documentation.
A JavaScript array's length property and numerical properties are
connected. Several of the built-in array methods (e.g., join(),
slice(), indexOf(), etc.) take into account the value of an array's
length property when they're called. Other methods (e.g., push(),
splice(), etc.) also result in updates to an array's length property.
var fruits = [];
fruits.push('banana', 'apple', 'peach');
console.log(fruits.length); // 3
When setting a property on a JavaScript array when the property is a
valid array index and that index is outside the current bounds of the
array, the engine will update the array's length property accordingly:
fruits[5] = 'mango';
console.log(fruits[5]); // 'mango'
console.log(Object.keys(fruits)); // ['0', '1', '2', '5']
console.log(fruits.length); // 6
Increasing the length.
fruits.length = 10;
console.log(Object.keys(fruits)); // ['0', '1', '2', '5']
console.log(fruits.length); // 10
Decreasing the length property does, however, delete elements.
fruits.length = 2;
console.log(Object.keys(fruits)); // ['0', '1']
console.log(fruits.length); // 2
JavaScript arrays are treated as objects (though they are instances of Array). Hence, when you write arr.lenght, it treats lenght as a property of an object that is undefined. Hence, you don't get an error.
It simply tries to get a property that is undefined. Also, in your case, the loop just does not execute as the condition of the loop is never satisfied.
Why
Standard JavaScript arrays aren't really arrays at all¹, they're objects, and if you read an object property that doesn't exist (like lenght), you get the value undefined (even in strict mode):
console.log(({}).foo); // undefined
When you use undefined in a relational operation like < or > with a number, it gets converted to a number, but the number value it gets is the special number NaN, which has the bizarre property of always causing comparisons to be false:
console.log(NaN < 0); // false
console.log(NaN > 0); // false
console.log(NaN === 0); // false
console.log(NaN === NaN); // false!!
What you can do about it
Linter tools will often pick these things up in simple cases.
Alternately, TypeScript provides a full static typing layer on top of JavaScript which can catch these sorts of errors.
If you wanted (and this would probably be overkill), you could wrap a Proxy around your objects that threw a proactive error when you tried to read a property that didn't exist:
function proactive(obj) {
return new Proxy(obj, {
get(target, propName, receiver) {
if (!Reflect.has(target, propName)) {
throw new TypeError(`Property '${propName}' not found on object`);
}
return Reflect.get(target, propName, receiver);
}
});
}
const a = proactive(["a", "b"]);
a.push("c");
for (let i = 0; i < a.length; ++i) {
console.log(a[i]);
}
console.log(`Length is: ${a.lenght}`); // Note the typo
.as-console-wrapper {
max-height: 100% !important;
}
There's a significant runtime penalty, though.
¹ (that's a post on my anemic little blog)
You could easily add new properties to arr object, JavaScript won't warn you about it, instead it will try to find the property you're calling, and if it didn't find anything such result will be undefined, so the comparison is actually i < undefined everytime because you're calling a property that hasn't been created on the object. I'll suggest you to read What does "use strict" do in JavaScript, and what is the reasoning behind it?.
The upper bound of the loop is specified as lenght, a typo for the local variable length. At runtime, lenght will evaluate to undefined, so the check 0 < undefined is false. Therefore the loop body is never executed.
By default, all objects in JavaScript are extensible, which means that you can add additional properties to them at any time simply by assigning a value to them.
Arrays are no different; they're simply objects that are instances of the Array type (at least for the purposes of extensibility).
In this case, had you added:
Object.preventExtensions(arr);
after creating the array, then in combination with 'use strict' this would have raised an error -- had you tried to write to a typo'd property. But for a read usage like this, there is still no error at all; you just get undefined.
This is just one of the things you have to live with in a loosely-typed language; with the added flexibility comes added risk of bugs if you're not careful.
I want to extract a value from a variable. If its an array, I want the first element, and if not, I want the value of that variable. The value is a float, but I was wondering which of these are better in terms of performance, portability to non-floats, and of course short code and code readability
I want to use
value = variable[0] || variable
Its short and nice, is there any caveats is using this?
or I can do,
value = ([].concat(variable))[0]
This SO question says it's bad for performance.
And then, ofcourse, I can check if variable is an array or not in a few different ways, that is also mentioned in above question. Is there any better ways if the first one is not good?
Your value = variable[0] || variable will work, and will work reliably. Technically, if variable is a number primitive, what the JS engine has to do at that point is promote it to an object and then look up the 0 property on that object, but as you know it won't have one, that's okay.
The only cases where that may fail are if variable is null or undefined, because neither of those can be promoted to an object, and so the expression will throw. Provided you're okay with that, then you can use that. I'd comment it, though, because it's pretty odd-looking.
If you needed to defend against null and undefined, you could use the fact that == null will filter out both of those:
value = variable == null ? undefined : variable[0] || variable;
I'd comment that, too. :-)
Having this
value = variable[0] || variable
you may go to a trouble if the first element of the array is false. For example:
var arr = [false, 1, 2, 3];
value = variable[0] || variable; // <--- value is [false, 1, 2, 3]
So, I'll go with this:
var value = arr instanceof Array ? arr[0] : arr;
If you are not sure if the array is full then you should add one more check.
var value = arr instanceof Array && arr.length > 0 ? arr[0] : arr;
I have a 2nd level array, that at a cetain point in the code can be ether undefined or contain value. If it is undefined I need to define it, without giving it any value.
this is what i did:
arr[arr2["stripID"]] = typeof(arr[arr2["stripID"]]) === 'undefined' ? [] : arr[arr2["stripID"]];
is there a better or shorter way?
arr[arr2["stripID"]] = arr[arr2["stripID"]] || [];
Should do what you want.
The || operator returns the first truthy value in the expression. Because an array is truthy, and the only other value it can be is undefined (falsy), this'll work fine.