数组拓展方法是从ES5中才使用的
一. JSON与数组的联系
知识回顾:很多大的项目JSON数据存在HTML中,减少了对服务器的请求
同时以数组的形式存储多项JSON数据:[{……},{……},{……}],这样的方式称之为
JSON对象集合 也叫 JSON数据集合
这样的话就形成了一套数据结构 ( 对象中各项打上引号、 []存储多项对象 ),这种数据结构称之为JSON
JSON数据就是对象,JSON数据集合就是数组
数组里面每一个值 称之为 数组元素 element
二. forEach(): 遍历
1. forEach()
它是遍历数组的方法: forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
data = [1, 2, 3];
data.forEach(myFunction);
function myFunction(item) {
var sum = 0;
for (var i = 0; i < data.length; i++) {
sum = sum + data[i]; //sum = 1 + 2 + 3
}
console.log(sum);
}
因为data中有三个元素,所以遍历function三次,输出 6 三次
forEach()是数组的原型上面的方法(Array.prototype)
所以说只能数组用这个方法,对象等不能用
forEach()每遍历出一个元素就会执行一次function-->需要提供三个参数:
data.forEach(function(elem, index, ayyay){ /数组元素, 索引, 正在遍历的数组
console.log(this);
});
elem:当前数组的元素
index: 当前元素的下标
array:正在遍历的数组
因为数组里面每一个值 称之为 数组元素 element
所以在forEach()中常把 data[i]写成 elem, 把 i 写成 index
同时这里面的this指向window
同时forEach()的 括号里面有两个参数, 第二个参数更改函数内部的this指向
因为 var data = [ ' 1 ' , ' 2 ' ]; ,有两个元素, 所以以下结果输出两次:
<script>
var data = ['1', '2'];
data.forEach(function (elem, index, ayyay) {
console.log(this);
},{name: 'test'}); /返回:{name: "test"}
var data = ['1', '2'];
data.forEach(function (elem, index, ayyay) {
console.log(this);
},1); /返回 Number {1}
var data = ['1', '2'];
data.forEach(function (elem, index, ayyay) {
console.log(this);
}, false); /返回 Boolean {false}
var data = ['1', '2'];
data.forEach(function (elem, index, ayyay) {
console.log(this);
},undefined); /Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
</script>
因为this 一定会指向一个对象, 所以填1、false等会强制给它转换成对象形式(包装类知识), 所以第二个参数填null、undefined 时不成功
2. forEach()方法的重写
重写: 详细写该方法的原理
<script>
var data = [1, 2, 3];
var fn = function (elem, index, array) {
console.log(this); //指向data,因为data调用此方法; 经过apply后指向第二个实参
}
Array.prototype.myForEach = function (fn) {
var arr = this, //因为是数组去调用自定义的方法,所以this指向该数组, 在方法中声明一个变量arr 去保存this
len = arr.length,
args2 = arguments[1] || window; //如果传入了第二个参数 就将其保存到args2, 如果没传,args就保存window
for (var i = 0; i < len; i++) {
fn.apply(args2, [arr[i], i, arr]); //每循环一次 都要遍历这个函数fn,
//使用apply 改变该函数的指向, 原本fn指向window, apply之后指向参数args2, 即下面的Sum
}
}
var a = 1;
data.myForEach(fn, a); //输出三个 Number {1}
//当a = undefined时,输出三个:Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
</script>
总结:forEach()有两个功能:
- 遍历: 调用的数组有几个元素,就遍历几次
- 将第二个实参调入第一个实参函数中
三. filter(): 筛选、过滤
与forEach() 最大的不同是 它会返回一个新的数组,即不会改变原数组:
<script>
var data = [{ 'name': '0', 'age': '18' }];
var newArr = data.filter(function (elem, index, array) {
return elem.name === '0'; //正确就返回data ,错误就返回空
})
console.log(newArr);
</script>
该方法通过返回的值是 true还是false 来判断哪些数据需要放到新数组中去: 上式用形参function来和data比较,有和data相同的话就把data赋给 newArr
filter()方法的重写
<script>
var data = [{ 'name': '0', 'age': '18' },{ 'name': '0', 'age': '8' }, {'name': '1', 'age': '8'} ];
var fn = function (elem, index, array) {
return elem.name === '0';
}
Array.prototype.myFilter = function (fn) {
var arr = this,
len = arr.length,
args2 = arguments[1] || window,
newArr = [];
for (var i = 0; i < len; i++) {
fn.apply(args2, [arr[i], i, arr]) ? newArr.push(arr[i]) : " ";
//加的是arr[i], 和args2无关
}
return newArr
}
var newARR = data.myFilter(fn, [{ 'name': 'jack', 'age': '100' }]);
console.log(newARR); //输出{ 'name': '0', 'age': '18' },{ 'name': '0', 'age': '8' }
</script>
对应的判断语句在fn的函数内,apply并无什么用,因为window的存在,只要符合fn中的判断语句,就会一直执行,不管第二个实参的个数。同时,符合条件的项将数组元素(只是data中的) arr[i]放入新数组中( newArr.push(arr[i]) )
所以第二个参数并不参与进去,以后箭头函数分析this指向等才会有用 , 这才是可填可不填的真谛
四. map: 映射
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。 并不会改变原数组的值
<script>
var data = [{ 'name': '0', 'age': '18' }];
var newArr = data.map(function (elem, index, arr) {
elem.name = this.name + elem.name;
// this.name 就是第二个形参的值, this指向第二个形参
return elem;
}, { 'name': '[JS前端]' })
console.log(newArr);
</script>
上式输出 {name: "[JS前端]0", age: "18"}
可以得出结论: map的作用就是将参数的值放入到数据中: data.map(fn, args2)
2. map() 方法 重写
var data = [{ 'name': '0', 'age': '18' }];
Array.prototype.myMap = function (fn) {
var arr = this,
len = arr.length,
arg2 = arguments[1] || window,
nArr = [],
item;
for (var i = 0; i < len; i++) {
item = arr[i];
nArr.push(fn.apply(arg2, [item, i, arr])); //唯一的不同就是for循环,for循环决定该方法的特性
}
return nArr;
}
var fn = function (elem, index, Array) {
elem.name = this.name + elem.name;
return elem;
}
var newArr = data.myMap(fn, { name: '[JS前端]' });
console.log(newArr);
输出 : { name: "[JS前端]0", age: "18" }
所以map可以修改数据,又能添加数据
五. 总结
这些重写方法 唯一的不同就是for循环, for循环决定该方法的特性