foreach循环内的JavaScript拼接函数递减索引

时间:2013-06-02 15:58:51

标签: javascript angularjs

$scope.clearCompleted = function()
        {
            angular.forEach($scope.todos, function(todo, i)
            {
                if(todo.done)
                {
                    $scope.todos.splice(i, 1);
                }
            });

            if($scope.todos.length == 0)
            {
                $scope.isEmpty = true;
            }
        }

这是我从数组中删除'done'待办事项的代码, 但是当两个相互之后的todos被移除时,它只会移除第二个。 我认为这是因为splice函数重置并返回拼接数组。

5 个答案:

答案 0 :(得分:18)

您从迭代的数组中拼接元素,因此“todos”中的索引减少了。对不起,我的英语不好。

var notDonedTodos = [];
angular.forEach($scope.todos, function(todo, i)
{
    if(!todo.done)
    {
       notDonedTodos.push(todo);
    }
});

$scope.todos = notDonedTodos;

答案 1 :(得分:18)

这种情况正在发生,因为forEach只知道数组的初始状态,因此调用您的方法两次,即使第一次调用从数组中删除了一个项目。只需做一个简单的while循环:

var i = $scope.todos.length;
while (i--){
    if ($scope.todos[i].done){
        $scope.todos.splice(i, 1);
    }
}

答案 2 :(得分:7)

替代方案我发现自己是使用array.filter方法。这是基于对象键过滤数组的最简单方法。如果你正在开发一个IE8项目(你很差),你需要为这个函数添加一个polyfill,因为它对于JavaScript来说还算新。

Everything you need to know about javascript

答案代码:

$scope.clearCompleted = function() {
    $scope.todos = $scope.todos.filter(function(item) {
        return !item.done;
    });
}

答案 3 :(得分:3)

each迭代的问题是它从数组中删除了一个项,导致跳过迭代。 jQuery有一个很好的grep方法,它返回所有符合特定条件的元素,这些元素由提供的匿名函数确定。

var todos =[{id:1, done:false},{id:2, done:true},{id:3, done:true}];

function removeCompleted(todos){
    return $.grep(todos,function(todo){
        return todo.done == false;
    });
}

todos = removeCompleted(todos);
console.log(todos);

工作示例 http://jsfiddle.net/ktCEN/

Documentation

答案 4 :(得分:2)

作为另一种选择,您可以在每次执行splice时减少索引。例如:

$scope.clearCompleted = function() {
    angular.forEach($scope.todos, function(todo, i) {
        if(todo.done) {
            $scope.todos.splice(i, 1);
            i--;
        };
    });

    if($scope.todos.length == 0) {
        $scope.isEmpty = true;
    };
}

每次修改数组时,都会调整索引以保持其有效性。您仍然可以使用angular.forEach,并且最终不会得到阵列的两个副本。