第三周js笔记

168 阅读12分钟

BOM常用对象

1、history常用对象,保存了当前窗口的历史记录

  • 前进:history.go(1);
  • 后退:history.go(-1);
  • 刷新:history.(0);

2、location对象:保存当前窗口正在打开的url

url的组成部分:

  1. 协议:https(加密)/http(未加密)/ftp(传输文件)/ws(直播),前两个都属于响应模式;
  2. 主机号/IP地址/域名:域名是需要花钱购买的,主机号和IP地址免费;
  3. 端口号:https默认端口为443,http默认端口是80,只有默认端口可以省略不写;
  4. 文件的相对路径/路由:百度加密了
  5. 查询字符串/请求消息:前端传输到后端的东西,前端对后端的话;

属性:获取url的五个部分的内容,但是不需要记忆,直接输入location即可进行查看:location.protocal协议;location.hostname域名;location.port端口;location.pathname路由;location.search请求信息;

跳转:location:"新url"-替换当前窗口,可以后退
跳转后禁止后退:location.replace("新url")-替换当前窗口,禁止后退;
刷新:location.reload();

DOM

  1. 查找元素:通过关系查找,直接查找
  • document.getElementsByXXXX(); - 返回的是一个动态集合HTMLCollection
  • var elem=document.querySelector("任意css选择器的"); //query-查询 selector-选择器:查询css选择;缺陷:只能找到单个元素,如果匹配到了多个,也只会返回第一个,没找到null
  • var elems=document.querySelectorAll("任意css选择器的");
  1. 找到了是一个集合,没找到是一个空集合
  2. 复杂查找时,非常简单
  3. 返回的是一个静态集合NodeList

两者区别: 1、后者更适合复杂查找
2、动态集合和静态集合的区别?
1、动态集合:每一次DOM发生变化,他都会悄悄的再次查找,让页面和数据保持一致,但是效率也就低下了 - 不支持forEach
2、静态集合:每一次DOM发生变化,他不会悄悄的再次查找,让页面和数据没有保持一致,但是效率也就高了 - 支持使用forEach

  1. 操作样式
  • 内联样式
  • 样式表样式 获取你想要操作的样式表:var sheet=document.styleSheets[i];
    获取此样式表中所有的样式规则:var rules=sheet.cssRules;
    数出你想要操作的那个规则的:var rule=rules[i];
    操作:
    console.log(rule.style.css属性名);
    rule.style.css属性名="css属性值";
  1. 操作属性 1、获取属性值:核心DOM:elem.getAttribute("属性名");
    HTML DOM:elem.属性名;
    2、设置属性值:核心DOM:elem.Attribute("属性名","属性值");
    HTML DOM:elem.属性名="属性值"; 3、删除属性:设置属性值为空字符串,某些属性可以算删除,但是只是删除属性值,属性名还在,有些属性只有属性名也会有具体作用;
    核心DOM:elem.removeAttribute("属性名");
    HTML DOM:elem.属性名="";属性节点删不干净;

4、判断有没有,只能判断有没有,不能判断是什么,推荐用getAttrribute("属性名"),去获取值,在进行比较运算;
核心DOM:elem.hasAttribute("属性名");
HTMLDOM:elem.属性名!="";

优先使用HTML,DOM,HTML;DOM实现不了的再用核心DOM补充,缺陷:
1、class必须写为className;
2、自定义的东西都操作了了;

4、操作内容:innerHTML/innerText/value

5、创建元素及上树:

  1. 创建标签;
  2. 为其设置必要的属性和事件;
  3. 上树

6、删除元素:elem.remove();
扩展:创建变量,新增的一个let关键字
let变量名:值;
作用:

  1. 解决了声明提前;
  2. 带来了块级作用域,一个{}就是一个块,此变量只能在那个{}内使用;
  3. 如果使用let去当下标绑定事件,那么他会记录这你当前元素的下标,不再需要你自定义下标了,其实就是forEach的那个形参i就是let创建的;

2、类数组转为普通数组:接住=Array.from(类数组对象);

递归

  • 在函数之中再一次调用自己,迟早会停下来;
  • 何时:专门用于遍历层级不明确的情况,DOM树和数据(children只能找到儿子层,找不到孙子层)
  • 使用:
  •       function 函数名(root){
      1、第一层要做什么直接做
    
      2、判断有没有下一层,如果有下一层则再次调用此方法,只不过传入的实参是自己的下一层	 
              }
             函数名(实际的根)
    
    

算法:深度优先!优先遍历当前节点的子节点,子节点遍历完后才会跳转到兄弟节点;
缺陷:不要过多使用,性能相对较差,同时开启大量的函数调用,浪费内存,我们只在层级不明确的情况下才会使用;
递归相比于纯循环
递归:简单实用,但是性能低;
纯循环:几乎不占用内存,但是相当难;

BOM的重点:定时器和event(事件对象)

  1. 事件周期:从事件发生到事件处理函数执行完毕的全过程。3个阶段:
  • 捕获阶段:由外向内,记录着要发生的事件有哪些
  • 目标优先触发:目标元素,当前点击的实际发生事件的元素;
  • 冒泡触发:由内向外,依次执行之前记录的要发生的事件;
  1. 获取事件对象event
  • 主流:会自动作为事件函数的第一形参传入
  • 老IE:event,老IE全局有这个变量
  • 兼容:event,老IE可用,主流也可用

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

2、阻止事件冒泡:笔试面试中;
主流:e.stopPropagation();
老IE:e.cancelButton=true;
兼容:e.cancelButton=true;,老IE可用,主流也可用

  1. 利用冒泡事件/事件委托:开发中常用,提升网页性能,事件函数可以转换为箭头函数了;
  • 优化:如果多个子元素定义了相同或者相似的事件操作,最好只给父元素定义一次;
  • 原因:每一次绑定一个事件函数,其实都是创建了一个事件对象,创建的事件对象越多,网站性能越差;
  • 淘汰了this,他指当前元素
  • 认识一个新元素target,点击哪一个他永远是那一个,不会变化的;
  • e.target;e.srcElement;
  1. 阻止浏览器默认行为:a标签的默认就可以提交表单,右键自带一个弹出框,f12自带一个控制台,f11自带全屏功能,f5自带刷新功能;
    主流:e.preventDefault();
    老IE:e.returnValue=false;
    兼容:e.returnValue=false;//第4次见到小三上位,不光老IE可用,主流也可用

新事件:
1、右键事件 - window.oncontextmenu
2、键盘事件:一般来说用于游戏开发较多+都要搭配上键盘的键码
window.onkeydown - 按住和按下,任何键盘按键都可以触发
window.onkeypress - 按住和按下,只有字母、数字、回车、空格可以触发,其他按键不行
window.onkeyup - 松开,任何键盘按键都可以触发(比手速的游戏)

  1. 获取键盘上的键码:e.keyCode; - 可以获取到你按了那个键,每个键都有自己对应的键码,但是不需要记忆,要么输出看,要么百度搜个表

event可以说是BOM之中最最重要的一个点,其他点就算你不用,你也要知道,笔试面试只要考BOM多半都是event

老IE:不支持HTML5和CSS3和ES5+

1、事件的取消绑定

  • 如果你使用elem.onclick=()=>{},那么elem.onclick=null
  • 如果你使用elem.addEventListener("事件名",回调函数); 那么:elem.removeEventListener("事件名",回调函数); - 事件名和回调函数,必须和添加时的一模一样

2、this的指向:单个元素绑定事件this->这个元素,多个元素绑定事件this->当前元素,箭头函数中的this->外部对象,函数中的this->当前正在调用函数的这个人,定时器的this->window;

3、Ess5强制改变this指向:

  • call/apply:临时的替换了函数的this - 借用
  • 语法:函数名.call(借用的对象,实参,...); - 单独传入每个实参
  • 函数名.apply(借用的对象,arr); - 只能传入一个实参要求是一个数组,apply其实会悄悄的打散数组
  • 强调:call/apply:相当于立刻调用函数,立即执行的
  • bind:永久替换了函数中的this - 买

3件事:

  1. 创建了一个和原函数功能完全相同的新函数
  2. 将新函数的this永久绑定为了指定对象,别人都借不走
  3. 将新函数的部分参数永久固定
  • 语法:var 新函数=函数名.bind(永久对象,永久实参,...); - 不是立刻执行,需要自己调
  • 强调:bind绑定的新函数没办法被call/apply再次借走
  • 以后不是自己的方法,可以用,个人推荐:借,白嫖!
固定套路
  1. Math.max/min.apply(Math,arr) - 也能支持数组参数:

  2. Object.prototype.toString.call/apply(x)==="[object Array]";//鄙视题:判断xx是不也是一个数组

  3. 类数组转为普通数组:
    1、接住=Array.prototype.slice.call/apply(类数组对象)
    2、接住=Array.from(类数组对象)

  4. ES6:
    1、学过了:let、const关键字、箭头函数

    2、模板字符串:可以直接识别变量,不再需要+运算去拼接了,而且实现了一个简答的js环境,甚至支持再里面书写API 我的名字叫${name}

解构赋值

  • 赋值新方式,并得到了增强;
  • 如果赋值符号左右两边的结构一样的,就会悄悄的解开/脱掉结构再一一进行赋值;
  • 语法:1、类似数组的解构赋值
    let [a,b,c]=[1,2,3];
	console.log(a);
	console.log(b);
	console.log(c);


2、类似对象的解构赋值:

                      let {a,b=默认值,c}={c:3,a:1,b:2};
				console.log(a);
				console.log(b);
				console.log(c);
				//形参可以设置默认值,如果自己传入了,就用自己的


3、调用函数时,传递实参的顺序就无所谓了

                          function zwjs({name,age,hobby="篮球"}){
				return `我的名字叫${name},今年${age}岁,喜欢${hobby}`;
				}
				console.log(zwjs({hobby:"学习",age:18,name:"楠"}));


4、函数的返回结果可以有多个

                                 function f1(){
					var a=1;
					var b=2;
					return [a,b];
				}
				var [a,b]=f1();
				console.log(a,b);


5、set和map新的数据类型:

  • Set:类似于数组的一种数据格式 - 【去重数组,然后再转回数组】
  • var s=new Set(arr);
  • ...s - 三个点扩展运算符,可以脱掉数组的外套
  • 一句话完成:[...new Set(arr)] - 不用记忆任何API

map类似于一个对象的一种数据格式

                        var m=new Map();
			添加:m.set("键","值");
			获取:m.get("键");
			清空:m.clear();
			删除:m.delete("键");


新的循环:带过,以后不用;

for(var v of arr){
			v;
		}


1、没有提供过下标,意味着不能修改原数组
2、只能遍历索引数组,不能遍历hash数组,意味着也不能遍历对象

正则表达式

  • 定义字符串中字符出现规则的表达式;
  • 使用:正则表达式语法
  • 最简单的正则表达式:原文"no"-/no/后缀;后缀+g找全部;再+i忽略大小写

备选字符集:

  • /^备选字符集$/
  • 强调:一个中括号只管一个字符串
  • 正则表达式默认只要满足就不管后续了,而我们希望用户按照我们的要求来,希望从头到尾安全匹配;
  • 解决:前加^,后加$,两者同时使用,代表要求从头到尾匹配备选字符集---只要做验证必须加;
  • 特殊:如果备选字符集的ASCII码是连续的,那么可以用-省略掉中间部分;
    一位数字:[0-9];一位字母:[A-Za-z];一位数字、字母、下划线:[0-9A-Za-z_];一位汉字:[\u4e00-\u9fa5]
    除了xxx之外的:[^0-9] - 很少使用,范围太广

预定义字符集:

  • 前辈们提前定义了一些字符集,方便我们简化备选字符集;
  • 一位数字:\d ===>[0-9];一位数字、字母、下划线:\w ===> [0-9A-Za-z_];一位空白字符:\s;一位除了换行外的任意字符:. - 很少使用,范围太广了
  • 建议:优先使用预定义字符集,预定义满足不了再用备选字符集补充
  • 不管是备选字符集还是预定义字符集,一个只管一位

量词

  • 规定一个字符集出现的次数;
  • 明确数量:字符集{n,m}:前边相邻的字符集,至少n个,最多m个
  • 字符集{n,}:前边相邻的字符集,至少n个,多了不限
  • 字符集{n}:前边相邻的字符集,必须n个
    无明确数量;
  • 字符集?:前边相邻的字符集,可有可无,最多1个
  • 字符集*:前边相邻的字符集,可有可无,多了不限
  • 字符集+:前边相邻的字符集,至少一个,多了不限

选择与分组:

  • 选择:多个规则中选一个 规则1|规则2
  • 分组:将多个字符集临时组成一组子规则(规则1|规则2)

指定匹配位置

^:开头;:结尾
特殊:两者同时使用,前加,后加:结尾
特殊:两者同时使用,前加^,后加:结尾
特殊:两者同时使用,前加,后加,表示从头到尾要求完全匹配--只能做验证;

密码强度验证

  • 2-4位,可以输入数字、字母,但是必须出现一位大写和一位数字的组合/^[0-9A-Za-z]{2,4}$/
  • 预判公式:(?![0-9]+$) -> 不能全由数字组成,可能有大写、小写、汉字、日文、特殊符号...
  • (?![a-z]+$) -> 不能全由小写组成,可能有数字、大写、汉字、日文、特殊符号...
  • (?![0-9a-z]+$) -> 不能全由数字组成、也不能全由小写组成、也不能全由数字和小写的组合组成

支持正则表达式的字符串API

  1. 切割:var arr=str.split("固定切割符"/RegExp);
  2. 替换:
  • 基本替换法 str=str.replace(/正则表达式/后缀,"新内容");
    replace支持支持正则,并且搭配上后缀g就可以找到全部
    缺陷:替换的新内容是一个固定的
  • 高级替换法
                               str=str.replace(/正则表达式/后缀,function(a,b,c){
				console.log(a);//正则匹配到的关键字
				console.log(b);//正则匹配到的关键字的下标
				console.log(c);//原字符串
				return 判断a关键字的长度,而返回不同的星星数量
			});


格式化身份证:

                        var id="533223200106231818";
			var reg=/(\d{6})(\d{4})(\d{2})(\d{2})(\d{4})/;
			id.replace(reg,function(a,b,c,d,e,f,g,h){
				//再replace的时候,正则出现了分组,我们会得到更多的形参
				//再形参a的后面就会出现n个形参,就看你有多少个分组
				//第1个分组获得的内容会保存在第2个形参之中
				//第2个分组获得的内容会保存在第3个形参之中
				//...
				//倒数第二个一定是下标
				//倒数第一个一定是原文本身
			})


总结:何时前加^后加$,何时又该添加后缀g

  1. 前加^后加$ - 验证
  2. 替换,你希望替换所有 - 必须加g

3、正则对象:
创建:

  1. 直接量:var reg=/正则表达式/后缀;
  2. 构造函数:var reg=new RegExp("正则表达式","后缀");

API:

            1、验证:var bool=reg.test(用户输入的);