JavaScript不清不楚之遍历

Array.prototype.every

以下代码均来自:MDN

  1. every函数测试数组的每一个元素是否通过测试,此方法并不一定会遍历全部的元素,它的执行机制是遇到未通过测试的项则立即返回false,如果全部通过测试则返回true
  2. every函数并不改变原数组
  3. 空数组对任何检测回调函数都返回true(空数组中所有元素都符合给定的条件,注:因为空数组没有元素)
    这个解释还真绕
  4. IE9+支持
if (!Array.prototype.every)
{
  Array.prototype.every = function(fun /*, thisArg */)
  {
    'use strict';

    //用void 0是为了防止undefined被重写而出现判断不准确的情况
    //过滤undefined和null
    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    //检测传入的参数类型
    if (typeof fun !== 'function')
        throw new TypeError();

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      //用(值,索引,数组)参数来调用回调函数,如果回调函数返回false则立即return false退出
      if (i in t && !fun.call(thisArg, t[i], i, t))
        return false;
    }
    //全部通过测试则返回true
    return true;
  };
}

Array.prototype.some

  1. some函数也不一定会遍历所有的项,当遇到符合条件的第一个项时就会返回true退出遍历
  2. some不会改变原数组
  3. some 遍历的元素的范围在第一次调用 callback. 时就已经确定了。在调用 some 后被添加到数组中的值不会被 callback 访问到。如果数组中存在且还未被访问到的元素被 callback 改变了,则其传递给 callback 的值是 some 访问到它那一刻的值。未被遍历的元素被动态删除后是不会被访问的
// Production steps of ECMA-262, Edition 5, 15.4.4.17
// Reference: http://es5.github.io/#x15.4.4.17
if (!Array.prototype.some) {
  Array.prototype.some = function(fun/*, thisArg*/) {
    'use strict';
    //过滤undefined和null
    if (this == null) {
      throw new TypeError('Array.prototype.some called on null or undefined');
    }
    //检测传入的参数类型
    if (typeof fun !== 'function') {
      throw new TypeError();
    }

    var t = Object(this);
    var len = t.length >>> 0;

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++) {
      //用(值,索引,数组)参数来调用回调函数,如果回调函数返回true则立即return true退出
      if (i in t && fun.call(thisArg, t[i], i, t)) {
        return true;
      }
    }
    //如果没有元素通过测试,则返回false
    return false;
  };
}
//改变数组中的项
[1,2,3,4,5].some(function(v, i, arr){
    if(v % 2 === 0){
        //被改变的值,会按改变后的值检测
        ++arr[i + 1];
        //后来动态添加的元素项,不会参与测试
        arr.push(20)
    }
    console.log(arr)
    return v > 10;
})
/*
    VM88:6 (5) [1, 2, 3, 4, 5]
    VM88:6 (6) [1, 2, 4, 4, 5, 20]
    VM88:6 (7) [1, 2, 4, 5, 5, 20, 20]
    VM88:6 (7) [1, 2, 4, 5, 5, 20, 20]
    VM88:6 (7) [1, 2, 4, 5, 5, 20, 20]
    false
*/
//判断两个数组是否有交集
function isIntersection(arr1, arr2){
    return arr1.some(function(v, i, arr1){
        return arr2.some(function(vv, ii, arr2){
            return v === vv
        });
    });
}

Array.prototype.find

  1. find函数也未必会遍历所有的元素项,当遇到符合条件的元素项时,就会立刻返回这个元素项,并不再继续遍历后面的元素,如果遍历完所有的项没有符合要求的值则返回undefined
  2. find不会改变原来的数组
  3. 在第一次调用 callback 函数时会确定元素的索引范围,因此在 find 方法开始执行之后添加到数组的新元素将不会被 callback 函数访问到。如果数组中一个尚未被callback函数访问到的元素的值被callback函数所改变,那么当callback函数访问到它时,它的值是将是根据它在数组中的索引所访问到的当前值。被删除的元素仍旧会被访问到。
    此处第三条是mdn上的原话,但是我在尝试之后发现如果先动态的添加一个元素,然后再把此元素动态的删除,这个元素被遍历了,不知道这个是不是bug
// https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    value: function(predicate) {
     // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      //决定以谁的名义调用回调函数
      var thisArg = arguments[1];

      // 5. Let k be 0.
      var k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return kValue.
        var kValue = o[k];
        //如果以(thisArg, kValue, kindex, arr)调用检测函数返回了true则直接返回这个kValue,否则继续循环
        if (predicate.call(thisArg, kValue, k, o)) {
          return kValue;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return undefined.
      return undefined;
    }
  });
}
[1,2,3,4,5].find(function(v, i, arr){
    if(v % 2 === 0){
        //被改变的值,会按改变后的值检测
        ++arr[i + 1];
        //后来动态添加的元素项,不会参与测试
        arr.pop();
        arr.push(20)
    }
    console.log(arr)
    return v > 10;
})
/*
    VM344:9 (5) [1, 2, 3, 4, 5]
    VM344:9 (5) [1, 2, 4, 4, 20]
    VM344:9 (5) [1, 2, 4, 5, 20]
    VM344:9 (5) [1, 2, 4, 5, 20]
    VM344:9 (6) [1, 2, 4, 5, 20, 20]
    20  这里最后居然输出了20,有点匪夷所思
*/

猜你喜欢

转载自blog.csdn.net/qq452981462/article/details/80903951