JS学习总结

86 阅读19分钟

JavaScript学习第二周总结

周一

1、*****自定义函数Function:

什么是函数:需要提前预定义好,以后可以反复使用的一个代码段
何时使用:不希望打开页面立刻执行,以后可以反复调用,由用户来触发
如何使用:
    
	1、***创建:2种 - 其实三种
		1、*【声明方式】创建函数
			function 函数名(形参列表){
				函数体;
				return 返回值;
			}

		2、【直接量方式】创建函数:
			var 函数名=function(形参列表){
				函数体
				return 返回值;
			} 

			感觉到函数名其实就是一个变量名,函数名要尽量的不重复,否则后面的会把前面的给覆盖掉

	2、调用:var result=函数名(实参列表);

		//其实return的本意其实是退出函数,但是如果return后面跟着一个数据
		//顺便将数据返回到函数作用域的外部,但是return只负责返回不负责保存,所以调用函数时,需要拿一个变量去接住返回值
		//就算省略return,默认其实也有return,会悄悄的给你return一个undefined,建议有返回值才拿变量接住,如果不需要返回值,直接不用接


	3、***作用域:21、全局作用域:全局变量 和 全局函数,在页面的任何一个位置都可以使用

		2、函数作用域:局部变量 和 局部函数,只能在【函数调用时,内部可用】

		带来了变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
		特殊点:缺点:
			1、局部可以使用全局的,但是全局不能使用局部的,解决:看上面,加return
			2、千万不要在函数中对着未声明的变量赋值 - 全局污染:全局本
                            身没有这个东西,但是函数作用域却给添加上了,降低网页的性能!

	4、***声明提前 - 只会出现在笔试之中
		原理:在程序正式执行以前,会将var声明的变量(轻)和function声明的函
                    数(重),都会悄悄的提前到当前作用域的顶部,但是赋值留在原地
		
		强调:
			声明方式创建的函数会完整的提前(第一种)
			直接量方式创建的函数不会完整提前,只有变量名部分会提前(第二种)

		何时使用:永远不会自己使用,干扰我们的判断 - 只会出现在笔试之中,为
                    什么平时开发不会遇到呢?
			只要你遵守以下规则:
				1、先创建后使用
				2、变量名和函数名尽量的不要重复

	5、函数内部的变量,都会在函数执行完毕后,自动释放,意味着我们根本不需要自己写xx=null;

	6、***重载:相同的函数名,根据传入的实参的不同,自动选择对应的函数去执行,但
            是JS不支持,如果函数名重复了,后面的肯定会覆盖前面的
		目的:减轻我们程序员的压力,记住一个方法就可以执行很多的操作
		解决:在【函数内部】自带一个arguments的对象(类数组对象),不需要我们去创建的

		作用:哪怕没有写任何形参,它也可以接受住所有的实参,
		固定套路:
			1、通过下标去获取传入的某一个实参:arguments[i] - i下标是从0开始的!
			2、通过length去获取到到底传入了几个实参:arguments.length;
		所以我们可以通过判断传入的实参的不同,执行不同的操作,变相实现重载操作

	为什么函数这么重要?因为不光实用而且考点多
		1、请你写出函数的三种创建方式
		2、请你简单描述一下你了解作用域
		3、声明提前
		4、什么是重载呢?

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

数组:创建一个变量保存【多个数据】
	数组都是线性排列的,除了第一个元素,每个元素都有唯一的前驱元素,除了最后一个
            元素,每个元素都有唯一的后继元素
	***每个元素都有一个自己的位置,称之为叫做下标,下标都是从0开始的,到最大长度-1结束

1、*创建数组:2种
	1、*直接量方式:var arr=[];//空数组
			var arr=[数据1,...];
	
	2、构造函数方式: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];//当前次元素
		}

周二

1、*****DOM:

Document Object Model:文档对象模型,专门用于操作HTML文档的,提供了一些方法给你。

2、DOM树概念:

DOM将我们的HTML看作了是一个倒挂的树状结构,但是树根不是HTML标签,而是document对象 document对象:不需要程序员创建,由浏览器的js解释器自动创建,一个页面只有一个document树根 作用:可以通过树根对象找到我们想要的任何一个DOM元素/节点/对象(属性和方法) DOM会将页面上的每个元素、属性、文本、注释等等都会被视为一个DOM元素/节点/对象

3、查找元素:两大方面

1、直接通过 HTML 的特点去查找元素
	1、通过 ID 去查找元素:
		var elem=document.getElementById("id值");
		特殊:
			1、返回值,找到了返回当前找到的DOM元素,没找到返回一个null
			2、如果出现了多个相同id,只会找到第一个
			3、*记住控制台输出的样子,这个样子才叫做一个DOM元素/节点/对象,才可以下午拿去做操作!
			4、忘记此方法,不允许使用,id不好用,一次只能找到一个元素,把id留给后端使用
			5、其实id根本不用查找,可以直接使用

	2、*通过 标签名 去查找元素:
		var elems=document/已经找到的某个父元素.getElementsByTagName("标签名");
		特殊:
			1、返回值,找到了返回的是一个类数组DOM集合,没找到返回空集合
			2、*js只能直接操作DOM元素,不能直接操作DOM集合!解决:要么下标拿到某一个元素,要么遍历拿到每一个元素
			3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素

	3、*通过 class名 去查找元素:
		var elems=document/已经找到的某个父元素.getElementsByClassName("class名");
		特殊:
			1、返回值,找到了返回的是一个类数组DOM集合,没找到返回空集合
			2、*js只能直接操作DOM元素,不能直接操作DOM集合!解决:要么下标拿到某一个,要么遍历拿到每一个
			3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素

2、通过 元素之间的关系 去查找元素:前提:至少要【先找到一个元素】才可以使用关系网:
	1、父亲:elem.parentNode;//单个元素
	2、儿子:elem.children;//集合
	3、第一个儿子:elem.firstElementChild;//单个元素
	4、最后一个儿子:elem.lastElementChild;//单个元素
	5、前一个兄弟:elem.previousElementSibling;//单个元素
	6、后一个兄弟:elem.nextElementSibling;//单个元素

	为什么:不希望影响到别人,只希望影响到自己的关系网

4、操作元素:前提:先找到元素,才能操作元素,分三方面:

<标签名 属性="" style="样式">内容</标签名>

1、*内容:
	1、*elem.innerHTML - 获取或设置开始标签到结束标签之间的内容,【支持识别标签的】
		获取:elem.innerHTML;
		设置:elem.innerHTML="新内容";

	2、elem.innerText - 获取或设置开始标签到结束标签之间的纯文本,不支持识别标签的
		获取:elem.innerText;
		设置:elem.innerText="新内容";

	以上两个属性都是专门为双标签准备的,而有一个但标签也是可以写内容:<input />,我们如何操作:
	
	3、input.value; - 专门获取/设置input的内容
		获取:input.value;
		设置:input.value="新内容";

2、属性:
	1、*获取属性值:elem.getAttribute("属性名");
	2、*设置属性值:elem.setAttribute("属性名","属性值");

	简化版:
		1、*获取属性值:elem.属性名;
		2、*设置属性值:elem.属性名="属性值";
		简化版有两个缺陷:
			1、class必须写成className - ES2015(ES6)class变成了一个关键字
			2、只能操作标准属性,不能操作自定义属性

3、*样式:
	使用样式的方式:3种
		1、*内联样式
		2、内部样式表
		3、外部样式表 - 一阶段做开发用的都是外部样式表

	二阶段我们就要用js来操作【内联样式】
		1、不会牵一发动全身
		2、优先级最高

	获取样式:elem.style.css属性名;
	设置样式:elem.style.css属性名="css属性值";
	特殊点:
		1、css属性名,有横线的地方,要去掉横线,变为小驼峰命名法
			background-color		--->	backgroundColor
			border-radius		--->	borderRadius
		2、小缺陷:获取时,由于我们只学了操作内联样式,所以我们也只能获取到内联样式!

强调:
	一切的获取,都是为了做判断!
	一切的设置,说白了就是在修改!

4、*绑定事件:
	elem.on事件名=function(){
		操作;
		***关键字this - 这个,只能在【事件】内使用
		·	如果单个元素绑定事件,this->这个元素
			如果多个元素绑定事件,this->当前触发事件的元素!!!
	}

周三

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

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

2、***面试题:按值传递:可能会这么出题:var a=x;	var b=a;	修改ab变不变,或者,修改ba变不变?
	如果传递的是原始类型:
		其实是复制了一个副本给对方,两者互不影响

	如果传递的是引用类型:js中不是原始类型,就是引用类型(数组、函数...都是引用类型) - 【浅拷贝】
		因为引用类型很大,比原始类型大得多,不可能保存在变量本地,只是保存了一个地址值而已,
		其实是把自己的地址值赋值给了对方,而两者使用的是同一个地址值,一个人修改,另一个也会跟着变化

	引用类型,在比较时,其实不是看的值,而是看的地址值作比较

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

索引数组:下标都是数字组成的数组	

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

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

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

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

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

3、*****数组的API:

前辈们预定义了很多方法,等待我们学习,我们程序员只需要学会如何使用,就可以直接用上 - 这些方法只有数组可用

1、*arr 转 str:
	var str=arr.join("自定义连接符");

	固定套路:2个
		1、鄙视题:将数组里面得内容拼接为一句话/单词 - 无缝拼接,其实就是拼接了一个空字符串
			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个
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(); 

周四

1、*****数组API:

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){
				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;
			})

	以上6个API都是在简化我们的for循环操作,以后数组我们可能真的不会再写for循环了
	
	ES6:箭头函数,专门简化一切的匿名回调函数
		公式:function去掉,()和{}之间添加=>,如果形参只有一个,那么()省
                    略,如果函数体只有一句话,那么{}省略,如果函数体只有一句话并且是
                    return,那么{}和return都省略

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

何时使用:在一个数组,希望再次细分每个分类
创建:
	var h52302=[
		["潭州好",18,3500],
		["料号姐",19,4500],
		["任庆宇",20,2500]
	];

访问:数组名[行下标][列下标];
特殊:面试题:
	列下标越界:返回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])
		}
	}

周五

1、*****String的概念:

什么是字符串:多个字符组成的【只读】字符【数组】(只读:今天我们要学习的所有的字符串的API都不会修改原字符串,只会返回一个新字符串)
和数组有相同点:
	1、字符串中的个数:str.length
	2、获取字符串中的某个字符:str[i]
	3、遍历字符串
	4、所有数组不修改原数组的API,字符串也可以使用(concat、slice)

和数组也有很多不同的地方
	所有数组的直接修改原数组的API,字符串都不可以使用,比如排序只有数组可以使用,但是
	字符串也有很多很多属于自己的API,等待我们明天学习

***引用/对象类型:11个
	*String Number Boolean -> 包装类型
	*Array *Function Date(日期) Math(数学) *RegExp(正则:验证)
	Error(错误)
	*Object(面向对象)
	Global(全局对象) - 只不过在浏览器端被window对象给代替了,自然保存着全局变量和全局函数,只不过window可以省略不写,有一天我们回去学习node.js这个后端语言,而在node.js中全局对象就叫做global

***包装类型:专门用于将原始类型的值封装为一个引用类型的对象的
	为什么:原始类型的值原本是没有任何属性和方法,意味着原始类型本身是不支持.去做任何操作的
		但是前辈们发现字符串经常会被我们程序员所操作,为了方便我们程序员所以将这个三人提供了包装类型(提供了属性和方法)
	何时使用:只要你试图使用原始类型的变量调用属性或方法的时候,自动包装
	何时释放:方法调用完毕后,自动释放包装类型,有变成了一个原始类型的值

为什么nullundefined不能使用. - 因为前辈们没有给他们提供包装类型

2、*****StringAPI:只有字符串可以使用的函数,不需要创建,直接使用

1、转义字符:\
	作用:
		1、将字符串中和程序冲突的字符转为原文
			"\""	'\''
		2、包含特殊功能的符号:
			换行:\n
			制表符:\t	->	大空格,跟你敲tab键效果是一样的
		3、*输出unicode编码的字符:
			汉字的第一个字:\u4e00 - ascii码:19968
			汉字的最后一个字:\u9fa5 - ascii码:40869

2、*大小写转换:将字符串中的每个英文字符统一的转为大写 或 小写
	何时:只要程序不区分大小写,就要【先统一】的转为大写 或 小写,再比较(做验证码)
	如何:
		var 大写=str.toUpperCase();
		var 小写=str.toLowerCase();

3、获取字符串中的指定位置的字符:str.charAt(i)	===	str[i];

4、*获取字符串中的指定位置的字符的ascii码
	var ascii=str.charCodeAt(i);

     *通过ascii码转回原文:
	var 字=String.fromCharCode(ascii码);

5、***检索字符串:检查索引 - 检查下标,获取关键字的下标:
	var i=str.indexOf("关键字",starti);
	从starti位置开始,查找右侧第一个关键字的第一个字符的位置
	starti可以省略,默认从0位置开始查找的
	返回值:找到了,返回的第一个关键字的第一个字符的下标位置
		*没找到,返回-1,其实我们根本不关心下标为多少,我们只关心下标为不为-1
	作用:***判断有没有!
	强调:数组也能使用此方法,数组这个方法其实是后期才添加上的,原本此方法只有字符串可用,比如老IE的数组就没有此方法
	鄙视题:默认只能获取第一个关键字的下标,如何才能获取到所有的关键字的下标呢?
		var str="no zuo no die no can no bibi";
		var index=-1;
		while((index=str.indexOf("no",index+1))!=-1){
			console.log("找到了关键字,下标为:"+index);
		}

6、拼接字符串:var newStr=str.concat(新字符串,...)	还不如+运算

7、*截取字符串:3个
	*var subStr=str/arr.slice(starti,endi+1);//用法和数组完全一致
		             .substring(starti,endi+1);//用法和slice几乎一致,但是不支持负数参数
		            *.substr(starti,n);//n代表的是截取的个数,不必考虑含头不含尾

8、*替换字符串:本身这个方法非常的强大,但是由于我们暂时不会使用正则,所以我们只能替换固定的关键字,暂时比较挫
	var newStr=str.replace("固定关键字"/RegExp,"新内容");

9、*****切割/分割/分隔字符串:
	作用:将字符串切割为数组:str<==>arr
	var arr=str.split("自定义切割符")
	特殊:
		1、切割后,切割符就不在了
		2、如果你的切割符写的是"",切散每一个字符

10、去掉空白字符:str.trim()/str.trimStart()/str.trimEnd()