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

javascript - How to "undo" a deleted element with splice? - Stack Overflow

programmeradmin1浏览0评论

When I have an array and I use splice to remove, let's say, the last element of the array. Is there a chance to create for example a button and when I click on it, it undoes the deleted action? Like using Ctrl + Z when write code and jump back in time? That means give me back the deleted element with all its characteristics?

When I have an array and I use splice to remove, let's say, the last element of the array. Is there a chance to create for example a button and when I click on it, it undoes the deleted action? Like using Ctrl + Z when write code and jump back in time? That means give me back the deleted element with all its characteristics?

Share Improve this question edited Mar 20, 2017 at 21:17 Heretic Monkey 12.1k7 gold badges61 silver badges131 bronze badges asked Mar 20, 2017 at 20:42 Derick KollnDerick Kolln 6339 silver badges20 bronze badges 7
  • 1 The 'deleted' element has to e back in exactly the same position as before the deletion? – kind user Commented Mar 20, 2017 at 20:43
  • 2 why not to have an array of objects with one key to be "active" and instead of splicing, just set it false – binariedMe Commented Mar 20, 2017 at 20:45
  • 1 @binariedMe This idea may be fine. Another question - does this array include duplicates? – kind user Commented Mar 20, 2017 at 20:49
  • 1 Instead one can always go for saving the spliced elements in a trash array with its index, preserved. and thats how you can always undo it accordingly. Although you have to be careful with reinsertion of element in the original array. – binariedMe Commented Mar 20, 2017 at 20:50
  • 1 @DerickKolln Check my answer. – kind user Commented Mar 20, 2017 at 21:13
 |  Show 2 more ments

4 Answers 4

Reset to default 4

Array.splice allows you to delete or insert elements, it also returns the removed elements when deleting. If you capture the deleted elements you can easily add them back:

let arr = [1,2,3,4,5,6];
// remove 1 element from index 1 ("2")
let removed = arr.splice(1, 1);
// add "2" back to position 1
arr.splice(1, 0, ...removed);

console.log(arr);

If you don't have access to ES6's spread operator, you could use .shift() to get the first element out of removed:

let arr = [1,2,3,4,5,6];
// remove 1 element from index 1 ("2")
let removed = arr.splice(1, 1);
// add "2" back to position 1
arr.splice(1, 0, removed.shift());

console.log(arr);

I'd be tempted to wrap your arrays in some kind of undoable utility. For example:

function undoable(value) {
  let history = [value];

  return {
    value() {
      return history[history.length - 1];
    },
    update(func) {
      let copy = [...this.value()];
      func(copy);
      history.push(copy);
      return copy;
    },
    undo() {
      history.pop();
      return this.value();
    }
  }
}

You could use this to handle undo behaviour.

let array = undoable([]);

array.update(arr => arr.push(2));
// [2]

array.update(arr => arr.push(3));
// [2, 3]

array.undo();
// [2]

You could make this even safer and more generic if you treat the values as immutable during the calls to update. At that point you wouldn't need to defensively copy your array before passing it to func. However, it would require you to use methods like filter and slice instead of splice.

Clicking on the Delete random item button will result in deletion of a random element from the arr array. The deleted element is being stored inside the deleted array.

Clicking on the Undo deletion button will move the deleted element back into the arr array, into the same position.

var arr = [5,1,2,6,4,8,0,7],
    stored = arr.slice(),
    deleted = [],
    btn = document.getElementById('deleteBtn'),
    undoBtn = document.getElementById('undoBtn');
    
    btn.addEventListener('click', function(){
      var randomElem = Math.floor(Math.random() * arr.length),
          deleteElem = arr.splice(randomElem, 1);
          deleted.push(...deleteElem);
          console.log(arr);
          console.log(deleteElem);
    });
    
    undoBtn.addEventListener('click', function(){
      if (arr.length >= 0 && arr.length < stored.length){
        var elem = deleted[deleted.length-1],
            index = stored.indexOf(elem);
            arr.splice(index, 0, elem);
            deleted.pop();
            console.log(arr);
      }
    });
    
console.log(arr);
<button id='deleteBtn'>Delete random item</button>
<button id='undoBtn'>Undo deletion</button>

If you only need one level of undo, you can just copy the array before deletion. If the user wants to "undo" then revert the array back to its previous incarnation.

var arr = [1,2,3,4,5,6];
var tempArr;

function removeThing(arr, index) {
   tempArr = arr;
   arr.splice(index, 1);
}

function undo() {
    arr = tempArr;
}
发布评论

评论列表(0)

  1. 暂无评论