Why doesn't the spread operator add properties to my array? - javascript

I'm working with a React useState variable. I have an array of objects that has 18 objects at this top level. I'm trying to update the object at the 14th index and then return the remaining objects after it. At first I was directly mutating the state by pushing my changes to it like so:
setFormWizard(wizard => {
wizard.controls[14].trash = true;
return ({
...wizard,
wizard: wizard.controls[14].group.push(...newSection.slice(0, 5)),
});
});
This works, but I'm told this isn't good practice because React may not catch the update if you push directly to the state in certain cases. So now I'm trying to use the spread operator instead.
What's happening is the first 14 objects are returning. The object I'm modifying is returning, but the rest of the objects that come after the 14th index are not returning. What am I doing wrong?
setFormWizard(wizard => {
const subjectControls = wizard.controls[14]
const groups = [...controls.group, ...subjectAddressCopy.slice(0, 5)]
return ({
...wizard,
controls: [
...wizard.controls.splice(0,14), // keep first 14 entries
{
...subjectControls,
group: groups,
trash: true
} // modify the 15th entry
...wizard.controls.splice(15) // this doesn't return the remaining controls
],
});
});

bcz splice changes in actual array you need to use slice
const arr = [1, 2, 3, 4]
arr.splice(0,2)
console.log('splice change in array so actual value of arr is :', arr)
const arr1 = [1,2,3,4,5]
// it will take slice(start, end) but end not included in return value
const cutSection = arr1.slice(1, 3);
console.log('portion of array', cutSection)

You might've wanted to use slice to return everything upwards from index 15.

Related

How can i understand this topic better, to be a better Programmer

i have a Question. I was thinking long Time about it, but poorly i don´t find a answer.
I know the every method.
My Question is about this code section:
var tr = order.every((i) => stock[i[0]] >= i[1]);
My Questions are:
stock is an Object. Why i must write as an array?
Why it is i[0] in stock and then i[1] ?
Why this code checks the nested Arrays in const order ?
const order = [
["shirt", 5],
["shoes", 2]
];
const stock = {
shirt: 50,
height: 172,
mass: 120,
shoes: 6
};
var tr = order.every((i) => stock[i[0]] >= i[1]); /// return true
console.log(`tr:`,tr)
So, the square brackets can be used to access element inside the array by passing it's index e.g:
const arr = ["first", "second"];
const secondElement = arr[1] // index 1 means seconds element
and also square brackets can be used to access element inside the object by passing it's key e.g:
const obj = { first: 1, second: 2 };
const secondElement = object.second // Normal way to access value in object
const secondElementWithAnotherSyntax = object['second'] // another syntax, same thing
the cool thing about the other syntax shown is that you can pass variable to it, e.g :
const objKey = 'second'
const secondElement = obj[objKey]
Now let's look at your example, i is one element of the array order, which carries arrays itself, so i is also one of the two small arrays, i[0] is the string word in the beginning of the small arrays, so:
i[0] // is either 'shirt' or 'shoes'
and since stocks is an object that has those keys, you can access for example the value 50 by saying stocks['shirt'] or as in your case, stock[i[0]] ;)
now your second question: why should it be >= i[1] ?
because the order second item , aka i[1] is the number of items required/ordered, so this should always be less that your stock, you can't by 5 shirts from a place that has only 3 in the stock :)
1. stock is an Object. Why i must write as an array?
You can access properties of objects using brackets [].
Why do we need this?
To be able to access properties of objects dynamically, e.g. when you are looping though keys and want to get the values
Object.keys(data).forEach(function(key) {
console.log('Key : ' + key + ', Value : ' + data[key])
})
Sometimes there is no other way to access the value:
const json = {
"id":"1",
"some key with spaces": "48593"
};
console.log(json.some key with spaces); // obviously throws error
console.log(json['some key with spaces']); // prints "48593"
2. Why it is i[0] in stock and then i[1] ?
3. Why this code checks the nested Arrays in const order ?
The code goes through the orders, each order is an array so i[0] is the type of the order and i[1] is the quantity. the code checks if there are enough items in stock. To check if there are enough shirts you would do:
console.log(stock["shirts"] >= 5
Thats what the code in your example does, it just passes the key ("shirts") and quantity (5) dynamically.
May I suggest to try to use more expressive naming of the variables ?
An object property can be accessed through bracket notation, as in stock[orderedProductName] when using a variable - Property accessors
A concise but imho more readable version can be written using destructuring assignment
const order = [
["shirt", 5],
["shoes", 2]
];
const stock = {
shirt: 50,
height: 172,
mass: 120,
shoes: 6,
};
// original version
let inStock = order.every((i) => stock[i[0]] >= i[1]); /// return true
// more verbose version
// check if every item in array order satisfies the condition
// let's cycle over the array calling the element we're working on
// orderItem
inStock = order.every( orderItem => {
const orderedProductName = orderItem[0];
const orderedProductQuantity = orderItem[1];
// to access an object property we can use bracket notation
const stockProductQuantity = stock[orderedProductName];
// the condition to check: do we have enough products in stock ?
return stockProductQuantity >= orderedProductQuantity;
});
// a concise variation could make use of destructuring assignment.
// Here, when we take the order item array, we immediately assign
// each of its elements to the appropriate variable
//
// orderItem[0] or first array element -> productName
// orderItem[1] or second array element -> orderedQuantity
inStock = order.every(([productName, orderedQuantity]) =>
stock[productName] >= orderedQuantity
);
if(inStock) {
console.log('pack and ship');
}
else {
console.log('need to restock');
}
The every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value. If you want to read more Array.prototype.every()
In your code snippet you are checking that every item in order array has quantity less than the quantity available in stock.
To access the properties of a object you can use square notation also like arrays. To read more Bracket Notation
If you assigned more meaningful variables to the code you'd probably understand how this works better.
In one order (an array) we have two nested arrays. The first describes shirt/value, the other shoes/value. every is going to see if there is enough stock for both shirt and shoes by checking that the stockValue >= the items in the order.
When you every over the order array the callback for each iteration is one orderItem (['shirt', 5] first, then ['shoes', 2] for the second). We can assign the first element of each array to a variable called itemType, and the second to a variable called itemQty.
So when you see stock[i][0] we can translate that in the new code as stock[orderType] which is using bracket notation to locate the property value associated by that key in the stock object. We then check to see if that value >= than the itemQty.
const order=[["shirt",5],["shoes",2]],stock={shirt:50,height:172,mass:120,shoes:6};
const result = order.every(orderItem => {
const itemType = orderItem[0];
const itemQty = orderItem[1];
return stock[itemType] >= itemQty;
});
console.log(result);

jQuery DataTable not working filter with negative index [duplicate]

Here is my JavaScript code so far:
var linkElement = document.getElementById("BackButton");
var loc_array = document.location.href.split('/');
var newT = document.createTextNode(unescape(capWords(loc_array[loc_array.length-2])));
linkElement.appendChild(newT);
Currently it takes the second to last item in the array from the URL. However, I want to do a check for the last item in the array to be "index.html" and if so, grab the third to last item instead.
if (loc_array[loc_array.length - 1] === 'index.html') {
// do something
} else {
// something else
}
In the event that your server serves the same file for "index.html" and "inDEX.htML" you can also use: .toLowerCase().
Though, you might want to consider doing this server-side if possible: it will be cleaner and work for people without JS.
EDIT - ES-2022
Using ES-2022 Array.at(), the above may be written like this:
if (loc_array.at(-1) === 'index.html') {
// do something
} else {
// something else
}
Not sure if there's a drawback, but this seems quite concise:
arr.slice(-1)[0]
or
arr.slice(-1).pop()
Both will return undefined if the array is empty.
Use Array.pop:
var lastItem = anArray.pop();
Important : This returns the last element and removes it from the array
A shorter version of what #chaiguy posted:
Array.prototype.last = function() {
return this[this.length - 1];
}
Reading the -1 index returns undefined already.
EDIT:
These days the preference seems to be using modules and to avoid touching the prototype or using a global namespace.
export function last(array) {
return array[array.length - 1];
}
Two options are:
var last = arr[arr.length - 1]
or
var last = arr.slice(-1)[0]
The former is faster, but the latter looks nicer
http://jsperf.com/slice-vs-length-1-arr
Performance
Today 2020.05.16 I perform tests of chosen solutions on Chrome v81.0, Safari v13.1 and Firefox v76.0 on MacOs High Sierra v10.13.6
Conclusions
arr[arr.length-1] (D) is recommended as fastest cross-browser solution
mutable solution arr.pop() (A) and immutable _.last(arr) (L) are fast
solutions I, J are slow for long strings
solutions H, K (jQuery) are slowest on all browsers
Details
I test two cases for solutions:
mutable: A,
B,
C,
immutable: D,
E,
F,
G,
H,
I,
J (my),
immutable from external libraries: K,
L,
M,
for two cases
short string - 10 characters - you can run test HERE
long string - 1M characters - you can run test HERE
function A(arr) {
return arr.pop();
}
function B(arr) {
return arr.splice(-1,1);
}
function C(arr) {
return arr.reverse()[0]
}
function D(arr) {
return arr[arr.length - 1];
}
function E(arr) {
return arr.slice(-1)[0] ;
}
function F(arr) {
let [last] = arr.slice(-1);
return last;
}
function G(arr) {
return arr.slice(-1).pop();
}
function H(arr) {
return [...arr].pop();
}
function I(arr) {
return arr.reduceRight(a => a);
}
function J(arr) {
return arr.find((e,i,a)=> a.length==i+1);
}
function K(arr) {
return $(arr).get(-1);
}
function L(arr) {
return _.last(arr);
}
function M(arr) {
return _.nth(arr, -1);
}
// ----------
// TEST
// ----------
let loc_array=["domain","a","b","c","d","e","f","g","h","file"];
log = (f)=> console.log(`${f.name}: ${f([...loc_array])}`);
[A,B,C,D,E,F,G,H,I,J,K,L,M].forEach(f=> log(f));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js" integrity="sha256-VeNaFBVDhoX3H+gJ37DpT/nTuZTdjYro9yBruHjVmoQ=" crossorigin="anonymous"></script>
Example results for Chrome for short string
Here's how to get it with no effect on the original ARRAY
a = [1,2,5,6,1,874,98,"abc"];
a.length; //returns 8 elements
If you use pop(), it will modify your array
a.pop(); // will return "abc" AND REMOVES IT from the array
a.length; // returns 7
But you can use this so it has no effect on the original array:
a.slice(-1).pop(); // will return "abc" won't do modify the array
// because slice creates a new array object
a.length; // returns 8; no modification and you've got you last element
Getting the last item is possible via the length property. Since the array count starts at 0, you can pick the last item by referencing the array.length - 1 item
const arr = [1,2,3,4];
const last = arr[arr.length - 1];
console.log(last); // 4
Another option is using the new Array.prototype.at() method which takes an integer value and returns the item at that index. Negative integers count back from the last item in the array so if we want the last item we can just pass in -1
const arr = [1,2,3,4];
const last = arr.at(-1);
console.log(last); // 4
Another option is using the new findLast method. You can see the proposal here
const arr = [1,2,3,4];
const last = arr.findLast(x => true);
console.log(last); // 4
Another option is using the Array.prototype.slice() method which returns a shallow copy of a portion of an array into a new array object.
const arr = [1,2,3,4];
const last = arr.slice(-1)[0];
console.log(last); // 4
The "cleanest" ES6 way (IMO) would be:
const foo = [1,2,3,4];
const bar = [...foo].pop();
This avoids mutating foo, as .pop() would had, if we didn't used the spread operator.
That said, I like aswell the foo.slice(-1)[0] solution.
const [lastItem] = array.slice(-1);
Array.prototype.slice with -1 can be used to create a new Array containing only the last item of the original Array, you can then use Destructuring Assignment to create a variable using the first item of that new Array.
const lotteryNumbers = [12, 16, 4, 33, 41, 22];
const [lastNumber] = lotteryNumbers.slice(-1);
console.log(lotteryNumbers.slice(-1));
// => [22]
console.log(lastNumber);
// => 22
const [y] = x.slice(-1)
Quick Explanation:
This syntax [y] = <array/object> is called destructuring assignment & according to Mozilla docs, the destructuring assingment makes possible to unpack values from an array or properties from an object into distinct variables
Read more about it: here
I'd rather use array.pop() than indexes.
while(loc_array.pop()!= "index.html"){
}
var newT = document.createTextNode(unescape(capWords(loc_array[loc_array.length])));
this way you always get the element previous to index.html (providing your array has isolated index.html as one item). Note: You'll lose the last elements from the array, though.
You can use relative indexing with Array#at:
const myArray = [1, 2, 3]
console.log(myArray.at(-1))
// => 3
const lastElement = myArray[myArray.length - 1];
This is the best options from performance point of view (~1000 times faster than arr.slice(-1)).
You can use this pattern...
let [last] = arr.slice(-1);
While it reads rather nicely, keep in mind it creates a new array so it's less efficient than other solutions but it'll almost never be the performance bottleneck of your application.
If one wants to get the last element in one go, he/she may use Array#splice():
lastElement = document.location.href.split('/').splice(-1,1);
Here, there is no need to store the split elements in an array, and then get to the last element. If getting last element is the only objective, this should be used.
Note: This changes the original array by removing its last element. Think of splice(-1,1) as a pop() function that pops the last element.
Multiple ways to find last value of an array in javascript
Without affecting original array
var arr = [1,2,3,4,5];
console.log(arr.slice(-1)[0])
console.log(arr[arr.length-1])
const [last] = [...arr].reverse();
console.log(last)
let copyArr = [...arr];
console.log(copyArr.reverse()[0]);
Modifies original array
var arr = [1,2,3,4,5];
console.log(arr.pop())
arr.push(5)
console.log(...arr.splice(-1));
By creating own helper method
let arr = [1, 2, 3, 4, 5];
Object.defineProperty(arr, 'last',
{ get: function(){
return this[this.length-1];
}
})
console.log(arr.last);
Getting the last item of an array can be achieved by using the slice method with negative values.
You can read more about it here at the bottom.
var fileName = loc_array.slice(-1)[0];
if(fileName.toLowerCase() == "index.html")
{
//your code...
}
Using pop() will change your array, which is not always a good idea.
This question has been around a long time, so I'm surprised that no one mentioned just putting the last element back on after a pop().
arr.pop() is exactly as efficient as arr[arr.length-1], and both are the same speed as arr.push().
Therefore, you can get away with:
---EDITED [check that thePop isn't undefined before pushing]---
let thePop = arr.pop()
thePop && arr.push(thePop)
---END EDIT---
Which can be reduced to this (same speed [EDIT: but unsafe!]):
arr.push(thePop = arr.pop()) //Unsafe if arr empty
This is twice as slow as arr[arr.length-1], but you don't have to stuff around with an index. That's worth gold on any day.
Of the solutions I've tried, and in multiples of the Execution Time Unit (ETU) of arr[arr.length-1]:
[Method]..............[ETUs 5 elems]...[ETU 1 million elems]
arr[arr.length - 1] ------> 1 -----> 1
let myPop = arr.pop()
arr.push(myPop) ------> 2 -----> 2
arr.slice(-1).pop() ------> 36 -----> 924
arr.slice(-1)[0] ------> 36 -----> 924
[...arr].pop() ------> 120 -----> ~21,000,000 :)
The last three options, ESPECIALLY [...arr].pop(), get VERY much worse as the size of the array increases. On a machine without the memory limitations of my machine, [...arr].pop() probably maintains something like it's 120:1 ratio. Still, no one likes a resource hog.
Just putting another option here.
loc_array.splice(-1)[0] === 'index.html'
I found the above approach more clean and short onliner. Please, free feel to try this one.
Note: It will modify the original array, if you don't want to modify it you can use slice()
loc_array.slice(-1)[0] === 'index.html'
Thanks #VinayPai for pointing this out.
Here's more Javascript art if you came here looking for it
In the spirit of another answer that used reduceRight(), but shorter:
[3, 2, 1, 5].reduceRight(a => a);
It relies on the fact that, in case you don't provide an initial value, the very last element is selected as the initial one (check the docs here). Since the callback just keeps returning the initial value, the last element will be the one being returned in the end.
Beware that this should be considered Javascript art and is by no means the way I would recommend doing it, mostly because it runs in O(n) time, but also because it hurts readability.
And now for the serious answer
The best way I see (considering you want it more concise than array[array.length - 1]) is this:
const last = a => a[a.length - 1];
Then just use the function:
last([3, 2, 1, 5])
The function is actually useful in case you're dealing with an anonymous array like [3, 2, 1, 5] used above, otherwise you'd have to instantiate it twice, which would be inefficient and ugly:
[3, 2, 1, 5][[3, 2, 1, 5].length - 1]
Ugh.
For instance, here's a situation where you have an anonymous array and you'd have to define a variable, but you can use last() instead:
last("1.2.3".split("."));
ES6 object destructuring is another way to go.
const {length, [length-1]: last}=[1,2,3,4,5]
console.log(last)
You extract length property from Array using object destructuring. You create another dynamic key using already extracted key by [length-1] and assign it to last, all in one line.
For those not afraid to overload the Array prototype (and with enumeration masking you shouldn't be):
Object.defineProperty( Array.prototype, "getLast", {
enumerable: false,
configurable: false,
writable: false,
value: function() {
return this[ this.length - 1 ];
}
} );
I generally use underscorejs, with it you can just do
if (_.last(loc_array) === 'index.html'){
etc...
}
For me that is more semantic than loc_array.slice(-1)[0]
jQuery solves this neatly:
> $([1,2,3]).get(-1)
3
> $([]).get(-1)
undefined
To prevent removing last item from origin array you could use
Array.from(myArray).pop()
Mostly supported of all browsers (ES6)
In ECMAScript proposal Stage 1 there is a suggestion to add an array property that will return the last element: proposal-array-last.
Syntax:
arr.lastItem // get last item
arr.lastItem = 'value' // set last item
arr.lastIndex // get last index
You can use polyfill.
Proposal author: Keith Cirkel(chai autor)
I think this should work fine.
var arr = [1, 2, 3];
var last_element = arr.reverse()[0];
Just reverse the array and get the first element.
Edit: As mentioned below, the original array will be reversed. To avoid that you can change the code to:
var arr = [1, 2, 3];
var last_element = arr.slice().reverse()[0];
This will create a copy of the original array.
Personally I would upvote answer by kuporific / kritzikratzi. The array[array.length-1] method gets very ugly if you're working with nested arrays.
var array = [[1,2,3], [4,5,6], [7,8,9]]
​
array.slice(-1)[0]
​
//instead of
​
array[array.length-1]
​
//Much easier to read with nested arrays
​
array.slice(-1)[0].slice(-1)[0]
​
//instead of
​
array[array.length-1][array[array.length-1].length-1]
Whatever you do don't just use reverse() !!!
A few answers mention reverse but don't mention the fact that reverse modifies the original array, and doesn't (as in some other language or frameworks) return a copy.
var animals = ['dog', 'cat'];
animals.reverse()[0]
"cat"
animals.reverse()[0]
"dog"
animals.reverse()[1]
"dog"
animals.reverse()[1]
"cat"
This can be the worst type of code to debug!

How to achieve map functionality with the use of filter in JavaScript, as we can use reduce as map and filter?

Suppose I have an array var arr = [1,2,3] and if I do var result = arr.filter(callback) I want value of result would be [2,4,6] by the use of filter. I want to only define callback function in order to do so. It can be easily done with map but I want to use only filter.
Array.prototype.filter only filters existing values in an array, effectively creating a new array that can hold the same values, their subset, or an empty array, based on the filtering function.
You could do it using filter():
const arr = [1, 2, 3];
arr.filter((c, i) => {
arr[i] = +arr[i] * 2;
return true;
});
console.log(arr)
we are always returning true, so filter() makes no sense in this case.
As stated many times, there is no reason why you should do it.
It is impossible to do it like map because map returns a new array. You can either alter on the original array or you have to make a clone of the original array so you do not change it.
// this modifies the orginal array
var arr1 = [1,2,3]
arr1.filter((v,index,arr)=>{
arr[index] = v * 2;
return true
})
console.log(arr1)
// or you can clone it and do the same thing
// this modifies the cloned array
var arr2 = [1,2,3]
var arr3 = arr2.slice()
arr3.filter((v,index,arr)=>{
arr[index] = v * 2;
return true
})
console.log(arr2, arr3)
So no, you can not recreate map with filter since you HAVE to modify the original array or cheat and use a copy of the array.
So I'm not sure I understand the second part of your question, but as for the first part:
The callback for filter has three arguments, two of which are optional.
The first argument is the current element in the traversal, and the second and third arguments (the optional ones) are the 0-based index of the current element, and a reference to the original array.
This third parameter is useful for what you're trying to do.
let myArr = [1, 2, 3];
myArr.filter((el, ind, orig) => {
orig[ind] = orig[ind] + 1; // Or, whatever map logic you want to use
return true; // since a Boolean condition must be returned here
});
This way you can do it without even even having to break the scope of the function!
If you want to do it without necessarily having a variable to originally call filter on (you do have to pass an array), you can use the prototype and the call method:
Array.prototype.filter.call([1, 2, 3], (el, ind, orig) => {
orig[ind] = orig[ind] + 1;
return true;
});

javaScript: how do i check if argument matches the last string in an array [duplicate]

Here is my JavaScript code so far:
var linkElement = document.getElementById("BackButton");
var loc_array = document.location.href.split('/');
var newT = document.createTextNode(unescape(capWords(loc_array[loc_array.length-2])));
linkElement.appendChild(newT);
Currently it takes the second to last item in the array from the URL. However, I want to do a check for the last item in the array to be "index.html" and if so, grab the third to last item instead.
if (loc_array[loc_array.length - 1] === 'index.html') {
// do something
} else {
// something else
}
In the event that your server serves the same file for "index.html" and "inDEX.htML" you can also use: .toLowerCase().
Though, you might want to consider doing this server-side if possible: it will be cleaner and work for people without JS.
EDIT - ES-2022
Using ES-2022 Array.at(), the above may be written like this:
if (loc_array.at(-1) === 'index.html') {
// do something
} else {
// something else
}
Not sure if there's a drawback, but this seems quite concise:
arr.slice(-1)[0]
or
arr.slice(-1).pop()
Both will return undefined if the array is empty.
Use Array.pop:
var lastItem = anArray.pop();
Important : This returns the last element and removes it from the array
A shorter version of what #chaiguy posted:
Array.prototype.last = function() {
return this[this.length - 1];
}
Reading the -1 index returns undefined already.
EDIT:
These days the preference seems to be using modules and to avoid touching the prototype or using a global namespace.
export function last(array) {
return array[array.length - 1];
}
Two options are:
var last = arr[arr.length - 1]
or
var last = arr.slice(-1)[0]
The former is faster, but the latter looks nicer
http://jsperf.com/slice-vs-length-1-arr
Performance
Today 2020.05.16 I perform tests of chosen solutions on Chrome v81.0, Safari v13.1 and Firefox v76.0 on MacOs High Sierra v10.13.6
Conclusions
arr[arr.length-1] (D) is recommended as fastest cross-browser solution
mutable solution arr.pop() (A) and immutable _.last(arr) (L) are fast
solutions I, J are slow for long strings
solutions H, K (jQuery) are slowest on all browsers
Details
I test two cases for solutions:
mutable: A,
B,
C,
immutable: D,
E,
F,
G,
H,
I,
J (my),
immutable from external libraries: K,
L,
M,
for two cases
short string - 10 characters - you can run test HERE
long string - 1M characters - you can run test HERE
function A(arr) {
return arr.pop();
}
function B(arr) {
return arr.splice(-1,1);
}
function C(arr) {
return arr.reverse()[0]
}
function D(arr) {
return arr[arr.length - 1];
}
function E(arr) {
return arr.slice(-1)[0] ;
}
function F(arr) {
let [last] = arr.slice(-1);
return last;
}
function G(arr) {
return arr.slice(-1).pop();
}
function H(arr) {
return [...arr].pop();
}
function I(arr) {
return arr.reduceRight(a => a);
}
function J(arr) {
return arr.find((e,i,a)=> a.length==i+1);
}
function K(arr) {
return $(arr).get(-1);
}
function L(arr) {
return _.last(arr);
}
function M(arr) {
return _.nth(arr, -1);
}
// ----------
// TEST
// ----------
let loc_array=["domain","a","b","c","d","e","f","g","h","file"];
log = (f)=> console.log(`${f.name}: ${f([...loc_array])}`);
[A,B,C,D,E,F,G,H,I,J,K,L,M].forEach(f=> log(f));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js" integrity="sha256-VeNaFBVDhoX3H+gJ37DpT/nTuZTdjYro9yBruHjVmoQ=" crossorigin="anonymous"></script>
Example results for Chrome for short string
Here's how to get it with no effect on the original ARRAY
a = [1,2,5,6,1,874,98,"abc"];
a.length; //returns 8 elements
If you use pop(), it will modify your array
a.pop(); // will return "abc" AND REMOVES IT from the array
a.length; // returns 7
But you can use this so it has no effect on the original array:
a.slice(-1).pop(); // will return "abc" won't do modify the array
// because slice creates a new array object
a.length; // returns 8; no modification and you've got you last element
Getting the last item is possible via the length property. Since the array count starts at 0, you can pick the last item by referencing the array.length - 1 item
const arr = [1,2,3,4];
const last = arr[arr.length - 1];
console.log(last); // 4
Another option is using the new Array.prototype.at() method which takes an integer value and returns the item at that index. Negative integers count back from the last item in the array so if we want the last item we can just pass in -1
const arr = [1,2,3,4];
const last = arr.at(-1);
console.log(last); // 4
Another option is using the new findLast method. You can see the proposal here
const arr = [1,2,3,4];
const last = arr.findLast(x => true);
console.log(last); // 4
Another option is using the Array.prototype.slice() method which returns a shallow copy of a portion of an array into a new array object.
const arr = [1,2,3,4];
const last = arr.slice(-1)[0];
console.log(last); // 4
The "cleanest" ES6 way (IMO) would be:
const foo = [1,2,3,4];
const bar = [...foo].pop();
This avoids mutating foo, as .pop() would had, if we didn't used the spread operator.
That said, I like aswell the foo.slice(-1)[0] solution.
const [lastItem] = array.slice(-1);
Array.prototype.slice with -1 can be used to create a new Array containing only the last item of the original Array, you can then use Destructuring Assignment to create a variable using the first item of that new Array.
const lotteryNumbers = [12, 16, 4, 33, 41, 22];
const [lastNumber] = lotteryNumbers.slice(-1);
console.log(lotteryNumbers.slice(-1));
// => [22]
console.log(lastNumber);
// => 22
const [y] = x.slice(-1)
Quick Explanation:
This syntax [y] = <array/object> is called destructuring assignment & according to Mozilla docs, the destructuring assingment makes possible to unpack values from an array or properties from an object into distinct variables
Read more about it: here
I'd rather use array.pop() than indexes.
while(loc_array.pop()!= "index.html"){
}
var newT = document.createTextNode(unescape(capWords(loc_array[loc_array.length])));
this way you always get the element previous to index.html (providing your array has isolated index.html as one item). Note: You'll lose the last elements from the array, though.
You can use relative indexing with Array#at:
const myArray = [1, 2, 3]
console.log(myArray.at(-1))
// => 3
const lastElement = myArray[myArray.length - 1];
This is the best options from performance point of view (~1000 times faster than arr.slice(-1)).
You can use this pattern...
let [last] = arr.slice(-1);
While it reads rather nicely, keep in mind it creates a new array so it's less efficient than other solutions but it'll almost never be the performance bottleneck of your application.
If one wants to get the last element in one go, he/she may use Array#splice():
lastElement = document.location.href.split('/').splice(-1,1);
Here, there is no need to store the split elements in an array, and then get to the last element. If getting last element is the only objective, this should be used.
Note: This changes the original array by removing its last element. Think of splice(-1,1) as a pop() function that pops the last element.
Multiple ways to find last value of an array in javascript
Without affecting original array
var arr = [1,2,3,4,5];
console.log(arr.slice(-1)[0])
console.log(arr[arr.length-1])
const [last] = [...arr].reverse();
console.log(last)
let copyArr = [...arr];
console.log(copyArr.reverse()[0]);
Modifies original array
var arr = [1,2,3,4,5];
console.log(arr.pop())
arr.push(5)
console.log(...arr.splice(-1));
By creating own helper method
let arr = [1, 2, 3, 4, 5];
Object.defineProperty(arr, 'last',
{ get: function(){
return this[this.length-1];
}
})
console.log(arr.last);
Getting the last item of an array can be achieved by using the slice method with negative values.
You can read more about it here at the bottom.
var fileName = loc_array.slice(-1)[0];
if(fileName.toLowerCase() == "index.html")
{
//your code...
}
Using pop() will change your array, which is not always a good idea.
This question has been around a long time, so I'm surprised that no one mentioned just putting the last element back on after a pop().
arr.pop() is exactly as efficient as arr[arr.length-1], and both are the same speed as arr.push().
Therefore, you can get away with:
---EDITED [check that thePop isn't undefined before pushing]---
let thePop = arr.pop()
thePop && arr.push(thePop)
---END EDIT---
Which can be reduced to this (same speed [EDIT: but unsafe!]):
arr.push(thePop = arr.pop()) //Unsafe if arr empty
This is twice as slow as arr[arr.length-1], but you don't have to stuff around with an index. That's worth gold on any day.
Of the solutions I've tried, and in multiples of the Execution Time Unit (ETU) of arr[arr.length-1]:
[Method]..............[ETUs 5 elems]...[ETU 1 million elems]
arr[arr.length - 1] ------> 1 -----> 1
let myPop = arr.pop()
arr.push(myPop) ------> 2 -----> 2
arr.slice(-1).pop() ------> 36 -----> 924
arr.slice(-1)[0] ------> 36 -----> 924
[...arr].pop() ------> 120 -----> ~21,000,000 :)
The last three options, ESPECIALLY [...arr].pop(), get VERY much worse as the size of the array increases. On a machine without the memory limitations of my machine, [...arr].pop() probably maintains something like it's 120:1 ratio. Still, no one likes a resource hog.
Just putting another option here.
loc_array.splice(-1)[0] === 'index.html'
I found the above approach more clean and short onliner. Please, free feel to try this one.
Note: It will modify the original array, if you don't want to modify it you can use slice()
loc_array.slice(-1)[0] === 'index.html'
Thanks #VinayPai for pointing this out.
Here's more Javascript art if you came here looking for it
In the spirit of another answer that used reduceRight(), but shorter:
[3, 2, 1, 5].reduceRight(a => a);
It relies on the fact that, in case you don't provide an initial value, the very last element is selected as the initial one (check the docs here). Since the callback just keeps returning the initial value, the last element will be the one being returned in the end.
Beware that this should be considered Javascript art and is by no means the way I would recommend doing it, mostly because it runs in O(n) time, but also because it hurts readability.
And now for the serious answer
The best way I see (considering you want it more concise than array[array.length - 1]) is this:
const last = a => a[a.length - 1];
Then just use the function:
last([3, 2, 1, 5])
The function is actually useful in case you're dealing with an anonymous array like [3, 2, 1, 5] used above, otherwise you'd have to instantiate it twice, which would be inefficient and ugly:
[3, 2, 1, 5][[3, 2, 1, 5].length - 1]
Ugh.
For instance, here's a situation where you have an anonymous array and you'd have to define a variable, but you can use last() instead:
last("1.2.3".split("."));
ES6 object destructuring is another way to go.
const {length, [length-1]: last}=[1,2,3,4,5]
console.log(last)
You extract length property from Array using object destructuring. You create another dynamic key using already extracted key by [length-1] and assign it to last, all in one line.
For those not afraid to overload the Array prototype (and with enumeration masking you shouldn't be):
Object.defineProperty( Array.prototype, "getLast", {
enumerable: false,
configurable: false,
writable: false,
value: function() {
return this[ this.length - 1 ];
}
} );
I generally use underscorejs, with it you can just do
if (_.last(loc_array) === 'index.html'){
etc...
}
For me that is more semantic than loc_array.slice(-1)[0]
jQuery solves this neatly:
> $([1,2,3]).get(-1)
3
> $([]).get(-1)
undefined
To prevent removing last item from origin array you could use
Array.from(myArray).pop()
Mostly supported of all browsers (ES6)
In ECMAScript proposal Stage 1 there is a suggestion to add an array property that will return the last element: proposal-array-last.
Syntax:
arr.lastItem // get last item
arr.lastItem = 'value' // set last item
arr.lastIndex // get last index
You can use polyfill.
Proposal author: Keith Cirkel(chai autor)
I think this should work fine.
var arr = [1, 2, 3];
var last_element = arr.reverse()[0];
Just reverse the array and get the first element.
Edit: As mentioned below, the original array will be reversed. To avoid that you can change the code to:
var arr = [1, 2, 3];
var last_element = arr.slice().reverse()[0];
This will create a copy of the original array.
Personally I would upvote answer by kuporific / kritzikratzi. The array[array.length-1] method gets very ugly if you're working with nested arrays.
var array = [[1,2,3], [4,5,6], [7,8,9]]
​
array.slice(-1)[0]
​
//instead of
​
array[array.length-1]
​
//Much easier to read with nested arrays
​
array.slice(-1)[0].slice(-1)[0]
​
//instead of
​
array[array.length-1][array[array.length-1].length-1]
Whatever you do don't just use reverse() !!!
A few answers mention reverse but don't mention the fact that reverse modifies the original array, and doesn't (as in some other language or frameworks) return a copy.
var animals = ['dog', 'cat'];
animals.reverse()[0]
"cat"
animals.reverse()[0]
"dog"
animals.reverse()[1]
"dog"
animals.reverse()[1]
"cat"
This can be the worst type of code to debug!

Array in Javascript (array.forEach Vs array.map) [duplicate]

I know that there were a lot of topics like this. And I know the basics: .forEach() operates on original array and .map() on the new one.
In my case:
function practice (i){
return i+1;
};
var a = [ -1, 0, 1, 2, 3, 4, 5 ];
var b = [ 0 ];
var c = [ 0 ];
console.log(a);
b = a.forEach(practice);
console.log("=====");
console.log(a);
console.log(b);
c = a.map(practice);
console.log("=====");
console.log(a);
console.log(c);
And this is output:
[ -1, 0, 1, 2, 3, 4, 5 ]
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
undefined
=====
[ -1, 0, 1, 2, 3, 4, 5 ]
[ 0, 1, 2, 3, 4, 5, 6 ]
I can't understand why using practice changes value of b to undefined.
I'm sorry if this is silly question, but I'm quite new in this language and answers I found so far didn't satisfy me.
They are not one and the same. Let me explain the difference.
forEach: This iterates over a list and applies some operation with side effects to each list member (example: saving every list item to the database) and does not return anything.
map: This iterates over a list, transforms each member of that list, and returns another list of the same size with the transformed members (example: transforming list of strings to uppercase). It does not mutate the array on which it is called (although the callback function may do so).
References
Array.prototype.forEach() - JavaScript | MDN
Array.prototype.map() - JavaScript | MDN
Array.forEach “executes a provided function once per array element.”
Array.map “creates a new array with the results of calling a provided function on every element in this array.”
So, forEach doesn’t actually return anything. It just calls the function for each array element and then it’s done. So whatever you return within that called function is simply discarded.
On the other hand, map will similarly call the function for each array element but instead of discarding its return value, it will capture it and build a new array of those return values.
This also means that you could use map wherever you are using forEach but you still shouldn’t do that so you don’t collect the return values without any purpose. It’s just more efficient to not collect them if you don’t need them.
forEach()
map()
Functionality
Performs given operation on each element of the array
Performs given "transformation" on a "copy" of each element
Return value
Returns undefined
Returns new array with transformed elements, leaving back original array unchanged.
Preferrable usage scenario and example
Performing non-tranformation like processing on each element. For example, saving all elements in the database.
Obtaining array containing output of some processing done on each element of the array. For example, obtaining array of lengths of each string in the array
forEach() example
chars = ['Hello' , 'world!!!'] ;
var retVal = chars.forEach(function(word){
console.log("Saving to db: " + word)
})
console.log(retVal) //undefined
map() example
chars = ['Hello' , 'world!!!'] ;
var lengths = chars.map(function(word){
return word.length
})
console.log(lengths) //[5,8]
The main difference that you need to know is .map() returns a new array while .forEach() doesn't. That is why you see that difference in the output. .forEach() just operates on every value in the array.
Read up:
Array.prototype.forEach() - JavaScript | MDN
Array.prototype.map() - JavaScript | MDN
You might also want to check out:
- Array.prototype.every() - JavaScript | MDN
Performance Analysis
For loops performs faster than map or foreach as number of elements in a array increases.
let array = [];
for (var i = 0; i < 20000000; i++) {
array.push(i)
}
console.time('map');
array.map(num => {
return num * 4;
});
console.timeEnd('map');
console.time('forEach');
array.forEach((num, index) => {
return array[index] = num * 4;
});
console.timeEnd('forEach');
console.time('for');
for (i = 0; i < array.length; i++) {
array[i] = array[i] * 2;
}
console.timeEnd('for');
forEach: If you want to perform an action on the elements of an Array and it is same as you use for loop. The result of this method does not give us an output buy just loop through the elements.
map: If you want to perform an action on the elements of an array and also you want to store the output of your action into an Array. This is similar to for loop within a function that returns the result after each iteration.
Hope this helps.
map returns a new array.
forEach has no return value.
That's the heart of the difference. Most of the other answers here say effectively that, but in a much more convoluted way.
forEach() :
return value : undefined
originalArray : not modified after the method call
newArray is not created after the end of method call.
map() :
return value : new Array populated with the results of calling a provided function on every element in the calling array
originalArray : not modified after the method call
newArray is created after the end of method call.
Conclusion:
Since map builds a new array, using it when you aren't using the returned array is an anti-pattern; use forEach or for-of instead.
The difference lies in what they return. After execution:
arr.map()
returns an array of elements resulting from the processed function; while:
arr.forEach()
returns undefined.
one of the shuttle difference not mentioned here is that forEach() can loop over static (not live) NodeList while map() cannot
//works perfectly
document.querySelectorAll('.score').forEach(element=>console.log(element));
//Uncaught TypeError: document.querySelectorAll(...).map is not a function
document.querySelectorAll('.score').map(element=>console.log(element));
Diffrence between Foreach & map :
Map() : If you use map then map can return new array by iterating main array.
Foreach() : If you use Foreach then it can not return anything for each can iterating main array.
useFul link : use this link for understanding diffrence
https://codeburst.io/javascript-map-vs-foreach-f38111822c0f
Difference between forEach() & map()
forEach() just loop through the elements. It's throws away return values and always returns undefined.The result of this method does not give us an output .
map() loop through the elements allocates memory and stores return values by iterating main array
Example:
var numbers = [2,3,5,7];
var forEachNum = numbers.forEach(function(number){
return number
})
console.log(forEachNum)
//output undefined
var mapNum = numbers.map(function(number){
return number
})
console.log(mapNum)
//output [2,3,5,7]
map() is faster than forEach()
One thing to point out is that both methods skips uninitialized values, but map keeps them in the returned array.
var arr = [1, , 3];
arr.forEach(function(element) {
console.log(element);
});
//Expected output: 1 3
console.log(arr.map(element => element));
//Expected output: [1, undefined, 3];
Performance Analysis (again - not very scientific)
In my experience sometime .map() can be faster than .foreach()
let rows = [];
for (let i = 0; i < 10000000; i++) {
// console.log("here", i)
rows.push({ id: i, title: 'ciao' });
}
const now1 = Date.now();
rows.forEach(row => {
if (!row.event_title) {
row.event_title = `no title ${row.event_type}`;
}
});
const now2 = Date.now();
rows = rows.map(row => {
if (!row.event_title) {
row.event_title = `no title ${row.event_type}`;
}
return row;
});
const now3 = Date.now();
const time1 = now2 - now1;
const time2 = now3 - now2;
console.log('forEach time', time1);
console.log('.map time', time2);
On my macbook pro (late 2013)
forEach time 1909
.map time 444
.map and .forEach will do just about then same thing, until you start operating on arrays with millions of elements. .map will create another collection with the same size (and possibly type, depending on the array species) which could use up a LOT of memory. .forEach will not do this.
const arr = [...Array(100000000).keys()];
console.time("for");
for (let i = 0; i < arr.length; i++) {}
console.timeEnd("for");
console.time("while");
let j = 0;
while (j < arr.length) {
j++;
}
console.timeEnd("while");
console.time("dowhile");
let k = 0;
do {
k++;
} while (k < arr.length);
console.timeEnd("dowhile");
console.time("forEach");
arr.forEach((element) => {});
console.timeEnd("forEach");
VM35:6 for: 45.998046875 ms
VM35:13 while: 154.581787109375 ms
VM35:20 dowhile: 141.97216796875 ms
VM35:24 forEach: 776.469970703125 ms
Map implicitly returns while forEach does not.
This is why when you're coding a JSX application, you almost always use map instead of forEach to display content in React.

Categories