再探js数组遍历

今天又看了一遍js高程的数组迭代方法,看到书中介绍ECMA5中的5个迭代方法都不会改变数组中包含的值。然后突然想到平时在做业务的时候经常有从接口拿数据,数据拿过来就一个遍历处理,然后遍历后的数组在渲染到页面。诶,按照这个习惯,数组的值似乎是被改变了呢!
干想也想不通,还是到浏览器下来输出下结果会比较直观。

var arr = [1, 2, 3];

arr.forEach(function(v) {
    v += 1;
});

console.log(arr); //[1, 2, 3]

咦?似乎是不变的呢!好像平时都在处理对象数组吧?好,那就上对象数组!

var arr = [
    {a: 1},
    {a: 2},
    {a: 3}
];

arr.forEach(function(v) {
    v.a += 1;
});

console.log(arr); // [{a: 2},{a: 3},{a: 4}]

这就尴尬了!对象数组内的属性值都变了!但js高程对迭代方法的讲解篇幅比较短,也没有作深入讨论,好吧,去看下源码实现吧。

if (!Array.prototype.forEach) {

  Array.prototype.forEach = function(callback, thisArg) {

    var T, k;

    if (this == null) {
      throw new TypeError(' this is null or not defined');
    }

    var O = Object(this);

    var len = O.length >>> 0;

    if (typeof callback !== "function") {
      throw new TypeError(callback + ' is not a function');
    }

    if (arguments.length > 1) {
      T = thisArg;
    }

    k = 0;

    while (k < len) {

      var kValue;

      if (k in O) {

        kValue = O[k];

        callback.call(T, kValue, k, O);
      }
 
       k++;
    }
    
  };
}

callback.call(T, kValue, k, O)每次回调会把对应的数组项传参进去,诶,传参,我似乎明白了。之前写过一个js传参的方式,还是印象深刻。
js是按值传递参数的,或者按共享传参的说法去理解,当传递的是基本数据类型时,复制一份给参数,回调里面对参数做了什么,外面的数组项还是原来的值。
而如果传递的是引用类型参数,也是会复制一份对象作为参数,但这时候的参数和回调外的数组项指向的是同一个堆内存,好了,回调对它做了什么,外面的数组项也反应了出来。
数组遍历的话题又回到了函数传参问题!
我又去试了其他几个遍历方法,当用every时情况又有所不一样。

var arr = [
    {a: 1},
    {a: 2},
    {a: 3}
];

arr.every(function(v) {
    v.a += 1;
});

console.log(arr); // [{a: 2},{a: 2},{a: 3}]

再去看书对every()方法的解释:对数组的每一项运行给定的函数,如果该函数对每一项都返回true,则返回true。
看完,我猜想这个every的实现应该是遍历每一项,只要有一项没有返回true就会直接中断函数,返回false。
还是去看看源码(易读版):


Array.prototype.every = function(fun /*, thisp*/) {
    var len = this.length;
    if (typeof fun != "function")
        throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
        if (i in this && !fun.call(thisp, this[i], i, this))
        return false;
    }

    return true;
};

再回头看看我写的js里面,只对每项的a属性值作了+1处理,没有任何返回值,那么js函数在没有返回值的时候,会如何处理返回值呢?
再来看个小实验:

function returnT(a) {
    a += 1;
    return true;
}

function returnNull(a) {
    a += 1;
}

console.log(!!returnT(1)); // true
console.log(!!returnNull(1)); // false

也就是说,当函数没有任何返回值的时候,函数会默认返回false;
ok,再结合every的源码一看,秒懂。

posted @ 2016-11-18 14:06  走叉文武  阅读(575)  评论(0编辑  收藏  举报