Array.prototype.every
以下代码均来自:MDN
- every函数测试数组的每一个元素是否通过测试,此方法并不一定会遍历全部的元素,它的执行机制是遇到未通过测试的项则立即返回false,如果全部通过测试则返回true
- every函数并不改变原数组
- 空数组对任何检测回调函数都返回true(空数组中所有元素都符合给定的条件,注:因为空数组没有元素)
这个解释还真绕- 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
- some函数也不一定会遍历所有的项,当遇到符合条件的第一个项时就会返回true退出遍历
- some不会改变原数组
- 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
- find函数也未必会遍历所有的元素项,当遇到符合条件的元素项时,就会立刻返回这个元素项,并不再继续遍历后面的元素,如果遍历完所有的项没有符合要求的值则返回undefined
- find不会改变原来的数组
- 在第一次调用 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,有点匪夷所思
*/