使用参数的JavaScript过滤器回调

dot*_*dot 1 javascript

目标是过滤数组并删除其参数列表中指定的所有元素.

例如,给定removeElements([1,2,3,1,2,3,4],2,3),我的输出应为[1,1,4].

function removeElements(arr) {
//I got an error that says **functions** not allowed **inside loop**
  for(var i=1;i<arguments.length;i++){
    arr= arr.filter(function(e){
        return e!==arguments[i];
    });
  }
  return arr;
}
Run Code Online (Sandbox Code Playgroud)

我尝试的第二件事是将过滤器移出for循环.

function removeElements(arr) {
  function isNotEqual(e){
    return e!==this;
  }
  for(var i=1;i<arguments.length;i++){
    arr= arr.filter(isNotEqual,arguments[i]);
  }
  return arr;
}
Run Code Online (Sandbox Code Playgroud)

他们都没有工作.它总是返回[1,2,3,1,2,3,4].你能告诉我用法有什么问题吗?或者在这种情况下使用过滤器的方法是什么?

arc*_*rty 9

您可以使用Array.prototype.slice以阵列形式获取列入黑名单的元素.

然后使用Array.prototype.indexOf查看给定元素是否在数组中用于过滤函数.

http://jsfiddle.net/Loothof7/

function removeElements(arr) {
  var blacklist = Array.prototype.slice.call(arguments, 1);
  return arr.filter(function(e) {
    return blacklist.indexOf(e) == -1;
  });
}

alert(removeElements([1, 2, 3, 1, 2, 3,4], 2, 3));
Run Code Online (Sandbox Code Playgroud)

请注意,Function.prototype.callArray.prototype.slicethisscope参数一起使用arguments而不是直接调用,arguments.slice因为arguments它实际上不是"真正的"数组.


Jon*_*ski 5

尝试解释片段未成功的原因:

  1. 每个函数都定义了自己的arguments,即使该函数是嵌入的。

    function removeElements(arr) {
        console.log(arguments);
        // Arguments {
        //   0: Array [1, 2, 3, 1, 2, 3, 4],
        //   1: 2,
        //   2: 3
        // }
    
        arr = arr.filter(function (e) {
            console.log(arguments);
            // Arguments {
            //   0: 1, 2, 3, 1, ...             (each value in `arr`)
            //   1: 0, 1, 2, 3, ...             (each index)
            //   2: Array [1, 2, 3, 1, 2, 3, 4] (`arr` itself)
            // }
    
            // ...
        });
    
        return arr;
    }
    
    removeElements([1, 2, 3, 1, 2, 3, 4], 2, 3);
    
    Run Code Online (Sandbox Code Playgroud)

    通过从arguments迭代器 ( function(e) {...})内部检索值,该语句将e与第二个参数中的值进行比较。

    for(var i=1;i<arguments.length;i++){
        arr = arr.filter(function(e){
            // 1st = 0              (the first index from `arr`)
            // 2nd = [1, 2, 3, ...] (the `arr` itself)
            console.log(arguments[i]);
    
            return e!==arguments[i];
        });
    }
    
    Run Code Online (Sandbox Code Playgroud)

    解决此问题的一种选择是访问arguments迭代器函数之外,将值存储在不会有相同冲突的变量中:

    for(var i=1;i<arguments.length;i++){
        var skip = arguments[i];
        arr = arr.filter(function (e) {
            return e !== skip;
        });
    }
    
    Run Code Online (Sandbox Code Playgroud)

    http://jsfiddle.net/y7evq6nq/

  2. 如果您不使用严格模式,则的值this将始终是一个对象。

    当您为 a 提供原始值时thisArg,它将被装箱到其等效的 Object 类型中。在这种情况下,一个new Number.

    function foo() {
        console.log(typeof this, this); // 'object' Number(3)
        return true;
    }
    
    [0].filter(foo, 3);
    
    Run Code Online (Sandbox Code Playgroud)

    而且,由于===首先检查类型是否相等,原始数和装箱数不能相等:

    var number = 3;
    var boxedNumber = new Number(3);
    
    console.log(typeof number);      // 'number'
    console.log(typeof boxedNumber); // 'object'
    
    console.log(typeof number === typeof boxedNumber); // false
    console.log(number === boxedNumber);               // false
    
    Run Code Online (Sandbox Code Playgroud)

    您可以使用该.valueOf()方法从对象中检索原始值。

    function isNotEqual(e){
      return e!==this.valueOf();
    }
    
    Run Code Online (Sandbox Code Playgroud)

    http://jsfiddle.net/ow9b78bf/

    或者,您可以尝试使用严格模式,它允许this保存原始值而不对其进行装箱。