二阶段第二周JS知识点整理

89 阅读16分钟

Monday

1、***数据类型转换:

1、强制类型转换:
	1、转字符串:
		1var str=x.toString();//xx不能是undefined和null,因为undefined和null不能使用.去做任何操作的
		2var str=String(x);//万能的,任何人都可以转为字符串,不重要:
		不重要的原因:
			1、页面上一切的数据类型都是字符串
			2String(); 完全相当于隐式转换,还不如+""

	2、*转数字:
		1parseInt/Float(str);//专门为字符串转为数字准备的
			原理:从左向右依次读取每个字符,碰到非数字字符则停止转换,如果一来就不认识则为NaN
			Int不认识小数点,Float认识第一个小数点

		2Number(x);//万能的,任何人都可以转为数字,不重要 - 完全相当于隐式转换,还不如-0 *1 /1

	3、转布尔:
		Boolean(x);//万能的,任何人都可以转为布尔,绝对不会手动使用,还不如!!x
		***只有6个会转为false0""undefinednullNaNfalse,其余的都是true
		在分支、循环条件中,其实就会带有布尔的隐式转换,以后【代老师不管在条件里写了什么】,你都不要太在意,只需要知道是true还是false即可

2、隐式类型转换:都是出现在运算符之中的

2、****运算符和表达式:

1、*算术运算符:+ - * / %
	特殊:1、%:取余,俗称模,判断奇偶性
	          2、隐式转换,默认转为数字,再运算
			true->1
			false->0
			undefined->NaN
			null->0
			特殊:1、+运算,碰到字符串,拼接
			          2、-*/%,字符串也可以转为数字,但是纯数字组成的字符串才行,但凡包含一个非数字字符则为NaN

2、*比较/关系运算符:>,<,>=,<=,==,!=,===,!==
	结果:布尔值
	隐式转换:默认,转为数字,再比较大小
	特殊:
		1、如果参与比较的左右两边都是字符串,则按位PK每个字符的十六进制的unicode号(十进制ascii码)
			0-9<A-Z<a-z<汉字
			汉字的第一个字:一(unicode号:4e00 - ascii码:19968)
			汉字的最后一个字:龥(unicode号:9fa5- ascii码:408692NaN参与任何比较运算,结果都是false,所以我们没有办法使用普通的比较运算来判断x是不是NaN
			解决:!isNaN(x);

		3undefined==null;//true
			解决:undefined===null; 才能区分出两者
			=== !==:不在带有隐式转换的比较运算
			要求数值相同,并且数据类型相同
			
		//想要区分undefined和null必须使用===
		function String(x){
			if(x===null){
				return "null";
			}else if(x===undefined){
				return "undefined";
			}else{
				return x.toString();
			}
		}
		
		console.log(String(1));
		console.log(String(true));
		console.log(String(null));
		console.log(String(undefined));

3、*逻辑运算符:
	&&:全部满足,才满足
	         一个不满足,就不满足

	||:全部不满足,才不满足
	     一个满足,就满足

	!:颠倒布尔值

	特殊点:短路逻辑:如果前一个条件,已经能够得出最终结论,则不必看后续
		&&短路:如果前一个条件满足,才执行后一个操作,如果前一个条件不满足,则不管后续操作
			目的:简化【简单的分支】if(条件){操作},1、一个条件一件事,满足就做,不满足就不做  2、操作必须只有一句话的情况
			语法:条件&&(操作);
			案例:if(total>=500){total*=0.8;}
			          total>=500&&(total*=0.8);
			if的性能是所有分支结构中最差的

		||短路:浏览器兼容,实现二选一操作 - 对于我们有点早,提前了解即可
			以后我们会见到这个语法:
			e=e||window.event;

4、位运算:
	左移:m<<n,读作m左移了n位,翻译:m*2的n次方
	右移:m>>n,读作m右移了n位,翻译:m/2的n次方
	个人不推荐:因为底数只能是2

5、*赋值运算:+=    -=    *=    /=     %=
	一个操作两件事,先计算,再赋值回去
	i++;//递增,每次固定只能+1
	i+=1;//累加,每次加几由我们程序员自己决定

	i++;  ===   i+=1;   ===   i=i+1;

	鄙视题:++i 和 i++的区别?
		单独使用,放前放后无所谓,效果一样
		但是如果参与了别的表达式,变量中的值都会+1
			返回不同:前++返回的是加了过后的新值
				 后++返回的是加了之前的旧值

6、***三目运算:简化if...else...  和  if...else if...else
	语法:
		1、条件?操作1:默认操作;

		2、条件1?操作1:条件2?操作2:默认操作;

	特殊:
		1、只能简化简单的分支 - 操作只能写一句话,不推荐你写多句,不方便维护,以后往往我们的操作真的只有一句话
		2、默认操作不能省略

	总结:
		if(){}		===>		&&短路	
		if(){}else{}		===>		三目
		if...else if...else	===>		三目
		

扩展:

1、计算机很笨,牛逼在快和记忆力好:计算机带有舍入误差,我们不可能修它,浏览器提供了解决方案:
	var str=num.toFixed(d);//d代表保留的小数位数,会四舍五入计算,但是它也有一个唯一的缺陷:结果返回一个字符串,所以建议搭配上parseFloat食用更佳

2、如何获取第一个字的ascii码:
	var asc=str.charCodeAt(0)

Tuesday

1、*****Function:自定义函数:也叫做方法,是需要预定义好的,以后可以反复使用的代码段

1、创建:2种
              *1、声明方式:function 函数名(形参列表){
			函数体;
			return 返回值;
		       }

	2、直接量方式:var 函数名=function(形参列表){
			函数体;
			return 返回值;
		          }
		通过此方式,我们可以看出一个点:函数名其实就是一个变量名,函数名和变量名尽量的不要冲突

	return的本意其实是退出函数的语法,但是return后如果跟着一个数据,会顺便将你的数据返回到全局,但注意只负责返回不负责保存

2、调用&接住结果:
	var result=函数名(实参列表)

3、***作用域:21、全局作用域:全局变量和全局函数,在任何地方都可以访问、使用

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

	带来了变量的使用规则:优先使用局部的,局部没有会自动找全局,全局也没有就报错

	特殊:
		1、千万不要对着未声明的变量直接赋值:a=1;//会导致我们污染全局,内存平白无故再全局创建了一坨,还不方便我们释放
		2、儿子不孝啊,局部的东西全局居然不能使用,解决:回看上面
		3、建议:return一般只出现在函数体的末尾,而且只能写一个return
		4、哪怕你没写return,其实最后也会悄悄的有一个returnreturn的是一个undefined,但是我们并不喜欢,不推荐
		5、往往前辈们提供的方法,底层都有一个return操作,前辈们觉得以后使用这些方法的人,可能还需要此结果拿去干别的操作
		6、不是说函数必须要有return,如果函数的调用者,以后还需要拿着函数的结果去干别的事,都需要return,否则不需要

4、***声明提前:鄙视重点 - 祖师爷留下的一个问题
	原理:在程序正式执行之前,
	          会悄悄的将var 声明的变量和function声明的函数,
	          集中提前到当前作用域的顶部,但是赋值留在原地,
	          而且变量比函数轻

	明说,我们自己写代码绝对不会碰到,只要我们遵守以下规则:
		1、先创建后使用
		2、变量名和函数名尽量的不要冲突
	只会在鄙视中碰到:如果你碰到了先使用后创建,多半都是在考你声明提前,你应该先转换为提前后的样子,再去判断输出,一定要看清代码执行的顺序

5、***按值传递:简单来说就是两个变量之间进行赋值 - 你一定看清楚传递的是什么类型
	如果你传递的是原始类型的值:两个变量之间是不会相互影响的,因为其实是复制了一个副本给对方

	如果你传递的是引用类型的对象:两个变量之间是会相互影响的,因为我们其实是使用了同一个地址值 - 也叫做浅拷贝

为什么函数我给5颗星,因为考点极多:慢慢学,不着急
	1、创建方式
	2、作用域
	3、声明提前
	4、按值传递
	5、匿名函数
	6、重载
	7、闭包

2、预定义的全局函数:前辈们提前准备好的,我们程序员可以随时随地使用的函数

1、编码和解码:
	问题1:url之中是不允许出现多字节字符的,如果出现则会发生乱码,乱码导致谁都认不到
		在utf-8编码格式下,一个汉字,占3字节
	解决:在发送之前,前端会将多字节字符编码为单字节内容,在发送
	          后端接收到了,可以进行解码操作,变回多字节原文
		编码:var code=encodeURIComponent("原文");
		解码:var 原文=decodeURIComponent(code);
	在某一次浏览器更新后,自带此功能了,这两个方法当场就被淘汰了

	现在唯一的用处就是用来玩个悄悄话 - 编码后发送到群里

2isFinite(num) - 判断出你这个数字是不是无穷大,垃圾
	有3个情况会为falseNaNInfinity、分母为0

3、真正牛逼反而是我早就教过大家的:isNaNparseIntparseFloateval(脱字符串的衣服)

3、***分支结构:

if分支、短路、三目、switch...case...:
语法:
	switch(变量/表达式){
		case1:
		操作;
		break;
		case2:
		操作;
		break;
		case3:
		操作;
		break;
		default:
		默认操作;
	}

特殊:
	1switch...case 比较时不具备隐式转换
	2switch...case 默认满足了一项,会把后面所有的操作全部做完,解决:搭配上break
		有的地方可以不加break1default最后一句话可以不加
			2、如果多个case之间做的是一样的操作,也可以不加
	3switch...case... vs if...else...
		1switch...case...:性能更好,因为它的case不能做范围判断,只能做精确值查找,但是switch小括号中还可以写表达式,语法相对复杂
		2if...else...:分支中性能最差,因为它支持范围判断,语法相对简单
	建议:真实开发中,if...else...越少越好

扩展:

1、animate.css文件,这是一个动画库,具有很多很多的动画,动画都不需要你写,你可以直接使用,可以让你的金夫人更漂亮
	https://animate.style/

Wednesday

1、***循环结构:

1、*var 循环变量=几;
      while(循环条件){
	循环体;
	变量的变化;
      }

2、var 循环变量=几;
     do{
	循环体;
	变量的变化;
     }while(循环条件)

面试题:while 和 do...while 的区别? 关键就看第一次,如果第一次条件满足,则两者没有区别 如果第一次条件不满足,则while一次都不会执行,而do...while至少会执行一次

*3for(var 循环变量=几;循环条件;变量的变化){
	循环体;
      }

4、*退出循环语句:
	break - 退出整个循环
	continue - 退出本次循环

        我们的循环结构就算是结束了,但是后面你可能还会学到for infor of、forEach、Map这些循环
    操作,但是代老师个人不爱称呼这些东西为循环,因为他们是专门为数组遍历准备纯自动循环,不能
    去设置从哪里开始到哪里结束

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

1、基础概念:一个变量/内存,可以保存多个数据的一种数据结构
      何时使用:只要存储多个相关的数据,都要集中定义在数组之中
      为什么:一个好的数据结构,可以极大的提升我们程序员的开发效率

2、创建:2种
	1、*直接量:var arr=[值1,...];
	2、构造函数方式:var arr=new Array(值1,...); - 此方法有一个坑:new Array(num) - 理解为你设置了一个长度为num的空数组

3、访问:数组名[下标];
      添加/替换:数组名[下标]=新值;
      特殊:
	读取元素,下标越界 - 返回undefined
	添加元素,下标越界 - 下标不连续,导致变成一个稀疏数组

4、数组的三大不限制
	1、不限制元素的长度
	2、不限制元素的类型
	3、不限制下标越界 - 不是好东西

5、数组唯一的属性:数组名.length - 获取此数组的长度
	三个固定套路:
		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];//当前元素
	}

7、如何释放一个引用类型:
	请你看清楚你的引用类型的数据有几个变量引用着,都要释放后才会真正的释放,建议:我们的代码尽量都要封装为一个函数,函数中的东西会自动释放

     索引数组:下标都是由数字组成的 - 我们以前学习的、用到的都是索引数组
8、关联(hash)数组:
	什么是:下标是可以自定义的
	为什么:索引数组的下标无具体意义的,不便于查找
	如何使用:
		1、创建:2步:
			1、创建空数组:var arr=[];
			2、为数组添加下标并且添加元素:arr["自定义下标"]=新值;

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

		3、强调:hash数组length失效了,永远为0!
		      遍历hash数组:绝对不能使用for循环,必须使用for in循环 - 专门用于遍历hash数组的,纯自动化的循环
			for(var i in 数组名){
				i;//自动得到所有下标
				数组名[i];//得到每一个元素
			}
		      其实for in循环非常牛逼,不光可以遍历hash数组,也可以遍历索引数组
		      代老师个人建议:不希望你会for in 忘了 for,hash数组再用for in,索引数组还是用for循环
  4、***面试中可能会问:hash数组的原理:
  	hash算法:将字符串,计算出一个尽量不重复的数字(地址值)
  	字符串内容相同,则计算出来的数字页一定是相同的
  	添加元素:将自定义下标交给hash算法,得到一个数字(地址值),直接将你要保存的数据放到此地址值去
  	获取元素:将指定的自定义下标交给hash算法,得到一个和当初保存时完全一样的数字(地址值),
  	通过这个地址值就可以找到我们当时保存的数据
		5、*****js里面万物皆对象,除了undefinednull,一切对象的底层都是hash数组 - 我们学习这一块最大的目的就是为了铺垫以后学习对象!

3、*****数组的API -

其实就是一些函数,只不过这些函数是前辈们定义好的,我们学习后直接就可以使用的,
而且这些函数只有数组可用
1、*数组 转为 字符串:
	var str=arr.join("自定义连接符");

	固定套路:2个
		1、鄙视题:将数组里面的内容拼接为一句话/单词
			无缝拼接:var str=arr.join("");

		2、将数组拼接为DOM页面元素 - 数据渲染页面
			var city=["请选择","北京","天津","南京","东京","西京","重庆","成都","厦门"];
			var str="<开始标签>"+city.join("</结束标签><开始标签>")+"</结束标签>";
			bd.innerHTML=str;

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

3、*截取子数组:
	根据你传入的开始下标到结束下标进行截取操作
	var subArr=arr.slice(starti,endi+1);
	特殊:
		1、不修改原数组,只会返回一个修改后的新数组
		2、含头不含尾
		3、endi可以省略不写,会从starti位置一直截取到末尾
		4、其实两个参数都可以省略,从头到尾完整的截取一份,也叫做数组深拷贝,和以前的按值传递(浅拷贝不同),复制了一个副本,两者互不影响
		5、甚至支持负数参数,-1代表倒数第一个

这条线以上的API都是不会修改原数组的

这条线以下的API都是会修改原数组的

4、*删插替:
	删除:var dels=arr.splice(starti,n);//n代表你要删除的个数
	    特殊:其实splice也有返回值,返回的是你删除的元素组成的一个新数组,因为前辈们考虑到,有可能删除的刚好是你需要用到的
	插入:arr.splice(starti,0,新元素1,...);
	    特殊:1、原starti位置的元素以及后续元素都会向后移动
	               2、没删除元素的时候也有返回值,返回的是一个空数组
	替换:var dels=arr.splice(starti,n,新元素1,...);
	    特殊:删除的元素个数和插入的元素个数不必相同

5、翻转数组:arr.reverse();

Thursday

1、*****ArrayAPI:

1、*****排序:2种方式
  1、鄙视/面试:冒泡排序:从第一个元素开始,依次比较相邻的两个元素,只要前一个元素>后一个元素,我们就交换两者的位置
  	公式:
  	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;
  			}
  		}
  	}
	2、正式开发:排序API:
		arr.sort();
		问题1:默认将元素们转为字符串,按位PK每个字符的unicode号进行排序的,如果希望按数字排序?
		解决:
		arr.sort(function(a,b){//传参很奇怪,传入的居然是一个函数,而且还没有名字,意味着我们不能主动调用,这种函数叫做匿名回调函数						   	   ,往往是前辈们创建好,我们学习如何使用即可的东西console.log("执行了吗");//确实不需要我们调用,他会自动调用,而且还做了很多,悄悄的还有循环在里面
			console.log(a);//保存的是后一个数字
			console.log(b);//保存的是前一个数字
			return a-b;//拿着后一个数字-前一个数字
					   //如果return返回的是一个正数,说明后一个数>前一个数
					   //如果return返回的是一个负数,说明后一个数<前一个数
					   //如果return返回的是一个0,说明后一个数==前一个数
					   //而我们sort方法会根据你返回的是什么数字,自动考虑要不要交换两者的位置
		});

		问题2:希望降序排列:
		arr.sort(function(a,b){
			return b-a;
		})

	强调:排序其实非常重要,记住,以后只要页面中有排序功能,那么他的底层一定是一个数组,因为再JavaScript只有数组可以做排序

2、*栈和队列:添加元素和删除元素的新方式
	栈:其实就是数组,只不过是一端封闭,只能从另一端进出的数组
	何时使用:优先使用最新的数据,现实生活中:情况不多:旅游大巴、电梯
	如何:
		开头进:arr.unshift(新值1,...)
		开头出:var first=arr.shift();//调用一次只会删除一个
		缺陷:影响其他元素的下标/位置

		结尾进:*arr.push(新值1,...);
		结尾出:var last=arr.pop();//调用一次只会删除一个
		至少没有缺点

	队列:其实就是数组,只能从一端进,从另一端出
	何时使用:希望按照先来后到的顺序使用数据,现实中多的很
		开头进:arr.unshift(新值1,...)
		结尾出:var last=arr.pop();//调用一次只会删除一个

		结尾进:*arr.push(新值1,...);
		开头出:var first=arr.shift();//调用一次只会删除一个

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

何时:在一个数组内,希望再次细分每个分类
创建:
	var arr=[
		["涂棚",18,"吃饭"],
		["杨玉华",19,"睡觉"],
		["程海峰",20,"学习"]
	];

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

总结:ES3的数组,你就算是完活了
	1、数组的基础(创建、访问、添加、length、遍历)
	2、数组的API:10个(转字符串、拼接、截取、删插替、翻转、排序、栈和队列)
	3、二维数组

3、*****String的概念:

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

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

***引用/对象类型:11个
	*String Number Boolean - 具有包装类型
	*Array *Function Date(日期) Math(数字) *RegExp(正则:验证)
	Error(错误)
	*Object(面向对象开发方式)
	Global(全局对象) - 在浏览器端(前端/客户端)中被window对象代替了 - 保存着全局变量和全局函数,只不过window可以省略不写
	只有前端的全局对象叫window,后端(Node.js)的全局对象还是叫global - 历史上第一次一门语言可以通吃前后端

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

为什么undefinednull不能使用. - 他们俩前辈们没有提供过包装类型 

Friday

1、*****String API:

其实就是函数,前辈们提供了,我们学习后直接可用,只有字符串可用

    1、转义字符:\
	作用:
		1、将字符串中和程序冲突的字符转为原文
			"\""	'\''

		2、包含特殊功能的符号
			换行:\n
			制表符:\t - 其实就是一个大空格,相当于你敲了键盘上tab键

		3、输出unicode编码的字符:
			常识:
			\uXXXX:第一个汉字:4e00		ascii:19968
				最后一个汉字:9fa5		ascii:40869

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

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

4、获取字符串中指定位置的字符的ascii码:
	var ascii=str.charCodeAt(i);
     通过ascii码转回原文:
	var 原文=String.fromCharCode(ascii);

5、***检索字符串:检查索引:获取关键字的下标
	var i=str/arr.indexOf("关键字",starti);
	从starti位置开始,向右查找【第一个关键字的第一个字符】的位置
	starti其实也可以省略,如果省略了会从0位置开始
	返回值:找到了,返回的是第一个关键字的第一个字符的下标
	              *没找到,返回-1,其实我们根本不关心下标为几,我们只关心下标为不为-1
	作用:判断有没有
	强调:数组也能使用此方法,数组是后期才添加上的,此方法原本是属于字符串
	鄙视题:默认只能获取第一个关键字的下标,如何才能获取到所有关键字的下标?
	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、*截取字符串:3种
               *var subStr=str/arr.slice(starti,endi+1);
		   str.substring(starti,endi+1);//不支持负数参数
		 *str.substr(starti,n);//n代表截取的个数,不必考虑含头不含尾

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

8、*替换字符串:本身这个方法非常强大,但是由于我们现在暂时不会正则表达式,只能替换固定的关键字(下周才能牛逼)
	var newStr=str.replace("关键字"/RegExp,"新内容"); 

9、*****切割/分割字符串:作用:str <=> arr
	var arr=str.split("自定义切割符");
	特殊:1、切割后,切割符就不存在了
	           2、切割符"",切散每一个字符

扩展:如何js创建/渲染元素:3步

1、JS创建空元素:
	var elem=document.createElement("标签名");

2、为此空标签添加必要的属性 或 事件
	elem.属性名=属性值;
	elem.on事件名=function(){}

3、渲染上DOM树:
	父元素.appendChild(elem);