js中的数组
window(global)全局对象在heap(堆内存)中对应的hash表里存储的东西包括有标准库和非标准库。标准库包括有String()、Number()、Boolean()、Object()、Array()、Function()等等。
js中声明一般有两种方法,拿number类型的数据举例,你可以写成var n = 1
或者是var n = new Number(1)
前者得到的是一个数值1,后者得到的是数值1封装而成的对象。基本数据类型像string、number、boolean都遵循此规律,对于object等复杂类型而言,加不加new得到的结果都会是一个对象。
数组虽然属于object但是有它自己的共有属性array.prototype,所以数组的声明有另一种形式。var arr = ['aaa','bbb']
或者是var arr = new Array('aaa','bbb')
。以及,这个诡异的数组声明有很多奇奇怪怪的地方,比如var arr = Array(3)
你以为得到的是一个含有数值3的数组吗,不你错了它得到的是一个长度为3的数组,并且数组里边只存了length
和__proto__
,你会发现'0' in a
的结果为false。但是var arr = Array(1,2,3)
的结果也是一个长度为3的数组,并且1,2,3分别是数组的第0项第1项和第2项。
tips:function VS Function
function是用来声明一个函数的(function f(){}
),就像var用来声明一个变量(var a = 1
)一样。
Function是一个全局对象,就像Object,window.Object
,window.Function
。
两者都可以用来声明对象,但是并没有什么关系。function是一个关键字,而Function是一个全局对象。
function声明:
function f(x,y){
return x+y;
}
Function声明:
var f = new Function('x','y','return x+y');
事实上我们知道如果没有什么变态的需求没有人会选择用第二种方法声明一个函数。至于原因自己体会。
什么是数组?
按照生活中的理解,数组就是按顺序排列的一组数值。用js的话来说,数组是用Array()构造出来的一种对象。
如果你想要遍历一个数组的话,你可以使用for循环进行遍历。
for(let i = 0; i < arr.length; i++){
console.log(arr[i]);
}
但是如果你需要遍历一个对象,这种方法显然行不通,因为对象里边并不只有数字。所以你需要用下边这种:
for(let key in arr){
console.log(arr[key]);
}
事实上,如果你声明了一个数组var arr = [0,1,2]
,然后再继续执行arr.xxx = 'xxx'
会如何呢?答案是可以存储,数组里会增加一个属性xxx,它的值为’xxx’。但是对数组的length属性没有影响。如果你用第一种方法对其进行遍历,依然遍历不到’xxx’这个字符串。但是如果你用第二种方法遍历却可以遍历的到。那么,这个arr到底是数组,还是对象?
答案是数组。一个变量是不是数组并不由它本身的内容确定。如果它的原型链上存在Array.prototype
那么它就是数组,不论它里边的数据存储形式如何。但是如果它的原型链上不存在Array.prototype
,那么它长得再像数组,也只能说是个伪数组。arguments就是一个典型的伪数组。
数组的一些方法
- Array.prototype.forEach(),数组的遍历
var a = ['a','b','c']
a.forEach(function(x,y){
console.log('value:' + x)
console.log('key:' + y)
})
Array.prototype.forEach()的参数是一个函数,这个函数的参数有三个,分别是数组的value、key和a这个数组本身。由于传入数组本身没有什么意义所以经常被省略。
- Array.prototype.sort(),数组内置的默认排序方法。
var a = [2,3,5,1,4]
a.sort(function(x,y){
return x-y //或者是return y-x 前者升序后者降序
})
得到的结果是内容为[1,2,3,4,5]的数组a。只有这个函数改变了数组a本身。
内置的排序算法一般都是快速排序。
- Array.prototype.join(),把数组变成字符串。
var a = ['a','b','c']
a.join() //"a,b,c"
a.join('') //"a,b,c"
a.join('-') //"a-b-c"
不改变原有数组。当然如果只是变成上边那两种形式直接用a + ''
或者a.toString()
就可以达到目的。
- Array.prototype.concat(),数组的连接。
var a = ['a','b','c']
var b = ['1','2','3']
var c = a.concat(b) //['a','b','c','1','2','3']
这里如果你对数组a、b执行 +
运算的话,得到的结果是”a,b,c1,2,3”。concat返回的是一个新的数组。
正由于concat的这个特性,它可以被用来实现深拷贝。var copy = a.concat([])
得到的就是一个和a内容相同但是并不指向同一地址的数组。
- Array.prototype.map(),数组中数据的映射。
var a = [1,2,3]
var b = a.map(function(value,key){
return value*2 //[2,4,6]
})
Array.prototype.map()和Array.prototype.forEach()的相似之处在于都实现了数组的遍历,不同的是a.map有返回值并且可以对数组中的数据进行操作实现数据的映射。
- Array.prototype.filter(),数组中数据的过滤。
var a = [1,2,3,4,5,6,7,9]
var b = a.filter(function(value, key){
return value > 4 //[5,6,7,9]
})
过滤器filter用来过滤掉一些你不想要的数据,return的结果如果是true那就留下这个值,是false则舍弃这个值。
filter和map可以结合使用如下。
var a = [2,3,4,5,7,8,10]
a.filter(function(value){
return value%2 === 0
}).map(function(value){
return value/2
}) //[1,2,4,5]
- Array.prototype.reduce(),功能很多。
实现数组中个数据项的相加:
var a = [1,2,3,4,5]
a.reduce(function(sum, value){
return sum + value
},0) //15
a.reduce()的第一个参数是一个函数,实现你想要实现的功能。函数的参数分别是上一次调用时的返回值、value、key以及函数本身。
a.reduce()的第二个参数是函数中sum参数的初始值,如果不写的话默认为数组的第一个元素,如果不存在第一个元素的话则会报错。建议总是写初始值。
用reduce实现map:
a.reduce(function(arr, value){
arr.push(value*2)
return arr
},[])
用reduce实现filter:
a.reduce(function(arr, value){
if(value > 3){
arr.push(value)
}
return arr
},[])