ECMAScript5新增Array方法的实现(续)

前言

继上一篇谈到ES5新增Array的迭代方法forEach后,今天来分析下余下的迭代方法:map、filter、every、some。这些方法的作用如下:

  • map方法是对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
  • filter方法是对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
  • every方法是对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
  • some方法是对数组中的每一项运行给定函数,如果该函数对任意一项返回true,则返回true。

注:以上的方法都不会修改数组中的包含的值,并且这些方法中,最相似的是every和some,它们都用于查询数组中的项是否满足某个条件。对every来说,传入的函数必须对每一项都返回true,这个方法才返回true。而some方法则是只要传入的函数对数组中的某一项返回true,就会返回true。

 

使用示例

var numbers = [1, 2, 3, 4, 5];
// map方法--返回一个新的数组,该新数组的每一项都是在原始数组中的对应项上运行传入函数的结果
console.log(numbers.map(function(item, index, array) {
    return item * 2; // [2, 4, 6, 8, 10]
}));
// filer方法--查询符合条件的数组项
console.log(numbers.filter(function(item, index, array) {
    return (item > 2); // [3, 4, 5]
}));
// every方法
console.log(numbers.every(function(item, index, array) {
    return (item > 2); // false
}));
// some方法
console.log(numbers.some(function(item, index, array) {
    return (item > 2); // true
}));

firefox下测试结果:

以上只是一些简单的例子,并且可选的参数(作用域对象)没有传入。虽然在某些情况下使用这些方法处理数组的任务很方便,但是支持这些迭代方法的浏览器只有IE9+、Firefox 2+、Safari 3+、Opera 9.5+和Chrome。所以为了兼容可恶的IE6+,我们不得不进行一些兼容性的处理,可以对Array原型进行扩展,让扩展的这些方法适用于大部分浏览器,并且作用是类似于ES5新增的迭代方法。

 

Array原型扩展

对于如何在Array原型上扩展这些方法以及这些方法具体有哪些参数就不多说了,可以查找之前的一篇forEach方法实现的blog。下面一个个来实现:

1、map:该方法可以理解为映射,即原数组被“映射”成对应的新数组。

实现代码:

/**
 * map
 * @param {Function}  回调函数
 * @param {Object} 作用域对象(环境)
 * @return {Array} 新的数组
 */
if (!Array.prototype.map && typeof Array.prototype.map !== "function") {
     Array.prototype.map = function(callback, context) {
        // 遍历数组,在每一项上调用回调函数,这里使用原生方法验证数组。
        if (Object.prototype.toString.call(this) === "[object Array]") {
            var i,
                len,
                arr = [];
                if (typeof callback === "function") {
                    for (i = 0, len = this.length; i < len; i++) {
                        arr.push(callback.call(context, this[i], i, this));
                    }
                }
                
            return arr; // 返回匹配的新数组
        }
     };
}

demo示例(所有浏览器测试已通过,包括IE6+)

// map方法示例1
var mapResult1 = [1, 2, 3, 4].map(function(value, index, array) {
    return value * value;
});
alert(mapResult1); // [1, 4, 9, 16]

// map方法示例2-传入作用域对象context
var data = {
    numbers: [1, 2, 3, 4],
    getNumber: function(value, index, array) {
        return value * value;
    }
};
var mapResult2 = data.numbers.map(data.getNumber, data);
alert(mapResult2); // [1, 4, 9, 16]

 

2、filter:该方法可以理解为过滤或者筛选返回过滤后的新数组。用法跟map极为相似。

实现代码:

/**
 * filter--用于过滤筛选数组的项,并返回新的数组。
 * @param {Function}  回调函数
 * @param {Object} 作用域对象(环境)
 * @return {Array} 新的数组
 */
if (!Array.prototype.filter && typeof Array.prototype.filter !== "function") {
     Array.prototype.filter = function(callback, context) {
        // 遍历数组,在每一项上调用回调函数,这里使用原生方法验证数组。
        if (Object.prototype.toString.call(this) === "[object Array]") {
            var i,
                len,
                arr = [];
                if (typeof callback === "function") {
                    for (i = 0, len = this.length; i < len; i++) {
                        // 把匹配的项添加到数组中
                        callback.call(context, this[i], i, this) && arr.push(this[i]);
                    }
                }
                
            return arr; // 返回新的数组
        }
     };
}

demo示例(所有浏览器测试已通过,包括IE6+)

// filter方法示例1
var filterResult1 = [1, 2, 3, 4].filter(function(value, index, array) {
    return (value > 2);
});
alert(filterResult1); // [3, 4]

// filter方法示例2-传入作用域对象context
var data = {
    numbers: [1, 2, 3, 4],
    getNumber: function(value, index, array) {
        return (value > 2);
    }
};
var filterResult2 = data.numbers.filter(data.getNumber, data);
alert(filterResult2); // [3, 4]

如FF下测试结果截图:

 

3、every:该方法对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。

 实现代码:

/**
 * every
 * @param {Function}  回调函数
 * @param {Object} 作用域对象(环境)
 * @return {Boolean} true || false
 */
if (!Array.prototype.every && typeof Array.prototype.every !== "function") {
     Array.prototype.every = function(callback, context) {
        // 遍历数组,在每一项上调用回调函数,这里使用原生方法验证数组。
        if (Object.prototype.toString.call(this) === "[object Array]") {
            var i,
                len,
                isRight = true; // 默认所有数组项运行给定函数都为true
                
                if (typeof callback === "function") {
                    for (i = 0, len = this.length; i < len; i++) {
                        if (isRight === false) {
                            break; // 跳出循环,终止执行
                        } else {
                            isRight = Boolean(callback.call(context, this[i], i, this));
                        }
                    }
                }
                
            return isRight; // 返回Boolean值
        }
     };
}

demo示例(所有浏览器测试已通过,包括IE6+)

// every方法示例1
var everyResult1 = [1, 2, 3, 4].every(function(value, index, array) {
    return (value > 2);
});
alert(everyResult1); // false

// every方法示例2-传入作用域对象context
var data = {
    numbers: [1, 2, 3, 4],
    getNumber: function(value, index, array) {
        return (value > 2);
    }
};
var everyResult2 = data.numbers.every(data.getNumber, data);
alert(everyResult2); // false

 

4、some:该方法对数组中的每一项运行给定函数,如果该函数对任意一项返回true,则返回true;否则返回false。

实现原理和every一致,只需修改一个变量isRight的值即可,其js代码如下所示:

/**
 * some
 * @param {Function}  回调函数
 * @param {Object} 作用域对象(环境)
 * @return {Boolean} true || false
 */
if (!Array.prototype.some && typeof Array.prototype.some !== "function") {
     Array.prototype.some = function(callback, context) {
        // 遍历数组,在每一项上调用回调函数,这里使用原生方法验证数组。
        if (Object.prototype.toString.call(this) === "[object Array]") {
            var i,
                len,
                isRight = false; // 默认所有数组项运行给定函数都为false
                
                if (typeof callback === "function") {
                    for (i = 0, len = this.length; i < len; i++) {
                        if (isRight === true) {
                            break; // 跳出循环,终止执行
                        } else {
                            isRight = Boolean(callback.call(context, this[i], i, this));
                        }
                    }
                }
                
            return isRight; // 返回Boolean值
        }
     };
}

demo示例(所有浏览器测试已通过,包括IE6+)

// some方法示例1
var someResult1 = [1, 2, 3, 4].some(function(value, index, array) {
    return (value > 2);
});
alert(someResult1); // true

// every方法示例2-传入作用域对象context
var data = {
    numbers: [1, 2, 3, 4],
    getNumber: function(value, index, array) {
        return (value > 2);
    }
};
var someResult2 = data.numbers.some(data.getNumber, data);
alert(someResult2); // true

呼呼(~ o ~)~zZ,终于测试完了,尼玛,太阳都落山了。例子其实都大同小异,关键是实现思路搞懂就不会很难了。还有值得注意的是:调用这些方法的参数的含义以及顺序。

 

结语

 以上针对ES5新增数组的迭代方法进行了相应的扩展,目的是当使用这些方法时,不用考虑兼容性的问题,当然代码性能方面没有考虑到。今天就到此为止了,有问题或建议的欢迎各路人马点评。ps:最近快要考试了,blog暂且一段时间都没时间写了,╮(╯▽╰)╭。

posted @ 2013-06-07 18:03  chmyun  阅读(817)  评论(2编辑  收藏  举报