Reputation: 11499
So I've created this jqueryui widget. Its creates a div that I can stream errors into. The widget code looks like this:
$.widget('ui.miniErrorLog', {
logStart: "<ul>", // these next 4 elements are actually a bunch more complicated.
logEnd: "</ul>",
errStart: "<li>",
errEnd: "</li>",
content: "",
refs: [],
_create: function() { $(this.element).addClass( "ui-state-error" ).hide(); },
clear: function() {
this.content = "";
for ( var i in this.refs )
$( this.refs[i] ).removeClass( "ui-state-error" );
this.refs = [];
$(this.element).empty().hide();
},
addError: function( msg, ref ) {
this.content += this.errStart + msg + this.errEnd;
if ( ref ) {
if ( ref instanceof Array )
this.refs.concat( ref );
else
this.refs.push( ref );
for ( var i in this.refs )
$( this.refs[i] ).addClass( "ui-state-error" );
}
$(this.element).html( this.logStart + this.content + this.logEnd ).show();
},
hasError: function()
{
if ( this.refs.length )
return true;
return false;
},
});
I can add error messages into it, and references to page elements that is will put into an error state. I use it to validate dialogs. In the "addError" method I can pass in a single id, or an array of ids, like this:
$( "#registerDialogError" ).miniErrorLog(
'addError',
"Your passwords don't match.",
[ "#registerDialogPassword1", "#registerDialogPassword2" ] );
But when I pass in an array of id's it doesn't work. The problem is in the following lines (i think):
if ( ref instanceof Array )
this.refs.concat( ref );
else
this.refs.push( ref );
Why doesn't that concat work. this.refs and ref are both arrays. So why doesn't the concat work?
Bonus: am I doing anything else dumb in this widget? It's my first one.
Upvotes: 130
Views: 131966
Reputation: 1214
The concat
method doesn't change the original array, you can use array destructuring.
const numbers = [1,2,3,4];
const newNumbers = [5,6,7,8,9];
numbers.push(...newNumbers); // [1,2,3,4,5,6,7,8,9]
Upvotes: 1
Reputation: 57185
Others have mentioned that this.refs.concat(ref);
allocates and returns a new array which can be reassigned to the object: this.refs = this.refs.concat(ref);
. concat
does not modify either argument array.
However, probably more accurate here is to use push
, which adds an element to the calling array in-place: this.refs.push(ref);
(no reassignment with =
--push
returns the new array length which is usually ignored).
If you're adding multiple items, push
accepts variable arguments, so you can spread an array onto it:
const arr = [0, 1, 2];
arr.push(3); // add one element
console.log(arr) // => [0, 1, 2, 3]
arr.push(4, 5); // add two elements
console.log(arr) // => [0, 1, 2, 3, 4, 5]
const toAdd = [6, 7, 8];
arr.push(...toAdd); // add an array
console.log(arr); // => [0, 1, 2, 3, 4, 5, 6, 7, 8]
concat
could create a similar result with reassignment:
let arr = [0, 1, 2];
arr = arr.concat(3); // reassign with one new element
console.log(arr) // => [0, 1, 2, 3]
arr = arr.concat(4, 5); // reassign with two new elements
console.log(arr) // => [0, 1, 2, 3, 4, 5]
const toAdd = [6, 7, 8];
arr = arr.concat(toAdd); // reassign with a new array added
console.log(arr); // => [0, 1, 2, 3, 4, 5, 6, 7, 8]
concat
is clearly less optimal for this use case but is useful to know about for others, particularly when immutability is needed (for example, when working with React state).
Another occasion mutating with push
is handy is in a function that should mutate its argument:
const addOne = arr => { // contrived example
arr.push(1);
};
const arr = [];
addOne(arr);
console.log(arr); // => [1] as expected
const addOneBroken = arr => {
arr = arr.concat(1); // purely local reassignment!
};
addOneBroken(arr);
console.log(arr); // => still [1]
Another option for merging arrays and items is the spread syntax, similar to concat:
let arr = [0, 1, 2];
const toAdd = [3, 4, 5];
const arr1 = [...arr, 3]; // add one item, similar to concat
console.log(arr1); // [0, 1, 2, 3]
const arr2 = [...arr, ...toAdd]; // add an array, similar to concat
console.log(arr2); // [0, 1, 2, 3, 4, 5]
arr = [-1, ...arr, 42, ...toAdd, 6, 7]; // build a new complex array and reassign
console.log(arr); // => [-1, 0, 1, 2, 42, 3, 4, 5, 6, 7]
The above can be done with chained concat
calls:
let arr = [0, 1, 2];
const toAdd = [3, 4, 5];
arr = [-1].concat(arr).concat(42).concat(toAdd).concat(6).concat(7);
console.log(arr); // => [-1, 0, 1, 2, 42, 3, 4, 5, 6, 7]
Note that if you have an array you don't want to flatten during a push
, just skip the ...
spread:
const arr = [0, 1, 2];
const toAdd = [3, 4, 5];
arr.push(toAdd);
console.log(arr); // => [0, 1, 2, [3, 4, 5]]
Upvotes: 2
Reputation: 2987
Just a note, if you really want to have a mutable array when using the concat function (by mutable I mean that it does not create a new array but mutate the existing one) you can reassign the concat function for that array instance. There is what I did when I needed this.
let myArray = [];
myArray.concat= function( toAdd){
if(Array.isArray(toAdd)){
for(let node of toAdd)
this.push(node);
}else
this.push(toAdd);
}
Upvotes: 0
Reputation: 13689
you have to re-assign value using = to array , that you want to get concated value
let array1=[1,2,3,4];
let array2=[5,6,7,8];
array1.concat(array2);
console.log('NOT WORK : array1.concat(array2); =>',array1);
array1= array1.concat(array2);
console.log('WORKING : array1 = array1.concat(array2); =>',array1);
Upvotes: 16
Reputation: 1447
To expand on Konstantin Dinev:
.concat()
doesn't add to current object, so this will not work:
foo.bar.concat(otherArray);
This will:
foo.bar = foo.bar.concat(otherArray);
Upvotes: 25
Reputation: 34905
Here is the reason why:
Definition and Usage
The concat() method is used to join two or more arrays.
This method does not change the existing arrays, but returns a new array, containing the values of the joined arrays.
You need to assign the result of the concatenation back in the array that you have.
Upvotes: 89
Reputation: 9576
The concat method doesn't change the original array, you need to reassign it.
if ( ref instanceof Array )
this.refs = this.refs.concat( ref );
else
this.refs.push( ref );
Upvotes: 346