JS的第三周总结

200 阅读11分钟

history对象

    前进:history.go(正数)
    后退:history.go(负数)
    刷新:history.go(0)
    

location对象

    常识:
        1.协议:http(未加密)/https(加密)/ftb(传输文件)/ws(直播)
        2.主机号/域名/IP地址
        3.端口号:https默认端口为443,http默认端口为80,只有默认端口可以省略不写
        4.文件的相对路径/路由
        5.查询字符串/请求消息:前端传输到后端的东西
        
    完整: 协议//域名:端口号/路由?请求消息
    
    属性:
        协议:location.protocal
        域名:location.hostname
        端口号:location.port
        路由:location.pathname
        请求消息:location.search
        

DOM:

    核心DOM:能操作HTML和XML
    HTMLDOM:只能操作HTML
    XMLDOM:只能操作XML,被淘汰
    
    通过css选择器去查找元素:
        var elem=document.querySelector("任意css选择器");
        缺点:只能找到单个元素,一次只能操作一个元素
        
       var elems=document.querySelectorAll("任意css选择器");
       优点:
           1.找到的是一个集合
           2.复杂查找时,简单明了
           3.返回的是一个静态集合NodeList
     getxxx 和 queryxxx的区别,也是动态集合和静态集合的区别,后者更适合复杂查找
         动态集合:每一个DOM发生变化,都会再次查找页面元素,让页面和数据保存一致,但效率降低 - 不支持forEach
         静态集合::每一个DOM发生变化,不会再次查找页面元素,让页面和数据保存不一致,效率提高 - 支持forEach
         
   操作样式:
          内联样式:
              获取: elem.style.css属性名
              设置: elem.style.css属性名="属性值"
              
          操作属性:
              获取:
                  核心DOM: elem.getAttribute("属性名")
                  HTMLDOM elem.属性名
              设置:  
                  核心DOM: elem.setAttribute("属性名")
                  HTMLDOM elem.属性名="属性值"
           
          删除属性:
              核心DOM: elem.removeAttribute("属性名")
              HTMLDOM: elem.属性名=""
          
          判断有没有 推荐用elem.hasAttribute去获取再写比较运算判断
              核心DOM: elem.hasAttribute("属性值")
              HTMLDOM: elem.属性名!=""
              
    操作内容: 
            innerHTML/innerText/value
            

如何创建元素以及上树

        1.创建空标签
            var elem=document.createElement("标签名")
        2.为其设置必要的属性和事件
            elem.属性名="属性值"
            elem.on事件名=function(){}
        3.上树
            父元素.appendChild(elem)
            
        删除元素:
            elem.remove()
        

input/textarea的专属事件:

onfocus(获得焦点)和onblur(失去焦点)

let 变量名=值

作用:
    1.解决了声明提前,一定先创建后使用
    2.带来了块级作用域,一个{}就是一个块
    3.如果用let下标去绑定事件,他会记录当前元素的下标,不需要再自定义下标,forEach的形参i也是用let创建的
    

递归

    在函数中再一次调用函数自己,但总会让他停下来
    何时使用:专门用于[遍历层级不明确]的情况
        function 函数名(root){
            1.root第一层要做什么直接做
            2.判断有没有下一层,如果有下一层,则再次调用此方法,但传入的实参是自己下一层
        }
       函数名(实际根元素)
    算法:深度优先算法,优先遍历当前节点、子节点遍历完毕才会跳到兄弟节点
    缺点:不用过度使用,性能较差,同时开启大量的函数调用,浪费内存
    

绑定事件

    1、在HTML页面上书写事件属性
	<elem on事件名="函数名()"></elem>
	缺点:
		1、不符合内容(HTML)与样式(CSS)与行为(JS)的分离
		2、无法动态绑定,一次只能绑定一个元素
		3、不支持绑定多个函数对象

2、*在JS中使用事件处理函数属性
	elem.on事件名=function(){操作}
	优点:
		1、符合内容(HTML)与样式(CSS)与行为(JS)的分离
		2、动态绑定,一次可以绑定多个元素
		3、不存在兼容性问题
	缺点:
		1、不支持绑定多个函数对象 - 个人觉得不算缺点

3、*在JS中使用事件API:如果不用考虑老IE的话,还是不错的
	主流:elem.addEventListener("事件名",callback)
	老IE:elem.attachEvent("on事件名",callback)
	兼容:
		if(elem.addEventListener){
                        	elem.addEventListener("事件名",callback)
		}else{
			elem.attachEvent("on事件名",callback)
		}
	优点:
		1、符合内容(HTML)与样式(CSS)与行为(JS)的分离
		2、动态绑定,一次可以绑定多个元素
		3、支持绑定多个函数对象
	缺点:
		具有兼容性问题:老IE不能使用

属于BOM的重点:定时器+客户端存储技术+event(事件对象):

   事件周期:从事件发生,到所有事件处理函数执行完毕的全过程:
	1、捕获阶段:由外向内,记录着要发生的事件有哪些
	2、目标优先触发:目标元素->当前点击的实际发生事件的元素
	3、冒泡触发:由内向外,依次执行我们之前记录着的要发生的事件

   获取事件对象event:
            主流:会自动作为事件处理函数的第一个形参传入e
            老IE:event;
            兼容:event;

得到了事件对象event可以做
	1、获取鼠标的坐标/位置:3种
		获取鼠标相对于屏幕的坐标:e.screenX/Y;
		获取鼠标相对于浏览器窗口/客户端/文档显示区域的坐标:e.clientX/Y
		获取鼠标相对于网页的坐标:e.pageX/Y;

	2、阻止冒泡:
		主流:e.stopPropagation();
		老IE:e.cancelBubble=true; 
		兼容:e.cancelBubble=true;

	3、事件委托/利用冒泡:开发中常用,提升网页性能
		优化:如果多个子元素定义了相同或相似的事件操作,那么最好只给父元素绑定一次
		为什么:每一次绑定一个事件函数,其实都是创建了一个事件对象,创建的对象越多,网页的性能越差。
		目标元素:实际触发事件的元素
		主流:e.target;
		老IE:e.srcElement;
		兼容:e.srcElement;

	4、阻止浏览器的默认行为:
		主流:e.preventDefault();
		老IE:e.returnValue=false;
		兼容:e.returnValue=false;

            右键事件 - window.oncontextmenu
	键盘事件:一般用于游戏开发比较多 + 都要搭配上键盘的键码
		window.onkeydown - 按下和按住都会触发,而且任何按键都会触发
		window.onkeypress - 按下和按住都会触发,但是只有数字、字母、回车、空格可以触发,其他不行
		window.onkeyup - 松开的时候才会触发,而且任何按键都会触发
           
           获取键盘的键码:
                    e.keyCode - 可以获取到按了哪个键,每个键都有自己对应的键码
                    
           事件的取消绑定:
                    1.如果你用的elem.on事件名=()=>{},那么你想要取消绑定:elem.on事件名=null

                    2.如果你用的elem.addEventListener("事件名",f1),那么你想要取消绑定:
	elem.removeEventListener("事件名",f1),事件名和回调函数,必须和添加时一模一样,是同一个
           
           this的指向:指向非常的多
                    1.单个元素绑定事件,this->这个元素
                    2.多个元素绑定事件,this->当前触发事件的元素
                    3.箭头函数中的this->外部对象
                    4.函数中的this->当前正在调用函数的这个人
                    5.定时器的this->window
           
           ES5强制改变this的指向:
                   call/apply:临时的替换了函数之中的this - 借用
	语法:
		1.函数名.call(借用的对象,实参,...) - 单独传入每个实参 
		2.函数名.apply(借用的对象,arr) - 只能传入一个实参,要求必须是一个数组:apply其实悄悄会将数组打散

	强调:call/apply,相当于立刻调用函数,是会立刻执行的,而且会还给别人,才叫借用

bind:永久的替换了函数中的this - 买
	语法:var 新函数=函数名.bind(指定对象,永久的固定的实参);
	3件事:
		1.创建了一个和原函数功能完全相同的新函数
		2.将新函数中的this永久绑定了为指定对象,别人都借不走
		3.将新函数的部分参数永久固定的
	强调:
		1.bind绑定的新函数没办法被call/apply再次借走!
		2.买是不会立刻调用的,需要自己手动调用一下
            三个固定套路:
		1.Math.max/min.apply(Math,arr);
		2.类数组转为普通数组:
			老方法:接住=Array.prototype.slice.call/apply(类数组)
			新方法:接住=Array.from(类数组)
            如何判断x是不是一个数组,千万不要用typeof,他只能判断原始类型
            Object.prototype.toString.call(x)=="[object Array]" 只要得到的结果为true说明就是一个数组
           
           ES5 - 严格模式:很严格 - 可以在任意作用域的顶部写上一句话:"use strict";
                  1.全局污染会报错
                  2.将静默失败升级为报错         
           
           模板字符串:
                   可以直接识别变量,不需要用+运算再去拼接了,而且实现了一个简单的JS的环境,甚至支持在里面使用API做操作
	`我的名字叫${name}`
            
            解构赋值:
                  解析结构再进行复制;如果赋值符号,左右两边的结构是一样的,他就会解开/脱掉结构再一一进行赋值
	如何使用:
		1.类似数组的解构赋值
			var [a,b,c]=[1,2,3];
			console.log(a);
			console.log(b);
			console.log(c);

		2.类似对象的解构赋值
			var {a,b=默认值,c}={a:1,c:3}
			console.log(a);
			console.log(b);
			console.log(c);

		3.调用函数时,传递实参的顺序无所谓了 - 往往很多框架之中!都会用到这个解构赋值
			function zwjs({name,age=默认值,hobby}){
				return `我的名字叫${name},今年${age}岁,喜欢${hobby}`;
			}
			console.log(zwjs({age:18,hobby:"吃饭",name:"袍哥"}));

		4.函数的返回的结果,可以有多个了
			function f1(){
				var a=1;
				var b=2;
				return [a,b];
			}
			var [a,b]=f1();
			console.log(a);
			console.log(b);

		只要以后见到:方法名({里面放着很多很多的的键值对,那么他的底层就是用到了ES6的解构赋值,键值对写入的顺序其实是随意的})
		见识一下layUI.js

                新的循环:for...of :
                    for(var v of arr){
                            v - 当前值
                    }

                    缺点:
                            1.因为没有提供过下标,不能操作原数组,只能返回新数组
                            2.只能遍历索引数组,不能遍历hash数组(也不能遍历对象)

               Set和Map:两个新的数据类型
                            1.Set:有一点点用,类似于数组的一种数据格式,但是远不如数组(没几个API,能做的事少) - 去重数组,然后再转回数组
                            [...new Set(arr)];
                            ... - 扩展运算符,可以脱掉数组/对象的衣服
                            不需要记忆set任何的API,完全比不上数组的API

                            2.Map:类似于对象的一种数据格式,完全不如对象
                正则表达式:定义字符串中字符出现规则的表达式
                何时使用:切割、替换、【验证】
                如何使用:语法:/正则表达式/;
                            1.最简单的正则就是关键字原文:"no"	->	/no/后缀
                                    后缀:g:找全部		i:忽略大小写
                            2.备选字符集:/[备选字符集]/;
		强调:
			1.一个中括号,只管一位字符
			2.前加^后加$,两者同时使用,代表要求从头到尾[完全匹配] - /^[备选字符集]$/;
		特殊:如果备选字符集中ASCII码是连续的,那么可用-省略掉中间部分
		比如:
			一位数字:[0-9]
			一位字母:[a-zA-Z]
			一位数字、字母、下划线:[0-9A-Za-z_]
			一位汉字:[\u4e00-\u9fa5]
			一位数字、字母、下划线、波浪号、汉字:[0-9A-Za-z_~\u4e00-\u9fa5]
                            除了xxx之外的:[^0-9] - 很少使用,范围太广了
                    			
	3.预定义字符集:前辈们提前定义了一些字符集,为了方便程序员开发 - 简化了备选字符集
                            一位数字:\d
                            一位数字、字母、下划线:\w
                            一位空白字符:\s - 什么叫空白字符:空格、制表符、换行

                            一位除了换行外的任意字符:. - 很少使用,范围太广
            建议:优先使用预定义字符集,预定义满足不了再用备选字符集补充
            
            4.量词:规定一个字符集出现的次数
		1.有明确数量:
			字符集{n,m}:前边相邻的字符集最少出现n个,最多出现m个
			字符集{n,}:前边相邻的字符集最少出现n个,多了不限
			字符集{n}:前边相邻的字符集必须出现n个

		2.无明确数量:
			字符集?:前边相邻的字符集,可有可无,最多1个
			字符集*:前边相邻的字符集,可有可无,多了不限
			字符集+:前边相邻的字符集,至少一个,多了不限
            5.选择和分组:
		选择:在多个规则中选一个,选择往往都要和分组进行搭配
			规则1|规则2
		分组:将多个字符集临时组成一组子规则
			(规则1|规则2)
            6.指定匹配的位置
		开头:^
		结尾:$
		*特殊:两者如果同时使用,前加^后加$,表示从头到尾要求完全匹配 - 只要你做[验证]
            7.密码强度验证:2-4位,可以输入数字、字母,但是必须出现一位大写和一位数字
		/^[0-9A-Za-z]{2,4}$/
		预判公式:
			(?![0-9]+$) -> 不能全由数字组成,可能有大写、小写、汉字、日文、韩文、特殊符号...
			(?![0-9a-z]+$) -> 不能全由数字组成,也不能全由小写组成,也不能全由数字和小写的组合组成,可能有大写、汉字、日文、韩文、特殊符号...
			(?![0-9A-Za-z]+$) -> 不能全由数字组成,也不能全由小写组成,也不能全由数字和小写的组合组成,也不能全由数字和大写的组合组成,也不能全由大字和小写的组合组成,也不能全由数字和大写和小写的组合组成,

		//2-4,可以输入数字、字母、但是必须出现一位大写和一位数字的组合
			var reg=/^(?![0-9a-z]+$)(?![A-Za-z]+$)[0-9A-Za-z]{2,4}$/;
		//2-4,可以输入数字、字母、但是必须出现3者的组合
			var reg=/^(?![0-9a-z]+$)(?![A-Za-z]+$)(?![A-Z0-9]+$)[0-9A-Za-z]{2,4}$/;
            
            支持正则的字符串API:
                    1.切割:var arr=str.split("固定切割符"/RegExp);

                    2.替换:很有可能出现在笔试面试中,而且真实开发也会遇到
                            1.基础替换法:
                                    var newStr=str.replace(RegExp,"新内容");
            
            2.高级替换法:
		var newStr=str.replace(/[卧我握窝][槽肏操草曹糙去]+/g,function(key,i,str){
			console.log(key);//关键字
			console.log(i);//关键字的下标
			console.log(str);//原文本身
			return a.length==2?"**":"***";
		});

	3.格式化:
		var idCard="500103198602215933";
		var reg=/(\d{6})(\d{4})(\d{2})(\d{2})(\d{4})/;
		var newStr=idCard.replace(reg,function(a,b,c,d,e,f,g,h){
			//在replace的时候,如果正则中出现了分组,那我们会得到更多的形参
			//在形参key的后面就会出现n形参,具体有多少个,看你有多少个分组
			//第1个分组获得的内容回保存到第2个形参之中
			//第2个分组获得的内容回保存到第3个形参之中
			//第3个分组获得的内容回保存到第4个形参之中
			//...
			//倒数第二个是下标
			//倒数第一个是原文
			return `${c}年${d}月${e}日`;
		})
            
            正则对象:
                    创建:
                         1.直接量:var reg=/正则表达式/后缀;
                         2.构造函数:var reg=new RegExp("正则表达式","后缀");

                    API:
                         验证:var bool=reg.test(str);
                         true->验证成功	false->验证失败
            
               边输入边判断:input.oninput
	   鼠标松开:onmouseup