基础篇之我是数组

155 阅读8分钟

1、*****数组Array的基础:

1、*创建数组:2种

*直接量方式:var arr=[];//空数组
	var arr=[数据1,...];	
构造函数方式:var arr=new Array();//空数组
	var arr=new Array(数据1,...);

2、*获取数组之中的元素:

数组名[i]

3、*后续添加/替换元素:

数组名[i]=新数据;
如果下标处没人则为添加,如果下标处有人则为替换

4、*数组具有三大不限制:

1、不限制元素的类型
2、不限制元素的长度
3、不限制下标越界 - 不是好东西:
	如果获取元素时,下标越界,返回的是一个undefined
	如果添加元素时,下标越界,会得到一个稀疏数组,如果有一天我们搭配上学过的循环去遍历获取每个元素,那么你会得到很多很多的undefined

5、***解决:数组中有一个唯一的属性:

语法:数组名.length
	作用:获取数组的长度,长度是从1开始的

	三个固定套路:
		1、向末尾添加元素:arr[arr.length]=新数据
		2、获取数组的倒数第n个元素:arr[arr.length-n];
		3、缩容:删除倒数n个元素:arr.length-=n

6、*****遍历数组:

往往很多情况,我们不会拿出某个数据来使用,而是拿出每个数据来进行 相同 或 相似 的操作 - 搭配上循环
	固定公式:
		for(var i=0;i<arr.length;i++){
			arr[i];//当前次元素
		}

2、***数组的基础(填坑):

1、创建数组:

1、*直接量:var arr=[值1,....];
2、构造函数:var arr=new Array(值1,....)
   第二个方法有一个坑:new Array(num);//创建了一个长度为num的空数组,里面没有任何东西,只有无数的undefined

2、***面试题:

***面试题:
按值传递:可能会这么出题:var a=x;	var b=a;	修改a,b变不变,或者,修改b,a变不变?
	如果传递的是原始类型:
	其实是复制了一个副本给对方,两者互不影响
        
        如果传递的是引用类型:js中不是原始类型,就是引用类型(数组、函数...都是引用类型)
	因为引用类型很大,比原始类型大得多,不可能保存在变量本地,只是保存了一个地址值而已,
	其实是把自己的地址值赋值给了对方,而两者使用的是同一个地址值,一个人修改,另一个也会跟着变化
	引用类型,在比较时,其实不是看的值,而是看的地址值作比较

***面试题:如何释放一个引用类型呢?一定要看清楚有几个变量引用着这个引用类型,每个变量都要释放后才能释放干净
	在js底层有一个垃圾回收器,只有垃圾回收器的计数器(记录着这个数据有几个人引用着)为0的时候才会删除不要的数据
	建议:我们代码都要封装在一个函数内,函数中的一切变量都会自动释放!
	索引数组:下标都是数字组成的数组	

3、***hash(关联)数组:下标是可以自定义的

为什么:索引数组的下标无具体的意义,不便于查找
	如何使用:
		1、创建:21、创建空数组:var arr=[];
			2、为数组添加自定义下标并且赋值:arr["自定义下标"]=新值

		2、访问:arr["自定义下标"]

		3、强调:hash数组的length会失效,永远为0!
			遍历hash,不能再使用for循环,必须使用for in循环 - 其实for in袍哥并不爱称呼他是一个循环,因为它不需要设置从哪里开始到哪里结束,纯自动化的,专门为了遍历hash数组而存在的
			语法:
				for(var i in 数组名){
					//i -> 下标
					//数组名[i] -> 当前次元素
				}
			不止hash数组可以遍历,也可以遍历索引数组
			个人建议:索引数组依然使用for,hash数组在使用for in

		4、***hash数组的原理:
			hash算法:将字符串,计算出一个尽量不重复的数字(地址值)
				 字符串内容相同,则计算出来的数字也一定是相同的
			添加元素:js解释器会将自定义下标交给hash算法,得到一个数字(地址值),直接将你要保存的数据放到此地址之中保存起来
			获取元素:js解释器会将指定的下标再次交给hash算法,得到一个和当初保存时完全一样的数字(地址值),通过此地址值就可以找到你当初保存的数据,取出来使用
		
		5、***js里面一切的东西都是对象,万物皆对象,除了undefinednull,【一切对象的底层都是hash数组】

4、*****数组的API:

1、*arr 转 str:

var str=arr.join("自定义连接符");
固定套路:21、鄙视题:将数组里面得内容拼接为一句话/单词 - 无缝拼接,其实就是拼接了一个空字符串
		var arr=["h","e","l","l","o"," ","w","o","r","l","d"];
		console.log(arr.join(""))

	2、***将数组拼接为DOM页面元素 - 第一次遇到数据渲染页面,这仅仅只是数据渲染的基础
		var arr=["-请选择-","北京","南京","西京","东京","重庆"];
		var str="<开始>"+arr.join("</结束><开始>")+"</结束>";
		sel.innerHTML=str;

2、*拼接数组:添加元素的新方式

将你传入的实参全部拼接为arr的末尾
	var newArr=arr.concat(新值1,arr1,...);
特殊:
	1、不修改原数组,只会返回一个新数组
	2、concat支持传入数组参数,悄悄的将你传入的数组打散为单个元素再拼接

3、*截取子数组:只想取出数组中的某一个部分

根据你传入的开始下标一直截取到结束下标
	var subArr=arr.slice(starti,endi+1);
	特殊:
	1、不修改原数组,只会返回一个新数组
	2、含头不含尾
	3、endi可以省略不写,如果省略不写,则从starti位置一直截取到末尾
	4、starti和endi都可以省略不写,那么从头到尾完整的复制一份,此操作也叫做深拷贝!复制了一个副本给对方,两者互不影响。
	5、支持负数参数,-1代表倒数第1

以上的API都是不会修改原数组的,只会返回新东西

4、*删插替:

删除:var dels=arr.splice(starti,n);//n代表删除的个数
	特殊:虽然他直接修改原数组,但是也有返回值,返回的是被删除的数据组成的一个新数组,因为前辈们考虑到有可能删除的东西刚好是你需要的东西,哪怕没有删除也会返回一个空数组
插入:var dels=arr.splice(starti,0,新值1,...);
	特殊:
	1、原starti位置的元素以及后续元素都会向后移动
	2、尽量的不要插入一个数组,会导致我们的数组一些是一维,一些是二维,遍历的时候极不方便
替换:var dels=arr.splice(starti,n,新值1,...);
	特殊:删除的个数和插入的个数不必相同

5、翻转数组:

arr.reverse(); 垃圾

6、*****数组排序:

1、笔试时:手写冒泡排序:前一个元素和后一个元素进行对比,如果前一个>后一个,两者就要交换位置,就算做完了循环,也只是把最大的一个放到了最后,所以还需要再次开启循环,才能把每一个都拍好
			var arr=[12,3,25,4,7,687,6,354,534,8,62,33,4];
			for(var j=1;j<arr.length;j++){
				for(var i=0;i<arr.length-j;i++){
					if(arr[i]>arr[i+1]){
						var m=arr[i];
						arr[i]=arr[i+1];
						arr[i+1]=m;
					}
				}
			}
			console.log(arr);

2、正式开发:数组的API:arr.sort();
	默认:将数组中的元素转为字符串后,再按位PK每个字符的unicode号(ascii码)!
	问题1:希望按照数字升序排列
		arr.sort(function(a,b){
			console.log(a);//后一个
			console.log(b);//前一个
			return a-b;
			});
			
	问题2:希望按照数字降序排列:
				arr.sort(function(a,b){
					return b-a;
				})

强调:
1、以后只要网页上有排序功能,说明他的底层一定是一个数组,因为js之中只有数组可以排序
2、以后只要网页上有随即功能,说明他的底层一定用到了随机数公式
 

7、栈和队列:添加元素和删除元素的新方式

栈:其实就是数组,只不过一端封闭了,只能从另一端进出
	如何使用:
	开头进:arr.unshift(新值,...);//添加元素的新方式,向前添加:缺点:导致其他元素的下标都会发生变化
	开头出:var first=arr.shift();//删除元素的新方式缺点,向前删除,一次只会删除一个,也有返回值,返回的就是被删除的元素:导致其他元素的下标都会发生变化
        结尾进:arr.push(新值,...);//添加元素的新方式,向后添加
	结尾出:var last=arr.pop()//删除元素的新方式缺点,向后删除,一次只会删除一个,也有返回值,返回的就是被删除的元素        
队列:其实就是数组,只不过一端进,从另一端出:
	何时使用:按照先来后到的顺序拿去数据
	如何使用:
		开头进:arr.unshift(新值,...);//添加元素的新方式,向前添加:缺点:导致其他元素的下标都会发生变化
		结尾出:var last=arr.pop()//删除元素的新方式缺点,向后删除,一次只会删除一个,也有返回值,返回的就是被删除的元素
		结尾进:arr.push(新值,...);//添加元素的新方式,向后添加
		开头出:var first=arr.shift();//删除元素的新方式缺点,向前删除,一次只会删除一个,也有返回值,返回的就是被删除的元素:导致其他元素的下标都会发生变化 

8、ES5提供了3组6个新的API:

1、判断:2个,判断的结果肯定都是一个布尔值

every:每一个,要求所有的元素都满足条件才为true,只要有一个不满足则为false,非常类似于我们以前学习&&
	var bool=arr.every(function(val,i,arr){
		//val - 当前的值
		//i - 当前的值的下标
		//arr - 当前数组本身
		return 判断条件;
	})

some:有一些,要求只要有一个元素满足结果就为true,全部条件不满足结果才为false,非常类似于我们以前学习||
	var bool=arr.some(function(val,i,arr){
		return 判断条件;
		})

2、遍历:拿到数组中的每个元素做相同 或 相似的操作

forEach - 直接修改原数组
	arr.forEach(function(val,i,arr){
			操作;
		})
map - 不会修改原数组,返回一个新数组
	var newArr=arr.map(function(val,i,arr){
		return 操作;
		})

3、过滤和汇总:

过滤:筛选出你需要的部分,但是和现实不太一样,原数组是不会发生变化的。
	var subArr=arr.filter(function(val,i,arr){
		return 判断条件;
		})
			
汇总:
	var result=arr.reduce(function(prev,val,i,arr){
		return prev+val;
		})

以上6API都是在简化我们的for循环操作,以后数组我们可能真的不会再写for循环了
		

ES6:箭头函数,专门简化一切的匿名回调函数 公式:function去掉,()和{}之间添加=>,如果形参只有一个,那么()省略,如果函数体只有一句话,那么{}省略,如果函数体只有一句话并且是return,那么{}和return都省略

9、二维数组:数组的元素,又引用着另一个数组

何时使用:在一个数组,希望再次细分每个分类
创建:
	var h52302=[
		[1,3,5,6],
		[4,5,6,7],
		[1,2,3,4]
	];
                
访问:数组名[行下标][列下标];
特殊:面试题:
	列下标越界:返回undefined
	行下表越界:得到的是一个报错,因为行下标越界已经得到undefined了,undefined没有资格再加[]做操作

遍历二维数组:必然两层循环,外层循环控制行,内层循环控制列
	for(var r=0;r<arr.length;r++){
		for(var c=0;c<arr[r].length;c++){
			console.log(arr[r][c])
		}
	}