Array.push return pushed value? - javascript

Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
I don't know if this has already been proposed or asked before; Google searches returned only a myriad number of questions related to the current functionality of Array.push().
Here's an example implementation of this functionality, feel free to correct it:
;(function() {
var _push = Array.prototype.push;
Array.prototype.push = function() {
return this[_push.apply(this, arguments) - 1];
}
}());
You would then be able to do something like this:
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray.push({}));
Where someFunction modifies the object passed in as the second parameter, for example. Now the contents of someArray are [{"someKey": "hello world"}].
Are there any drawbacks to this approach?

See my detailed answer here
TLDR;
You can get the return value of the mutated array, when you instead add an element using array.concat[].
concat is a way of "adding" or "joining" two arrays together. The awesome thing about this method, is that it has a return value of the resultant array, so it can be chained.
newArray = oldArray.concat[newItem];
This also allows you to chain functions together
updatedArray = oldArray.filter((item) => {
item.id !== updatedItem.id).concat[updatedItem]};
Where item = {id: someID, value: someUpdatedValue}
The main thing to notice is, that you need to pass an array to concat.
So make sure that you put your value to be "pushed" inside a couple of square brackets, and you're good to go.
This will give you the functionality you expected from push()
You can use the + operator to "add" two arrays together, or by passing the arrays to join as parameters to concat().
let arrayAB = arrayA + arrayB;
let arrayCD = concat(arrayC, arrayD);
Note that by using the concat method, you can take advantage of "chaining" commands before and after concat.

Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
Of course there is one: Other code will expect Array::push to behave as defined in the specification, i.e. to return the new length. And other developers will find your code incomprehensible if you did redefine builtin functions to behave unexpectedly.
At least choose a different name for the method.
You would then be able to do something like this: someFunction(value, someArray.push({}));
Uh, what? Yeah, my second point already strikes :-)
However, even if you didn't use push this does not get across what you want to do. The composition that you should express is "add an object which consist of a key and a value to an array". With a more functional style, let someFunction return this object, and you can write
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
return obj;
}
someArray.push(someFunction(value, {}));

Just as a historical note -- There was an older version of JavaScript -- JavaScript version 1.2 -- that handled a number of array functions quite differently.
In particular to this question, Array.push did return the item, not the length of the array.
That said, 1.2 has been not been used for decades now -- but some very old references might still refer to this behavior.
http://web.archive.org/web/20010408055419/developer.netscape.com/docs/manuals/communicator/jsguide/js1_2.htm

By the coming of ES6, it is recommended to extend array class in the proper way , then , override push method :
class XArray extends Array {
push() {
super.push(...arguments);
return (arguments.length === 1) ? arguments[0] : arguments;
}
}
//---- Application
let list = [1, 3, 7,5];
list = new XArray(...list);
console.log(
'Push one item : ',list.push(4)
);
console.log(
'Push multi-items :', list.push(-9, 2)
);
console.log(
'Check length :' , list.length
)

Method push() returns the last element added, which makes it very inconvenient when creating short functions/reducers. Also, push() - is a rather archaic stuff in JS. On ahother hand we have spread operator [...] which is faster and does what you needs: it exactly returns an array.
// to concat arrays
const a = [1,2,3];
const b = [...a, 4, 5];
console.log(b) // [1, 2, 3, 4, 5];
// to concat and get a length
const arrA = [1,2,3,4,5];
const arrB = [6,7,8];
console.log([0, ...arrA, ...arrB, 9].length); // 10
// to reduce
const arr = ["red", "green", "blue"];
const liArr = arr.reduce( (acc,cur) => [...acc, `<li style='color:${cur}'>${cur}</li>`],[]);
console.log(liArr);
//[ "<li style='color:red'>red</li>",
//"<li style='color:green'>green</li>",
//"<li style='color:blue'>blue</li>" ]

var arr = [];
var element = Math.random();
assert(element === arr[arr.push(element)-1]);

How about doing someArray[someArray.length]={} instead of someArray.push({})? The value of an assignment is the value being assigned.
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray[someArray.length]={});
console.log(someArray)

Related

Why do i get just a number from console.log(Array.push()); in Javascript? [duplicate]

Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
I don't know if this has already been proposed or asked before; Google searches returned only a myriad number of questions related to the current functionality of Array.push().
Here's an example implementation of this functionality, feel free to correct it:
;(function() {
var _push = Array.prototype.push;
Array.prototype.push = function() {
return this[_push.apply(this, arguments) - 1];
}
}());
You would then be able to do something like this:
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray.push({}));
Where someFunction modifies the object passed in as the second parameter, for example. Now the contents of someArray are [{"someKey": "hello world"}].
Are there any drawbacks to this approach?
See my detailed answer here
TLDR;
You can get the return value of the mutated array, when you instead add an element using array.concat[].
concat is a way of "adding" or "joining" two arrays together. The awesome thing about this method, is that it has a return value of the resultant array, so it can be chained.
newArray = oldArray.concat[newItem];
This also allows you to chain functions together
updatedArray = oldArray.filter((item) => {
item.id !== updatedItem.id).concat[updatedItem]};
Where item = {id: someID, value: someUpdatedValue}
The main thing to notice is, that you need to pass an array to concat.
So make sure that you put your value to be "pushed" inside a couple of square brackets, and you're good to go.
This will give you the functionality you expected from push()
You can use the + operator to "add" two arrays together, or by passing the arrays to join as parameters to concat().
let arrayAB = arrayA + arrayB;
let arrayCD = concat(arrayC, arrayD);
Note that by using the concat method, you can take advantage of "chaining" commands before and after concat.
Are there any substantial reasons why modifying Array.push() to return the object pushed rather than the length of the new array might be a bad idea?
Of course there is one: Other code will expect Array::push to behave as defined in the specification, i.e. to return the new length. And other developers will find your code incomprehensible if you did redefine builtin functions to behave unexpectedly.
At least choose a different name for the method.
You would then be able to do something like this: someFunction(value, someArray.push({}));
Uh, what? Yeah, my second point already strikes :-)
However, even if you didn't use push this does not get across what you want to do. The composition that you should express is "add an object which consist of a key and a value to an array". With a more functional style, let someFunction return this object, and you can write
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
return obj;
}
someArray.push(someFunction(value, {}));
Just as a historical note -- There was an older version of JavaScript -- JavaScript version 1.2 -- that handled a number of array functions quite differently.
In particular to this question, Array.push did return the item, not the length of the array.
That said, 1.2 has been not been used for decades now -- but some very old references might still refer to this behavior.
http://web.archive.org/web/20010408055419/developer.netscape.com/docs/manuals/communicator/jsguide/js1_2.htm
By the coming of ES6, it is recommended to extend array class in the proper way , then , override push method :
class XArray extends Array {
push() {
super.push(...arguments);
return (arguments.length === 1) ? arguments[0] : arguments;
}
}
//---- Application
let list = [1, 3, 7,5];
list = new XArray(...list);
console.log(
'Push one item : ',list.push(4)
);
console.log(
'Push multi-items :', list.push(-9, 2)
);
console.log(
'Check length :' , list.length
)
Method push() returns the last element added, which makes it very inconvenient when creating short functions/reducers. Also, push() - is a rather archaic stuff in JS. On ahother hand we have spread operator [...] which is faster and does what you needs: it exactly returns an array.
// to concat arrays
const a = [1,2,3];
const b = [...a, 4, 5];
console.log(b) // [1, 2, 3, 4, 5];
// to concat and get a length
const arrA = [1,2,3,4,5];
const arrB = [6,7,8];
console.log([0, ...arrA, ...arrB, 9].length); // 10
// to reduce
const arr = ["red", "green", "blue"];
const liArr = arr.reduce( (acc,cur) => [...acc, `<li style='color:${cur}'>${cur}</li>`],[]);
console.log(liArr);
//[ "<li style='color:red'>red</li>",
//"<li style='color:green'>green</li>",
//"<li style='color:blue'>blue</li>" ]
var arr = [];
var element = Math.random();
assert(element === arr[arr.push(element)-1]);
How about doing someArray[someArray.length]={} instead of someArray.push({})? The value of an assignment is the value being assigned.
var someArray = [],
value = "hello world";
function someFunction(value, obj) {
obj["someKey"] = value;
}
someFunction(value, someArray[someArray.length]={});
console.log(someArray)

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!

Is there a way to check whether the argument passed into a function is an array in javascript?

const validateCred = arr => {
let checkableArr = arr.pop();
for (let i = arr.length - 1; i >= 0; i--) {
arr[i]
checkableArr.push(arr[i])
}
}
When i run the code, I get an error saying that .push() is not a function that I can use on checkableArr. this is because checkableArr isn't an array due to it being a variation of arr (the argument that will be passed when the function is called), which the function isn't sure is an array, is there any way to check that the argument passed into the function is an array?
EDIT:
The thing I was looking for is called isArray(), a method that returns a boolean indicating if the item passed into it is an array or no. Thanks to #David for showing me this tool, along with a bunch of helpful information that helped a lot with writing my program
You're getting that error, because you haven't made sure that the last item of the passed array (arr) is an array itself, but your function's logic requires it to be an array.
There are various ways to solve this, some of them have already been outlined by others (#hungerstar).
Check the last element of arr
One attempt is to ensure that the last element/item inside arr is an array and bail out if it isn't.
const validateCred = arr => {
let lastItem = arr.pop();
if (!Array.isArray(lastItem)) {
throw new Error('validateCred :: Last item of passed array must be an array itself');
}
// ... rest of your code ...
}
Although that does not solve the root cause, it ensures you get a decent and descriptive message about what went wrong. It's possible to improve that by defining a fallback array in case the last item isn't an array itself. Something like this:
const validateCred = arr => {
let lastItem = arr.pop();
let checkableArr = Array.isArray(lastItem) ? lastItem : [];
// ... rest of your code ...
}
One thing to note: If the last item may be an array with a value inside, you have to copy that value into the new array!
const validateCred = arr => {
let lastItem = arr.pop();
let checkableArr = Array.isArray(lastItem) ? lastItem : [lastItem]; // <--
// ... rest of your code ...
}
HINT: The following answer is based on guessing. The name validateCred lets me assume you use it to validate credentials. However, that's just guessing because all the provided code does is taking the last item and then pushing the rest of the contents of arr reversely into it (= reversing and flattening)
Reversing and flattening
If all you want to do with validateCred is reversing and flattening (and you only target supporting environments), you can easily do that with a one-liner:
// impure version
const validateCred = arr => arr.reverse().flat();
// pure version
const validateCred = arr => arr.flat().reverse();
To support older environments as well, you can use .reduce and .concat instead of .flat:
// impure version
const validateCred = arr => arr.reverse().reduce((acc, x) => acc.concat(x), []);
// pure version
const validateCred = arr => arr.reduce((acc, x) => acc.concat(x), []).reverse();
Yes, we pass an array as an argument using call/apply method. In your code when you are using arr.pop() it gets converted to number/string depending upon what type of array you specified, I specified below integer value so checkableArr is now integer so because of this you are getting an error.
Corrected code is here. Just replace in your code like:
let checkableArr = arr; //arr.pop();

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!

Categories