最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Short way to replace content of an array - Stack Overflow

programmeradmin0浏览0评论

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
  • See stackoverflow.com/questions/7486085/… – elclanrs Commented May 6, 2014 at 5:38
  • 2 @elclanrs this is exactly the opposite I want to achieve. They are copying arrays into new arrays. I want to replace the content of one array with another array without creating a new array. – 23tux Commented May 6, 2014 at 5:43
  • 1 My intuition tells me this is an XY problem. Why do you need to mutate an array, or a variable like that? What is the real-world use case? – elclanrs Commented May 6, 2014 at 5:45
  • 1 I added some background information and a plunker. I think this is a real world use case, isn't it? – 23tux Commented May 6, 2014 at 6:09
  • 1 @23tux I just have to confirm: it is real world case! ;) had to solve almost the same... and the arr1.length = 0 (in fact something like arr1.clear()) is the trick which solved lot of similar stuff for me – Radim Köhler Commented May 6, 2014 at 6:16
 |  Show 2 more comments

3 Answers 3

Reset to default 13

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'

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)]
发布评论

评论列表(0)

  1. 暂无评论