Pergunta

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="angular.js@1.2.x" 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>
Foi útil?

Solução

What 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:

  1. How to empty an array in JavaScript?
  2. .push() multiple objects into JavaScript array returns 'undefined'

Outras dicas

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)]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top