Is there any convenient way to replace the content of an array, AND keep a reference to it? I don't want to replace the array like this:
var arr1 = [1,2,3];
var referenceToArr1 = arr1;
var arr2 = [4,5,6];
arr1 = arr2;
// logs: [4,5,6] false
console.log(arr1, arr1===referenceToArr1);
// logs [1,2,3]
console.log(referenceToArr1);
This way arr1
has the content of arr2
, but I loose the reference in referenceToArr1
, because it still points to the original arr1
.
With this way, I don't loose the reference:
var arr1 = [1,2,3];
var referenceToArr1 = arr1;
var arr2 = [4,5,6];
arr1.length = 0;
for (var i = 0; i < arr2.length; i++) {
arr1.push(arr2[i]);
}
// logs: [4,5,6] true
console.log(arr1, arr1===referenceToArr1);
// logs: [4,5,6]
console.log(referenceToArr1)
The drawback here is, that I have to empty arr1.length = 0
, iterate over every element of arr2
and push it to arr1
by hand.
My questions are:
- Sure, I could write a helper for this, but what is the most efficient way?
- Is there a short, vanilla javascript way, to do this (maybe a one liner?)
- I'm also using underscore.js but haven't found a method for this kind of problem. Is there a way to do this with underscore.js?
Background:
I have an AngularJS app with a service. Inside this service, I have an array to keep all the elements loaded from the server. The data from the service get's bind to a controller and is used in a view. When the data from the service get's change (e.g. a refetch happens), I want to auto update my controllers vars and the view it is bind to.
Here is a Plunker:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, myService) {
$scope.name = 'World';
myService.fetchData().then(function(data) {
console.log(data)
$scope.data = data;
})
});
app.service('myService', function($timeout, $q) {
var arr;
var deferred;
var loadData = function() {
// here comes some data from the server
var serverData = [1,2,3];
arr = serverData;
deferred.resolve(arr);
// simulate a refetch of the data
$timeout(function() {
var newServerData = [4,5,6];
// this won't work, because MainCtrl looses it's reference
// arr = newServerData;
}, 1000);
$timeout(function() {
var newServerData = [7,8,9];
arr.length = 0;
[].push.apply(arr, newServerData);
}, 2000);
$timeout(function() {
var newServerData = [10,11,12];
[].splice.apply(arr, [0, arr.length].concat(newServerData));
}, 3000);
}
return {
fetchData: function() {
deferred = $q.defer();
loadData();
return deferred.promise;
}
}
})
And the view:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="[email protected]" src=".2.16/angular.js" data-semver="1.2.16"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="d in data">{{d}}</li>
</ul>
3 refetches every second
</body>
</html>
Is there any convenient way to replace the content of an array, AND keep a reference to it? I don't want to replace the array like this:
var arr1 = [1,2,3];
var referenceToArr1 = arr1;
var arr2 = [4,5,6];
arr1 = arr2;
// logs: [4,5,6] false
console.log(arr1, arr1===referenceToArr1);
// logs [1,2,3]
console.log(referenceToArr1);
This way arr1
has the content of arr2
, but I loose the reference in referenceToArr1
, because it still points to the original arr1
.
With this way, I don't loose the reference:
var arr1 = [1,2,3];
var referenceToArr1 = arr1;
var arr2 = [4,5,6];
arr1.length = 0;
for (var i = 0; i < arr2.length; i++) {
arr1.push(arr2[i]);
}
// logs: [4,5,6] true
console.log(arr1, arr1===referenceToArr1);
// logs: [4,5,6]
console.log(referenceToArr1)
The drawback here is, that I have to empty arr1.length = 0
, iterate over every element of arr2
and push it to arr1
by hand.
My questions are:
- Sure, I could write a helper for this, but what is the most efficient way?
- Is there a short, vanilla javascript way, to do this (maybe a one liner?)
- I'm also using underscore.js but haven't found a method for this kind of problem. Is there a way to do this with underscore.js?
Background:
I have an AngularJS app with a service. Inside this service, I have an array to keep all the elements loaded from the server. The data from the service get's bind to a controller and is used in a view. When the data from the service get's change (e.g. a refetch happens), I want to auto update my controllers vars and the view it is bind to.
Here is a Plunker: http://plnkr.co/edit/8yYahwDO6pAuwl6lcpAS?p=preview
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, myService) {
$scope.name = 'World';
myService.fetchData().then(function(data) {
console.log(data)
$scope.data = data;
})
});
app.service('myService', function($timeout, $q) {
var arr;
var deferred;
var loadData = function() {
// here comes some data from the server
var serverData = [1,2,3];
arr = serverData;
deferred.resolve(arr);
// simulate a refetch of the data
$timeout(function() {
var newServerData = [4,5,6];
// this won't work, because MainCtrl looses it's reference
// arr = newServerData;
}, 1000);
$timeout(function() {
var newServerData = [7,8,9];
arr.length = 0;
[].push.apply(arr, newServerData);
}, 2000);
$timeout(function() {
var newServerData = [10,11,12];
[].splice.apply(arr, [0, arr.length].concat(newServerData));
}, 3000);
}
return {
fetchData: function() {
deferred = $q.defer();
loadData();
return deferred.promise;
}
}
})
And the view:
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="[email protected]" src="https://code.angularjs.org/1.2.16/angular.js" data-semver="1.2.16"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="d in data">{{d}}</li>
</ul>
3 refetches every second
</body>
</html>
Share
Improve this question
edited May 6, 2014 at 6:09
23tux
asked May 6, 2014 at 5:37
23tux23tux
14.7k16 gold badges96 silver badges194 bronze badges
7
|
Show 2 more comments
3 Answers
Reset to default 13What about this:
// 1. reset the array while keeping its reference
arr1.length = 0;
// 2. fill the first array with items from the second
[].push.apply(arr1, arr2);
See:
- How to empty an array in JavaScript?
- .push() multiple objects into JavaScript array returns 'undefined'
You can use splice to replace the content of arr1
with the one of arr2
:
[].splice.apply(arr1, [0, arr1.length].concat(arr2));
This way, all references to arr1
would be correctly updated as this would be the same array with a new content.
As you see, that's possible and easy. But there's normally no reason to do this in a well designed program. If the reason is that you're passing an array to different places, then perhaps you should consider embedding this array in an object.
This will merge both arrays persisting items from second array
[...arr2, ...arr1.slice(arr2.length)]
arr1.length = 0
(in fact something likearr1.clear()
) is the trick which solved lot of similar stuff for me – Radim Köhler Commented May 6, 2014 at 6:16