重写 Javascript filter / forEach

Rewriting Javascript filter / forEach

Javascript 的新手 - 我正在尝试重写 forEach 和过滤器以理解它们。我希望能够使用过滤器来传递类似 {"hello": 4, "world": 2, "hi": 1} 的内容,并能够根据数字进行过滤。

这是我的 forEach:

function myForEach(collection, callback) {

      if (Array.isArray(collection)) {
        for (var i = 0; i < collection.length; i++) {
          callback(collection[i]);
        }
      }
      else {
        for (var key in collection) {
          callback(collection[key]);
        }
      }
    }

这是过滤器:

function filterWithForEach (collection, predicate) {
  if (Array.isArray(collection)) {
    var newArray = [];
    myForEach(collection, function (element) {
      if (predicate(element)) {
        newArray.push(element);
      }
    });
    return newArray;
  }
  else {
    var newCollection = {};
    myForEach(collection, function (element) {
      if (predicate(element)) {
        newCollection[element] = element; //here's where I think it's wrong
      }
    });
    return newCollection;
  }
}

我知道问题在于我如何分配它们,因为当我测试它时我得到这些输出:

console.log(filterWithForEach([1,2,3,4,5], function(num) {
  return num > 2;
})); // works fine
console.log(filterWithForEach(aList, function(item) {
  return item > 3;
})); // provides {4: 4}..

如果你想知道他们做什么,the spec is fairly clear and can pretty reasonably be turned into JavaScript code (in fact, that's been done on MDN)。

你的和 JavaScript 的一些区别:

  1. JavaScript的forEachfilter不要使用for-in,这是你和JavaScript的根本区别。他们只使用对象和数组索引,期望对象是一个 类数组 (例如,有一个 length 和带有 "0" 等键的属性, "1",依此类推[是的,所有的键都是字符串,甚至是标准数组中的键,它们根本不是真正的数组]。

  2. JavaScript 的版本不会为不存在的条目调用回调(例如,在稀疏数组的情况下)。要将其添加到您的,您需要在某个阶段添加 hasOwnProperty(index)

  3. JavaScript 的版本将更多参数传递给回调。

  4. JavaScript 的版本允许您在调用回调时指定一个值作为 this 使用。

  5. JavaScript的版本在开始前就抢了长度,所以如果修改了collection,还是用旧的长度。根据更改的位置,条目可能会被跳过。

例如,您对 forEach 的看法可能更像是这样:

function myForEach(collection, callback, thisArg) {
    var l = +collection.length;
    for (var i = 0; i < l; i++) {
        if (collection.hasOwnProperty(i)) {
            callback.call(thisArg, collection[i], i, collection);
        }
    }
}

同样,不是(远程)规范中算法的准确实现,只是对您的算法稍作修改以解决我上面提出的具体点。

如果您正在寻找要返回的对象,那么这就是它应该的方式。

function myForEach(collection, callback) {

      if (Array.isArray(collection)) {
        for (var i = 0; i < collection.length; i++) {
          callback(collection[i]);
        }
      }
      else {
        for (var key in collection) {
          callback(collection[key], key);
        }
      }
    }

这是过滤器:

function filterWithForEach (collection, predicate) {
  if (Array.isArray(collection)) {
    var newArray = [];
    myForEach(collection, function (element) {
      if (predicate(element)) {
        newArray.push(element);
      }
    });
    return newArray;
  }
  else {
    var newCollection = {};
    myForEach(collection, function (element,key) {
      if (predicate(element)) {
        newCollection[key] = element;           }
    });
    return newCollection;
  }
}

您可以在 Array 原型函数中创建一个过滤器自己的方法。如果您正在寻找不同的方法,您可以使用迭代器和这样的递归函数:

Array.prototype.megaFilter = function(cb) {
  const iterator = this[Symbol.iterator]();
  const iteration = iterator.next();
  const filteredArray = [];
  iterate(iteration);
  function iterate(iteration) {
    if (iteration.done) return iteration;
    if (cb(iteration.value)) filteredArray.push(iteration.value);
    const nextIteration = iterator.next(iteration.value);
    return iterate(nextIteration);
  }
  return filteredArray;
};

const array = [1, 2, 3, 4, 5, 6, 7];

console.log(array.megaFilter(v => v % 2 === 0));

大纲就到这里了,欢迎大家多提意见: https://gist.github.com/jdtorregrosas/d69f67e8079f82fbc2a5904e76a8fb6c