JavasScript

121 阅读13分钟

# 1、自定义Function: 什么是函数:需要先定义好,可以反复使用的一个代码段 何时使用:1、不希望打开页面立刻执行 2、以后可以反复使用 3、希望绑定在页面元素之上 如何使用:

1、创建并且调用:2种

	1、创建
	       *1、【声明方式】创建函数
		   function 函数名(形参,...){
			函数体;
			return 返回值/结果;
		   }

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

	2、调用
		var 接住返回的结果=函数名(实参,...);

		//其实return的本意退出函数,但是如果return后跟着一个数据,
		//顺便将数据返回到函数作用域的外部,但return只负责返回,不负责保存
		//就算省略return,默认也会return undefined;
		//具体需不要得到函数的结果,看你自己

2、***作用域:2种

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

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

		*变量的使用规则:优先使用自己的,自己没有找全局,全局没有报错
		特殊:缺点:1、千万不要再函数中对着未声明的变量直接赋值 - 全局污染
			    2、局部可以用全局的,但是全局不能用局部的 - 解决:看上面return
	

3、***声明提前:

	在程序正式执行之前
	将var声明的变量(轻)和function声明的函数(重)
	都会悄悄集中定义在当前作用域的顶部
	但是赋值留在原地

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

	何时使用:永远不会自己使用,垃圾干扰我们判断 - 只会在鄙视中遇到,为什么平时开发根本不可能遇到它?
		只要你遵守以下原则:
			1、变量名和函数名尽量的不要重复
			2、先创建后使用
			3、如果鄙视时需要先试用后创建,多半都是在考你声明提前

4、***按值传递:两个变量之间赋值,分两种情况

	如果传递的是原始类型的值:
		修改一个变量,另一个变量是不会受到影响的,其实是复制了一个【副本】给对方

	如果传递的是引用类型的对象:
		修改一个变量,另一个变量是会受到影响的,引用类型其实根本没有保存到变量中,仅仅只是保存了一个地址值
		两者用的是同一个地址值,所以会相互影响

2、预定义全局函数:前辈们提前定义好的,我们程序员可以直接使用的,在任何位置都可以使用

*parseInt/Float/isNaN/eval... 其实都是预定义全局函数,但是alert/prompt不属于我们现在学的范畴:确实也是全局预定义函数,只不过属于BOM

1、编码和解码

      问题:url中不允许出现多字节字符(汉字,utf-8编码格式下,一个汉字占3字节),如果出现会乱码
      解决:发送前,前端将多字节字符编码为单字节字符(数字、字母、符号)
	发送后,后端将单字节字符在解码为多字节原文
      如何:
	编码:var 不认识=encodeURIComponent("大梵");
	解码:var 原文=decodeURIComponent(不认识);
     这个东西没有用,在某一次浏览器更新后,当前就被淘汰了,浏览器自带此功能 - 唯一的用处,现在就是玩了:悄悄话

2、isFinite(num):判断num是不是有效范围 - 垃圾并不能用于判断是不是NaN,因为有三个人会是false

	哪些会为false:NaN,Infinity,分母为0

3、***分支结构:根据条件的不同,选择部分代码执行

1if分支
2、三目&短路
3switch...case...语法
	switch(变量/表达式){
		case1:
		操作1;
		case2:
		操作2;
		case3:
		操作3;
		default:
		默认操作;
	}
	特殊:1、不具备隐式转换
	           2、问题:默认只要一个case满足后,就会将后面所有操作全部做一次
		解决:break;
		建议:每一个case的操作后都要跟上一个break
			有的地方可以不加break:
				1、最后一个操作default可以省略break
				2、如果中间连续的多个操作,是相同的,也可以省略掉中间部分
		
	面试题:if  vs switch
	1switch:缺点:必须要知道最后的结果才能使用,不能做范围判断
		  优点:执行效率相对较高

	2if         : 优点:可以做范围判断
		 缺点:执行效率相对较慢

	建议:代码优化:尽量的将if替换为switch或者三目或短路
      

1、***循环结构:宏观几乎是一瞬间执行的,相同 或 相似的 代码

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

2do...while循环语法:
      var 循环变量=几; 
      do{
	操作;
	变量变化;
       }while(循环条件)

**面试题:whiledo...while的区别?
	只看第一次,如果大家都满足,则没区别
		   如果不满足,while一次都不执行,而dowhile至少会执行一次**
      
3、*for(var 循环变量=几;循环条件;变量变化){
	操作;
      }

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

5、死循环:while(true){}		for(;;){}

forEach for in for of - 专门为遍历数组准备的

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

1、什么是数组:一个集合可以保存多个数据
         何时使用:多个相关的数据,都要集中的定义在一个集合中
         为什么:因为一个好的数据结构,能够极大的提升我们程序员的开发效率

2、创建:2种
	1、*直接量方式:var arr=[值1,...];
	2、构造函数方式:var arr=new Array(值1,...);
			坑:new Array(num); - 懂不起:以为你是创建了一个长度为num的空数组

3、访问:数组名[下标];
     添加/修改:数组名[下标]=新值;
     特殊:访问时,下标越界 - 返回undefined
               添加时,下标越界 - 变为稀疏数组,导致下标不连续,导致以后遍历一定会得到undefined

4、数组三大不限制
	1、不限制类型
	2、不限制长度
	3、不限制下标越界 - 不推荐

5、数组唯一的一个属性:数组名.length - 获取数组的长度
	三个固定套路:
		1、末尾添加:arr[arr.length]=新值
		2、获取倒数第n个:arr[arr.length-n];
		3、缩容: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循环遍历数组,语法:
		for(var i in 数组名){
			console.log(i);//自动获得当前数组的所有的下标,不需要我们去设置从哪里开始到哪里结束
			console.log(arr[i]);//当前次元素
		}
	     牛逼:不光可以遍历hash数组,也可以遍历索引数组:
	     建议:hash用for in,索引用for

	4、*js中一切东西都是对象,万物皆对象,除了undefined和null,【一切对象的底层都是hash数组】

3、*****数组的API:数组的函数,前辈们定义好的,只有数组可以使用

1、*****arr 转为 str:

1、语法:var str=arr.join("自定义连接符");
	作用:
	   1、鄙视时:给你一个数组,将他无缝拼接在一起:
		var arr=["h","e","l","l","o"];
		var str=arr.join("");
		console.log(str);

	   2、拼接为页面元素:
		//以后从数据库中取出数据
		var cities=["-请选择-","北京","南京","西京","东京","重庆"];
		//拼接成页面元素后,innerHTML是识别标签的
		sel.innerHTML="<option>"+cities.join("</option><option>")+"</option>";

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

语法:var newArr=arr.concat(值1,arr1,...);
特殊:1、此方法不修改原数组,只会返回一个新数组
           2、支持传入数组参数,悄悄的将我们传入的数组打散,不会变成二维数组

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

语法:var subArr=arr.slice(starti,endi);
特殊:1、此方法不修改原数组,只会返回一个新数组
           2、含头不含尾
           3、第二参数可以省略不写,截取到末尾
           4、第一个参数也可以省略不写,如果两个参数都没写,从头截取到尾 - 深拷贝(复制了一份副本)
           5、支持负数参数,-1代表倒数第一个

以上的API都不会修改原数组


以下的API都会修改原数组

4、*删除、插入、替换:

删除:var dels=arr.splice(starti,n);//n代表删除的个数
    特殊:此方法其实也有返回值,返回的就是你删除的元素组成的一个新数组
插入:arr.splice(starti,0,新值1,....);
    特殊:1、没有删除,也有返回值,返回的是一个空数组
               2、原starti位置的元素以及后续元素都会向后顺移
               3、不建议插入数组,会变得不伦不类
替换:var dels=arr.splice(starti,n,新值1,....);
    特殊:删除的个数和插入的个数不必相同

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

1、*****Array API

1、*****排序:

     1、鄙视时:不允许使用数组的API - 冒泡排序:拿着数组中的每一个元素,
	       让前一个和后一个做比较,如果前一个>后一个,两者应该交换位置:固定公式
		var arr=[32,14,43,453,6,58,56,531,5,57];
		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号,默认是按照字符串排序
	问题1:希望按照数字升序排序
	解决:
		arr.sort(function(a,b){
			return a-b;
		});
	原理:1、匿名函数回调,一般都是前辈们规定好的,我们只能学习怎么使用,自动调用,而且有多少对儿就会调用多少次
	           2a:后一个数字    b:前一个数字
	           3、返回结果,如果是正数,说明后一个大
		                 如果是负数,说明前一个大
			如果是0,说明一样大
	            4、而我们的sort方法会根据你返回的正数负数0,来判断要不要交换位置

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

	建议:开发中使用API排序,鄙视可能会碰到冒泡排序
	强调:切记前端所有技术中:唯独只有数组可以排序,意味着以后如果网页中有一个排序功能,说明他的底层一定是一个数组

2、栈和队列:

	栈:其实就是一个数组,只不过要求只能从一端进出,另一端是封闭的
	何时:始终希望使用最新的数据时,现实中很少,代码中也很少
	如何:
		前进:arr.unshift(新元素,...)	-      添加元素的新方式,建议不要添加数组
		前出:var first=arr.shift();	-      删除元素的新方式,一次只能删除一个,而且是第一个

		后进:arr.push(新元素,...)	-      添加元素的新方式,建议不要添加数组
		后出:var last=arr.pop();	-      删除元素的新方式,一次只能删除一个,而且是最后一个

	队列:其实就是一个数组,只不过要求一端进,另一端出
	何时:按照先来后到的顺序
	如何:
		前进:arr.unshift(新元素,...)	-      添加元素的新方式,建议不要添加数组
		后出:var last=arr.pop();	-      删除元素的新方式,一次只能删除一个,而且是最后一个

		后进:arr.push(新元素,...)	-      添加元素的新方式,建议不要添加数组
		后出:var last=arr.pop();	-      删除元素的新方式,一次只能删除一个,而且是最后一个

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

 何时使用:在一个数组内,希望再次细分每个分类
 如何使用
 	创建:
var arr=[
	["杨杰",18,1200],
	["周洁",19,1500],
	["盛蕾",20,3500]
];

访问: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的概念:

1、什么是字符串:多个字符组成的【只读】字符【数组】:

	1、只读:我们下周一要学习的所有的字符串的API,都不会修改原字符串,只会返回一个新字符串
	2、数组:和数组有相同点:
		1、可以使用下标得到某个字符
		2、可以使用length获取字符串的长度
		3、遍历字符串
		4、数组不修改原数组的API,字符串也可以使用(拼接 - 垃圾还不如直接+运算,截取)
	      当然和数组也有很多的不同点,数组修改原数组的API,字符串一个都用不到,字符串也有十几个API等待我们学习

2、引用/对象类型:11个

	*String Number Boolean - > 具有包装类型
	*Array *Function Math(数学) Date(日期) *RegExp(正则表达式:验证) 
	Error(错误)
	*Object(面向对象)
	Global - 全局对象:在前端/浏览器端/客户端/js中被window代替了:功能:保存着全局变量和全局函数,只有window可以省略不写

3、***包装类型:专门用于将原始类型的值封装为一个引用类型的对象的(带来了属性和方法)

              为什么:原始类型的值原本是不具备任何属性和方法的,但是前辈们发现我们程序员会经常操作到字符串
	           前辈们为了方便我们程序员,为三个原始类型提供了包装类型
           何时使用:只要试图用原始类型的变量去用.调用属性和方法时,就会悄悄的用上包装类型变为对象
           何时释放:方法调用完毕后,自动释放包装类型,并且返回数据(又会变回原始类型)

           为什么undefinednull不能用. - 没有提供包装类型
               

1、StringAPI:只有字符串可以使用的函数,特点:只读!

1、转义字符:\

	作用:
	   1、将字符串中和程序冲突的符号编译为原文
		"\""	'\''
	   2、包含特殊功能的符号:
		换行:\n
		制表符:\t
	  *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位置开始,查找右侧【第一个关键字】的位置
	特殊:
	   1、starti可以省略不写,从0开始查找
	   2、返回值:找到了,返回的第一个关键字的第一个字符的下标
		    *没找到,返回-1,我们不关心下标为多少,我只关心下标为不为-1
	         作用:判断有没有,以后如果不想有重复的,就一定要用上他
	   3、此方法不光字符串可以使用,数组也可以使用,后期才为数组添加上的,老IE上的数组就没有此方法
	   4、笔试题:默认只能获取到第一个关键字的下标,如何才能获取到所有的关键字的下标
		var str="no zuo no die no can no bibi";
		var i=-1;
		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、*****切割/分割字符串:

	var arr=str.split("任意切割符");
	作用:将字符串=>数组
	特殊:1、切割后,切割符就不存在了
	           2、切割符"",切散每一个字符

扩展:如何使用JS生成元素:3步

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

2、为此元素设置必要的属性 或 事件
	elem.属性名="值";
	elem.on事件名=function(){}

3、渲染页面,上DOM树:
	父.appendChild(新);