js基础

101 阅读12分钟
第二周:
位运算:
   左移:m<<n:读作m左移了n位,翻译:m*2的n次方
   右移:m>>n:读作m右移了n位,翻译:m/2的n次方
   垃圾的原因:底数始终只能是2
赋值运算:+= -= *= /= %=
	一个操作两件事,先计算,在赋值回去

	i++; //递增:每次固定只能+1
	i+=1;//累加:每次加几由程序员自己决定

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

	鄙视题:++ii++ 的区别?
		1、单独使用(独立存在)时,放前放后无所谓,完全一样
		2、如果参与了别的表达式,变量中的值都会+1
			前++返回的是【加了过后】的新值
			后++返回的是【加了之前】的旧值
三目运算:简化【简单的】分支结构if(){}eles{} if(){}else if(){}eles{}
	语法:
		1、条件?操作1:默认操作;

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

	特殊:
		1、【简单的】,操作只能有一句话
		2、默认操作必须写出来,不能省略,省略会导致语法错误

	总结:
		if		 ===			&&短路
		if...else	 ===			三目
		if...else if...else	===		三目	

2、计算机带有舍入误差 - 解决:num.toFixed(d);//d代表保留的小数位数,会自动四舍五入 此方法有一个唯一的小缺陷:最好搭配上一个parseFloat使用

获取字符串中第一个字符的ascii码:var ascii=str.charCodeAt(0);

自定义Function
什么是函数:需要先定义好,可以反复使用的一个代码段
何时使用:1、不希望打开页面立刻执行  2、以后可以反复使用  3、希望绑定在页面元素上  4、第一等公民地位
如何使用:
	1、***创建并且调用:
		1、创建:2种方式
			1、*【声明方式】创建函数
				function 函数名(形参,...){
					函数体
					return 返回值/结果;
				}

			2、【直接量方式】
				var 函数名=function(形参,...){
					函数体
					return 返回值/结果;
				}

			通过第二种创建方式:学到了一个点:函数名其实就是一个变量名

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

			其实return的本意是退出函数,但是如果return后面跟着一个数据
			顺便将数据返回到函数作用域的外部,但是return只负责返回,不负责保存
			所以调用函数时,如果里面有return操作,记得拿一个变量接住结果
			就算你省略return,默认也会返回return undefined;
			具体要不要得到函数的结果,看你自己
***作用域:2种
		1、全局作用域:全局变量和全局函数,在页面的任何一位置都可以访问到

		2、函数作用域:局部变量和局部函数,在【当前函数调用时内部可用】
	
			*变量的使用规则:优先使用局部的,局部没有找全局,全局没有就报错
			特殊:缺点:
				1、千万不要在函数中对着未声明的变量直接赋值 - 全局污染(全局没有的东西,突然被局部添加上了)
					解决:使用变量之前记得先var了来在使用
				2、局部可以使用全局的,但是全局不能使用局部的 - 解决:看上面的return操作
***声明提前:
		在程序正式执行之前
		悄悄的,将var声明的变量(轻)和function声明的函数(重)
		集中提前到当前作用域的顶部
		但是赋值留在原地

		声明方式创建的函数会完整的提前(第一种方式)
		直接量方式创建的函数不会完整提前,只有变量部分提前(第二种方式)

		何时使用:永远不会自己使用,垃圾干扰我们判断 - 只会在鄙视中遇到,为什么平时开发不会遇到呢?
			只要遵守一下规则:
				1、变量名和函数名尽量的不要重复
				2、先创建后使用
				3、如果鄙视时碰到了先使用后创建,多半都是在考你声明提前
、***按值传递:两个变量之间进行赋值
		如果传递的是【原始类型】的值:
			修改一个变量,另一个变量是不会受到影响的,其实是复制了一个【副本】给对方

		如果传递的是【引用类型】的对象:- 除了那5个,其余的都是引用类型(ArrayFunction...)
			修改一个变量,另一个变量是会受到影响的,因为大家其实操作的都是同一个地址值

4、预定义全局函数:前辈们提前创建好的方法,我们程序员可以直接使用,任何位置都可以使用 1、编码和解码:-> 玩个悄悄话,你编码发到群里,其他人来解码 问题:url中不允许出现多字节字符的,如果出现会乱码 utf-8编码格式下,一个汉字占3字节 解决:发送前,前端将多字节字符原文编码为单字节字符(数字、字母) 发送后,后端将单字节字符解码为多字节原文

	如何:
		编码:var code=encodeURIComponent("倚天屠龙记");
		解码:var 原文=decodeURIComponent(code);
	其实这个东西在某次浏览器更新后,当场就淘汰了,浏览器现在自带此功能

2isFinite(num);判断num是不是无穷大:true->有效数字  false->无穷大
	哪些会为falseNaN,Infinity,分母为0

3、*其实真正有用的反而是代老湿之前就交了你们的
	parseInt/Float/eval/isNaN

5、***分支结构:根据条件的不同,选择部分代码执行:if分支、三目、&&短路、switch分支 语法: switch(变量/表达式){ case 值1: 操作1; case 值2: 操作2; case 值3: 操作3; default: 默认操作; }

特殊:
  1case作比较的使用不带有隐式转换
  2、问题:默认只要一个case满足后,会将后面所有的操作全部做完
     解决:break;
     建议:每一个case的操作后面都要跟上一个break;
		有的地方也可以不加break1、最后的一个操作default可以省略break
			2、如果中间多个条件,做的操作是一样的,也不需要break,甚至可以省略掉中间部分
  3default可以省略不写,但是不推荐,如果所有条件都不满足,则什么事都不会发生

if  vs  switch
  1switch...case:缺点:必须要知道最后的结果才能使用,不能做范围判断
		    优点:执行效率相对较高

  2if...else:优点:能做范围判断
		缺点:执行效率相对较低

建议:开发时,你爱用什么用什么,开发完了,要做代码优化,要尽量的把if考虑能不能换成switch

扩展:1、js动画:几乎和js没有关系,与css有关(transition过渡) js操作样式,瞬间生效的,只要加上过渡就会慢慢生效 - animate.css动画库(库:很多动画) 网址:animate.style/

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

2、创建:2种
	1、*直接量:var arr=[值1,...];
	2、构造函数:var arr=new Array(值1,...);
			第二种方式还有一个坑:var arr=new Array(num);//创建了一个长度为num的空数组

3、访问:数组名[下标]; -- 当前元素
   添加/修改:数组名[下标]=新值;
   特殊:获取元素,下标越界 - 返回undefined
	 添加元素,下标越界 - 稀疏数组,导致下标不在连续,导致搭配上for遍历会得到很多很多的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 arr){
				i;//自动得到所有的下标,不需要我们设置从哪里开始到哪里结束,一切都是自动化的
				arr[i];//当前次元素,想要干什么看你自己
			}

		for in循环非常牛逼,不光可以遍历hash数组,也可以遍历索引数组
		个人推荐:索引数组依然使用for,hash数组在用for in

	    4、***面试题:hash数组的原理:
		hash算法:将字符串,交给hash算法,计算出一个尽量不重复的数字(地址值)
			  字符串内容相同,则计算出来的数字也一定是相同的
		添加元素:将自定义下标交给hash算法,得到一个数字(地址值),直接将你要保存的数据放到这个地址里面去
		获取元素:将指定的自定义下标交给hash,得到一个和当初保存时一样的数字(地址值),通过地址值就能拿到你当初存进去的数据

	    5、js之中一切东西都是对象,除了undefined和null,【一切对象的底层都是hash数组】
、*****数组的API:前辈们提供好的一些方法,这些方法只有数组可以使用
1、*arr to str:
	var str=arr.join("自定义连接符");

	固定套路:2个
	  1、鄙视题:将数组中的每个数据,拼接为一句话/单词
		var arr=["h","e","l","l","o"," ","w","o","r","l","d"];
		无缝拼接:var str=arr.join("");

	  2、将数组拼接为DOM页面元素
		//以后会从数据库里拿到数据 - 数据渲染
		var arr=["-请选择-","北京","南京","西京","东京","重庆"];
		//数组转为字符串并且拼接上了应有标签
		var str="<开始标签>"+arr.join("<结束标签><开始标签>")+"<结束标签>"
		//字符串渲染到DOM树上
		sel.innerHTML=str;

2、*数组的拼接:添加元素的新方式
	把你传入的实参全部拼接到arr的末尾
	var newArr=arr.concat(新值1,...);
	特殊:
	  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也有返回值,返回的就是你删除的元素组成的一个新数组,前辈们考虑有可能你删掉的东西,刚好是你需要使用的东西
	插入:var dels=arr.splice(starti,0,新值,...);
	  特殊:原starti位置的元素以及后续元素都会向后顺移
	替换:1、var dels=arr.splice(starti,n,新值,...);
	      2、不推荐插入一个数组,一些是一维,一些是二维
	  特殊:插入的个数和删除的个数不必相同,随意
*****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 middle=arr[i];
					arr[i]=arr[i+1];
					arr[i+1]=middle
				}
			}
		}

	2、正式开发中:排序API:
		arr.sort();
		问题1:默认会将元素们转为字符串,按位PK每个字符的unicode号,如果希望按照数字排序
		解决:
		//我们第一次遇到传入实参,传入的是一个函数,而且是一个没有函数名的函数,我们称呼这种函数叫做匿名回调函数,不需要我们程序员自己调用
		//回调函数都是前辈们提供好的,我们只需要学习如何使用的
		arr.sort(function(a,b){//a:后一个数  b:前一个数
			return a-b;//返回一个正数:后一个数>前一个数
					   //返回一个负数:后一个数<前一个数
					   //返回一个0:后一个数==前一个数
					   //而我们的sort会根据你返回的正数/负数/0,来自动判断要不要交换两者的位置
		});

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

	强调:排序非常重要:切忌:只要以后页面中有排序功能,他的底层一定是一个数组,因为在js中只有数组可以做排序功能

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();

	ES3提供的数组API我们学完了,后面ES5还提供了一些新的API

3、二维数组:数组的元素,又引用着另一个数组
   何时使用:在一个数组内,希望再一次细分每个分类
       创建:
	 var arr=[
		["喻杭",18,3500],
		["尹天星",19,4500],
		["陈磊",20,1500]
	 ];

       访问:arr[行下标][列下标];
       特殊:列下标越界,返回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、数组的基础(创建、访问、添加、length、遍历)
  2、API:10个(转字符串,拼接,截取,删插替,翻转,排序,栈和队列)
  3、二维数组
数组暂时告一段落,以后ES5还会有新的API

、*****String的概念/理论:
什么是字符串:多个字符组成的【只读】字符【数组】(只读:明天我们要学习的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全局对象给代替了 - 有一天我们会学习后端语言Node.js(到时候你就会见到global)
				如果有一天你发现有个方法前面没有对象,则一定是window对象,window对象可以省略不写

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

   为什么undefined和null不能使用. - 没有包装类型
只读:拿个变量接住结果
*****StringAPI:只有字符串可以使用的函数,无需创建,程序员直接使用
1、转义字符:\
	作用:1、将字符串中和程序冲突得分字符转为原文
			"\""
	      2、包含特殊功能的符号
			\n - 换行
			\t - 制表符,你平时敲一下tab
	     *3、输出unicode编码的字符
			\uXXXX:
			第一个汉字:4e00		-	19968
			最后一个汉字:9fa5	-	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 i=-1;//-1			  22
		while((i=str.indexOf("no",i+1))!=-1){
			console.log(i);
		}

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

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

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

9、*****切割/分割字符串:
	作用:将字符串转为数组  arr <=> str
	var arr=str.split("自定义切割符")
	特殊:
		1、切割后,切割符就不存在
		2、切割符"",切散每个字符
扩展:3步

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

2、为其设置必要的东西 elem.属性名="属性值"; elem.on事件名=function(){}

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