JavaScript学习笔记: 数组迭代方法

发布于 大漠

使用数组总是会碰到数组的遍历(迭代)操作。说到迭代,可能会立马想起for语句对数组进行迭代。比如需要迭代出下面数组peoples年龄(age)大于30的人名(name)。

var peoples = [
    {
  		name: 'Agraj',
  		gender:'M',
  		age: 29,
  		address:
  		{
  			city: 'Delhi',
  			pincode: '110064'
  		}
  	},
  	{
  		name: 'Mark',
  		gender:'M',
  		age: 35,
  		address:
  		{
  			city: 'West Bengal',
  			pincode: '220013'
  		}
  	},
  	{
  		name: 'Lance',
  		gender:'M',
  		age: 39,
  		address:
  		{
  			city: 'Chandigarh',
  			pincode: '201201'
  		}
  	},
  	{
  		name: 'Vikas',
  		gender:'M',
  		age: 21,
  		address:
  		{
  			city: 'Noida',
  			pincode: '201301'
  		}
  	},
  	{
  		name: 'Kanika',
  		gender:'F',
  		age: 21,
  		address:
  		{
  			city: 'Noida',
  			pincode: '201301'
  		}
  	}
];

for (var i = 0; i < peoples.length; i++ ) {
    if (peoples[i].age > 30) {
        console.log(peoples[i].name + ':' + peoples[i].age);
    }
}

Chrome浏览器输出的结果:

Mark:35
Lance:39

其实ES5为数组定义了五个迭代方法:

  • forEach():没有返回值,只是针对每个数组项调用指定的函数(callbackfn)
  • every(): 返回一个布尔值(truefalse),判断每个数组项是否符合指定函数的条件,符合为true,反之为false
  • some(): 返回一个布尔值(true或false),判断每个数组项是否符合指定函数的条件,只要有任何一项返回为true,就会返回true
  • filter(): 每个数组项调用指定的函数,条件为true的将返到一个新数组中
  • map(): 每个数组项调用指定的函数,返回每次函数调用的结果组成一个新数组

这五个数组迭代的方法中,其中forEach()every()some()方法不生成一个新数组,而filter()map()方法将会生成一个新数组(符合条件)。并且这些方法都会调用指定的函数callbackfn。回调函数callbackfn语法如下:

function callbackfn (value, index, array) {...}

可以使用三个参数来声明回调函数callbackfn:

  • value: 数组元素的值
  • index: 数组元素在数组中的索引值
  • array: 包含该元素的数组对象

今天主要一起了解这五个数组迭代方法是如何使用?在接下来的内容中都将以开头的数组为例。

forEach()方法

forEach() 方法让数组的每一项都执行一次给定的函数。

语法

array.forEach(callbackfn[, thisArg])

参数

参数 说明
array 必选。一个数组对象。比如示例中的peoples数组
callbackfn 必选。最多可以接受三个参数的函数。对于数组中的每个元素,forEach 都会调用 callbackfn 函数一次。
thisArg 可选。 callbackfn 函数中的 this 关键字可引用的对象。如果省略 thisArg,则 undefined 将用作 this 值。

forEach() 方法按升序为数组中含有效值的每一项执行一次callbackfn 函数,那些已删除或者从未赋值的项将被跳过(但不包括哪些值为 undefined 的项)。

示例

开头使用for语句遍历出年龄大于30岁的名称,并且输出peoplenameage。其实使用forEach()方法也可以实现:

peoples.forEach(function (people) {
    if (people.age > 30) {
        console.log(people.name + ':' + people.age);
    }
});

Chrome浏览器输出的结果:

Mark:35
Lance:39

在此基础上,你可以做很多事情,比如说,将数组peoples中的name遍历出来,然后重新创建一个新数组names,可以这样做:

var names = [];
var peoplesDb = peoples.forEach(function (people, index) {
    names.push(people.name);
});
console.log(names); // ["Agraj", "Mark", "Lance", "Vikas", "Kanika"]

内部实现

看看forEach()方法内部实现的方法:

Array.prototype.forEach = 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);
    }
};

every()方法

every() 方法测试数组的所有元素是否都符合指定函数的条件,只要有有一个元素不符合,返回的都会是false

语法

array.every(callbackfn[, thisArg])

every()方法为数组中的每个元素执行一次 callbackfn 函数,直到它找到一个使 callbackfn 返回 false(表示可转换为布尔值 false 的值)的元素。如果发现了一个这样的元素,every() 方法将会立即返回 false。否则,callbackfn 为每一个元素返回 trueevery() 就会返回 truecallbackfn 只会为那些已经被赋值的索引调用。不会为那些被删除或从来没被赋值的索引调用。

示例

还是上面开头的数组,如果每一位的年龄都大于或等于30,就会返回“都大于或等于30岁了”,反之返回“不是所有人都大于30岁了”。

function bigAge(ele,index,arr){
    return (ele.age >= 30);
}

var isBigPeople = peoples.every(bigAge);

if (isBigPeople) {
    console.log('都大于或等于30岁了');
} else {
    console.log('不是所有人都大于30岁了');
}

Chrome浏览器输出的结果:

// 不是所有人都大于30岁了

内部实现

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;
};

some()方法

some()方法和every()方法类似,不同的是,some()方法在调用指定的函数callbackfn指定的条件符合就会返回true,不符合则返回false

语法

array.some(callbackfn[, thisArg])

示例

只要数组中年龄age有一个大于或等于30,就会返回“有部分人还是年纪大了”,反之返回“你们都还很年轻”:

function OldAge(ele,index,array){
    return (ele.age >= 30);
}

var isOldPeople = peoples.some(OldAge);

if (isOldPeople) {
    console.log('有部分人还是年纪大了');
} else {
    console.log('你们都还年轻');
}

内部实现

Array.prototype.some = 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 true;
    }
 
    return false;
};

map()方法

map()方法返回一个由原数组中的每个元素调用一个指定函数callbackfn后的返回值组成的新数组。如果符合callbackfn会返回符合条件的一个值,将所有返回的值再创建一个新数组。

语法

array.map(callbackfn[, thisArg])

map()方法会给原数组中的每个元素都按顺序调用一次 callbackfn 函数。callbackfn每次执行后的返回值组合起来形成一个新数组。 callbackfn 函数只会在有值的索引上被调用;那些从来没被赋过值或者使用 delete 删除的索引则不会被调用。

示例

使用map()方法遍历数组peoples,并且让index在以前的index增加1:

var usersDb = peoples.map(function (user, index) {
user.id = index + 1; return user; }); console.table(usersDb);

Chrome浏览器输出的结果:

map()方法

内部实现

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

    var res = new Array(len);
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
        if (i in this)
        res[i] = fun.call(thisp, this[i], i, this);
    }

    return res;
};

filter()方法

filter() 方法使用指定的函数callbackfn测试所有元素,并创建一个包含所有通过测试的元素的新数组。

语法

array.filter(callbackfn[, thisArg])

filter() 为数组中的每个元素调用一次 callbackfn 函数,并利用所有使得 callbackfn 返回 true 或 等价于 true 的值 的元素创建一个新数组。callbackfn 只会在已经赋值的索引上被调用,对于那些已经被删除或者从未被赋值的索引不会被调用。那些没有通过 callbackfn 测试的元素会被跳过,不会被包含在新数组中。

示例

遍历出数组中genderM的相关数组项:

var guys = peoples.filter(function (user) {  
    return user.gender === 'M';
});
console.table(guys);  

Chrome浏览器输出的结果:

filter()方法

内部实现

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

    var res = new Array();
    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
        if (i in this)
        {
        var val = this[i]; // in case fun mutates this
        if (fun.call(thisp, val, i, this))
            res.push(val);
        }
    }

    return res;
};

总结

今天主要学习了数组的五个遍历方法:forEach()every()some()map()filter()。其中forEach()every()some()方法不会改变原数组,而map()filter()方法会根据指定的函数callbackfn创建一个新数组。其中filter()方法将符合callbackfn函数条件创建一个新数组,而some()将数组的每一项都是在原数组中的对应项上运行传入的函数callbackfn。另外,every()some()方法根据指定的函数callbackfn返回truefalse值,其中every()方法,只要有一项不符合callbackfn指定的条件就会返回falsesome()方法,将根据callbackfn函数指定的条件,只要符合就返回true,不符合则返回则返回false

初学者学习笔记,如有不对,还希望高手指点。如有造成误解,还希望多多谅解。

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。中国Drupal社区核心成员之一。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.fedev.cn/javascript/array-part-7.htmlnike air max 90 black