forEach
const root = this;
Array.prototype.myForEach = function(fn, context) {
// 可选参数, 设置回调中的this指向
context = context || root;
if (typeof fn !== 'function') throw new TypeError('A function is expected on parameter 1');
for (let i = 0, len = this.length; i < len; i++) {
// 不对不存在或已经删除的属性(索引)执行函数
if (Object.prototype.hasOwnProperty.call(this, i)) {
fn.call(context, this[i], i, this);
}
}
}
const names = ['Wango', 'Lily', 'Peter'];
names.myForEach((val, idx, all) => {
console.log(idx, val, all);
});
// 0 Wango [ 'Wango', 'Lily', 'Peter' ]
// 1 Lily [ 'Wango', 'Lily', 'Peter' ]
// 2 Peter [ 'Wango', 'Lily', 'Peter' ]
delete names[2];
console.log(names.length);
// 3
names.myForEach((val, idx, all) => {
console.log(idx, val, all);
});
// 0 Wango [ 'Wango', 'Lily', <1 empty item> ]
// 1 Lily [ 'Wango', 'Lily', <1 empty item> ]
map
Array.prototype.myMap = function(fn, context) {
if (typeof fn !== 'function') throw new TypeError('A function is expected on parameter 1');
const result = Array(this.length);
// 类型判断, context默认值等交由forEach循环处理,
// map只需要保存结果并返回
this.forEach(function(val, idx, all) {
result[idx] = fn.call(this, val, idx, all);
}, context);
return result;
}
const nums1 = [1, 2, 3, 4];
const nums2 = nums1.myMap((val, idx, all) => {
return val * val;
});
console.log(nums1);
// [ 1, 2, 3, 4 ]
console.log(nums2);
// [ 1, 4, 9, 16 ]
filter
Array.prototype.myFilter = function(fn, context) {
if (typeof fn !== 'function') throw new TypeError('A function is expected on parameter 1');
const result = [];
this.forEach(function(val, idx, all) {
// 将满足条件的结果加入新数组
fn.call(this, val, idx, all) && result.push(val);
}, context);
return result;
}
const num1 = [1, 5, 3, 6, 7, 2, 3, 6, 9, 0];
const num2 = num1.myFilter(val => val > 5);
console.log(num1);
// [1, 5, 3, 6, 7, 2, 3, 6, 9, 0]
console.log(num2);
// [ 6, 7, 6, 9 ]
some
const root = this;
Array.prototype.mySome = function(fn, context) {
if (typeof fn !== 'function') throw new TypeError('A function is expected on parameter 1');
context = context || root;
// forEach无法正常中断循环, 使用for代替
// 只要有一个满足条件即可返回true不需要全部遍历
for (let i = 0, len = this.length; i < len; i++) {
if (fn.call(context, this[i], i, this)) return true;
}
return false;
}
const nums1 = [1, -3, 2, 3, 4, -1];
console.log(nums1.mySome(val => val < 0));
// true
console.log(nums1.mySome(val => val === undefined));
// false
delete nums1[1];
console.log(nums1);
// [ 1, <1 empty item>, 2, 3, 4, -1 ]
console.log(nums1.mySome(val => val === undefined));
// true
every
const root = this;
Array.prototype.myEveny = function(fn, context) {
if (typeof fn !== 'function') throw new TypeError('A function is expected on parameter 1');
context = context || root;
// forEach无法正常中断循环, 使用for代替
// 只要有一个不满足条件即可返回false不需要全部遍历
for (let i = 0, len = this.length; i < len; i++) {
if (!fn.call(context, this[i], i, this)) return false;
}
return true;
}
const nums1 = [2, -1, 3, 5, 1, 0];
console.log(nums1.myEveny(val => typeof val === 'number'));
// true
indexOf
Array.prototype.myIndexOf = function(val, fromIndex) {
// 只要是数字或者可以被自动转换为数字即为有效
// 否则使用默认起始点0
fromIndex = fromIndex * 1 || 0;
// 索引从小到大顺序查找, 返回第一个查找到的索引
for (let i = fromIndex, len = this.length; i < len; i++) {
if (this[i] === val) return i;
}
return -1;
}
const names = ['Wango', 'Lily', 'Lily', 'Peter'];
console.log(names.myIndexOf('Lily'));
// 1
console.log(names.myIndexOf('Anna'));
// -1
console.log(names.myIndexOf('Lily', 1));
// 1
console.log(names.myIndexOf('Lily', 2));
// 2
console.log(names.myIndexOf('Lily', '2'));
// 2
console.log(names.myIndexOf('Lily', -1));
// 1
lastIndexOf
Array.prototype.myLastIndexOf = function(val, fromIndex) {
const len = this.length;
// 起始点为数组长度减一
fromIndex = fromIndex * 1 || len - 1;
// 从大到小逆序查找,返回查找到的第一个元素的索引
for (let i = fromIndex; i > 0; i--) {
if (this[i] === val) return i;
}
return -1;
}
const names = ['Wango', 'Lily', 'Lily', 'Peter'];
console.log(names.myLastIndexOf('Lily'));
// 2
console.log(names.myLastIndexOf('Anna'));
// -1
console.log(names.myLastIndexOf('Lily', 1));
// 1
console.log(names.myLastIndexOf('Lily', 2));
// 2
console.log(names.myLastIndexOf('Lily``', '2'));
// 2
console.log(names.myLastIndexOf('Lily', -1));
// 1
reduce
Array.prototype.myReduce = function(fn, initVal) {
if (typeof fn !== 'function') throw new TypeError('A function is expected on parameter 1');
// 若initVal不是或不能自动转换为数字
// 则初始值为第一个元素
let pre = +initVal || this[0];
// 有初始值时当前值从0开始
// 没有初始值时当前值从1开始(0被上面pre拿走了)
for (let i = +initVal ? -1 : 0, len = this.length; i < len; i++) {
// 当下一个值不存在即数组循环完毕后, 返回累计结果
if (!this[i + 1]) {
return pre;
}
pre = fn.call(this, pre, this[i + 1], i, this);
}
}
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9];
console.log(nums.myReduce((a, b) => a + b));
// 45
console.log(nums.myReduce((a, b) => a + b, 10));
// 55
console.log(nums.myReduce((a, b) => a + b, 'aa'));
// 45
console.log(nums.myReduce((a, b) => a + b, '10'));
// 55
console.log([[1, 2, 3], [4, 5, 6]].myReduce((a, b) => a.concat(b)));
// [ 1, 2, 3, 4, 5, 6 ]
参考网址:ES5中新增的Array方法详细说明