JavaScript学习 --- 第三周

114 阅读16分钟

一. 递归

1.定义:

  递归简单来说就是函数自调, 循环会停止, 专门用于【遍历层级不明确的情况】 - DOM树和数据(children只能找到儿子层,找不到孙子层)

2.使用步骤:

        function 函数名(root){

1、写第一层的操作

 

2、判断有没有下一层,有再次调用此方法,传入的实参是自己的下一层

}

函数名(实际的根)

3.算法: 深度优先!优先遍历当前节点的子节点,子节点遍历完毕才会跳到兄弟节点

4.缺陷: 使用过多会降低浏览器性能同时开启大量的函数调用,浪费内存,只在【层级不明确】时使用

5.递归和纯循环对比

 

| 循环方式 | 优点 | 缺点 |

| --- | --- | --- |

|递归  | 简单易用 |性能低  |

|纯循环  | 性能高 |操作语句复杂,写起来相对困难 |

 

2.事件的绑定与取消

1.elem.on事件名=()=>{}绑定  使用elem.on事件名=null取消

2.绑定:elem.addEventListener("事件名",回调函数); 取消:elem.removeEventListener("事件名",回调函数);

事件名和回调函数必须一一对应

 

3.this的指向问题

1.this的指向

   单个元素绑定事件this->这个元素

   多个元素绑定事件this->当前元素

   箭头函数中的this->外部对象

   ***函数中的this->当前正在调用函数的东西

   定时器的this->window

2.强制改变this的指向

     (1) call/apply:临时的替换了函数的this - 借用

语法:函数名.call(借用的对象,实参,...); - 单独传入每个实参

                

     函数名.apply(借用的对象,arr); - 只能传入一个实参要求是一个数组,

                                                    apply其实会打散数组

                                                    

强调:call/apply:相当于立刻调用函数,立即执行的

 

     (2)bind:永久替换了函数中的this - 买

     

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]";

                        //笔试题:判断x是否是一个数组

                        

3、类数组转为普通数组:

1、接住=Array.prototype.slice.call/apply(类数组对象)

2、接住=Array.from(类数组对象)

 

4.ES6

1.已学部分: let,const关键字    箭头函数

2.模板字符串:可以直接识别变量,不需要+运算去拼接,而且实现了一个简单的js环境,甚至支持在里面书写API

我的名字叫${name}

3.解构赋值: 解析结构再进行赋值 - 赋值的新方式,并且得到了增强

如果赋值符号,左右两边的结构一样的,先解开结构再一一赋值

语法:

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

 

只要以后见到:方法名({键值对})就是使用了ES6的解构赋值

 

4.Set和Map - 新的数据类型:

1、*Set:类似于数组的一种数据格式 - 【去重数组,然后再转回数组】

var s=new Set(arr);

...s - 三个点扩展运算符,可以解开数组结构

一句话完成去重数组并转回数组:

                        [...new Set(arr)]

 

2、Map:类似于对象的一种数据格式

var m=new Map();

添加:m.set("键","值");

获取:m.get("键");

清空:m.clear();

删除:m.delete("键");

 

5.新的循环 - 没用

     for(var v of arr){

v;

}

 

缺陷:

1、没有提供过下标,不能修改原数组

2、只能遍历索引数组,不能遍历hash数组,也不能遍历对象

 

5.正则表达式:

定义字符串中字符出现规则的表达式

何时使用:切割 替换 【验证】!

如何使用:语法:/正则表达式/

一.基本属性

1.最简单的正则就是关键字原文 "no" -> /no/后缀

      后缀:

        g:找全部

        i:忽略大小写

2.备选字符集:/^[备选字符集]$/

       强调:

             1. 一个中括号,只管一位字符

             2. 问题:正则表达式默认只要前面几位设置了正则的字符满足就不管后边,

             而我们做验证的人,希望的是用户从头到尾按照我们的要求来,希望从头到尾完全匹配:

         3. 解决:前加^,后加,两者同时使用,代表要求从头到尾完全匹配/[备选字符集],两者同时使用,代表要求从头到尾完全匹配/^[备选字符集]/

                 - 只要做验证必加!

         4. 特殊:如果备选字符集中的ascii码是连续的,那么可用-省略中间部分

比如:

一位数字:[0-9];

一位字母:[A-Za-z];

一位数字、字母、下划线:[0-9A-Za-z_]

一位汉字:[\u4e00-\u9fa5]

 

除了xxx之外的:[^0-9] - 很少使用,范围太广

3.预定义字符集:前辈们提前定义的-,简化了备选字符集

                         一位数字:\d 等同于[0-9]

     一位数字、字母、下划线:\w 等同于[0-9A-Za-z_]

                         一位空白字符:\s

     一位除了换行外的任意字符:.   - 很少使用,范围太广

 

建议:优先使用预定义字符集,预定义满足不了我们再用备选字符集补充

 

问题:不管是备选字符集,还是预定义字符集,一个都只管一位

 

4.量词:规定一个字符集出现的次数:

                   1、有明确数量:

字符集{n,m}:前边相邻的字符集,至少n个,最多m个

字符集{n,}:前边相邻的字符集,至少n个,多了不限

字符集{n}:前边相邻的字符集,必须n个

 

2、无明确数量:

字符集?:前边相邻的字符集,可有可无,最多1个

字符集*:前边相邻的字符集,可有可无,多了不限

字符集+:前边相邻的字符集,至少一个,多了不限

5.选择和分组:

                    选择:在多个规则中选一个

规则1|规则2|...

分组:将多个字符集临时组成一组子规则

(规则1|规则2|...)

6.指定匹配位置

                    ^:开头

$:结尾

特殊:两者同时使用,前加^,后加$,表示从头到尾要求完全匹配

 

7.密码强度验证:/^[0-9A-Za-z]$/数字,大写,小写

      预判公式:

(?![0-9]+$) -> 不能全由数字组成,可能有大写、小写、汉字、日文、特殊符号...

                

(?![a-z]+$) -> 不能全由小写组成,可能有数字、大写、汉字、日文、特殊符号...

                

(?![0-9a-z]+$) -> 不能全由数字组成、也不能全由小写组成、

                              也不能全由数字和小写的组合组成

 

  比如:

/(?![0-9a-z]+)(?![AZaz]+)(?![A-Za-z]+)[0-9A-Za-z]{2,4}/;

                2-4位,可以输入数字、字母,但是必须出现一位大写和一位数字的组合

                

/(?![0-9a-z]+)(?![AZaz]+)(?![A-Za-z]+)(?![A-Z0-9]+$)[0-9A-Za-z]{2,4}/;

                必须三者都有

            /(?![0-9A-Za-z]+$)[0-9A-Za-z_]{2,4}/;

            至少要有下划线

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

1.切割:var arr=str.split("固定切割符"/RegExp);

2.*替换:很有可能出现在笔试之中

      1、基本替换法:

str=str.replace(/正则表达式/后缀,"新内容");

//replace支持支持正则,并且搭配上后缀g就可以找到全部

//缺陷:替换的新内容是一个固定的

 

      2、高级替换法:

str=str.replace(/正则表达式/后缀,function(a,b,c){

console.log(a);//正则匹配到的关键字

console.log(b);//正则匹配到的关键字的下标

console.log(c);//原字符串

return 判断a关键字的长度,并进行替换

});

 

3、格式化:身份证

var id="500103198602215933";

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的时候,正则出现了分组,形参数量增减,

                                //有几个分组就多几个形参

//第1个分组获得的内容会保存在第2个形参之中

//第2个分组获得的内容会保存在第3个形参之中

//...

//倒数第二个一定是下标

//倒数第一个一定是原文本身

})

      格式化:手机号

var phone="13452390312";

var reg=/(\d{4})\d{4}(\d{3})/;

phone=phone.replace(reg,(a,b,c)=>{

return b+"****"+c;

})

console.log(phone);

                        

                        *****想要留下原字符串的哪部分,就把哪部分设置分组

 

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

1、前加^后加$ - 验证

2、希望替换所有 - 必须加g

 

3.正则对象

1.创建:

1、直接量:var reg=/正则表达式/后缀;

2、构造函数:var reg=new RegExp("正则表达式","后缀");

2.API:

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

DOM(Document Object Model)

意为文档对象类型 专门用于操作HTML对象

原本DOM是可以操作一切结构化文档的,但是再某一次升级后,为了方便各类程序员将DOM分为了3方面:

1、核心DOM:即可以操作HTML又可以操作XML,但是语法相对比较繁琐

        

2、HTML DOM:只可以操作HTML,不能访问一切自定义的东西,但语法简单

        

3、XML DOM:只可以操作XML已经被JSON数据格式代替了

 

 

1.DOM树的概念:DOM将HTML视作倒挂的树状结构,但是树根是document而非html

     document对象:无需创建,js解释器自动创建,一个页面只有一个

     

     作用:可以通过树根找到想要的任何一个DOM元素/节点/对象(属性和方法)

2.查找元素

        (1)通过id查找

             var elem = document.getElementById("id值");

             特殊:

               返回值:找到就返回DOM元素,没找到就返回null

               出现多个相同的id,只会找到第一个

               前端开发不使用id查找

             

        (2)通过标签名查找

             var elem = document/已经找到的父元素.getElementByTagName("标签名");

             特殊:

               返回值:找到返回一个类数组DOM集合,没找到就返回空集合

               js只能操作DOM元素,不能直接操作DOM集合

               使用已经找到的父元素对标签名的查找会更准确

               

        (3)通过class名查找

              var elem = document/已经找到的父元素.getElementByClassName("class名");

             特殊:

               返回值:找到返回一个类数组DOM集合,没找到就返回空集合

               js只能操作DOM元素,不能直接操作DOM集合

               使用已经找到的父元素对标签名的查找会更准确

               

        (4) querySelector: 查询css选择器 query(查询)

             1.var elem = document.querySelector("任意css选择器");

             缺陷:只能找到单个元素,如果匹配到了多个,也只会返回第一个,没找到null

             2.var elem = document.querySelectorAll("任意css选择器");

             优点:

                      1、找到了是一个集合,没找到是一个空集

                      2、进行复杂查找时,简化了操作

                      3、返回的是一个静态集合NodeList

                      

面试题:

      1.document.getXXX 和 document.queryXX

          答:后者更适合复杂查找

      2、动态集合和静态集合的区别?

  答:

             1、动态集合:每一次DOM发生变化时都会再次查找,让页面和数据保持一致,

             因此效率更低 - 不支持forEach

         2、静态集合:每一次DOM发生变化时不会再次查找,没有让页面和数据保持一致,

             因此效率更高 - 支持使用forEach

 

3.通过关系查找元素,前提:找到一个元素后才可使用关系

会返回一个动态集合HTMLCollection

      

| 关系 |语句  |范围  |

| --- | --- | --- |

| 父元素 | elem.parentNode | 单个元素 |

| 子元素 | elem.children | 集合 |

| 第一个子元素 | elem.firstElementChild | 单个元素 |

| 最后一个子元素 | elem.lastElementChild | 单个元素 |

| 前一个兄弟 | elem.previousElementSibling | 单个元素 |

| 后一个兄弟 | elem.nextElementSibling | 单个元素 |

 

4.操作元素,前提:找到元素

     1.内容

     elem.innerHTML(会显示子元素标签)

        获取和设置开始标签到结束标签之间的内容

        获取:elem.innerHTML;

        设置:elem.innerHTML="新内容";

        

     elem.innerText(会显示子元素标签)

        获取和设置开始标签到结束标签之间的纯文本

        获取:elem.innerText;

        设置:elem.innerText="新内容";

        

     input.value: 专门获取/设置input里的内容

        获取:input.value;

        设置:input.value="新内容";

        

      2.属性:

          *****设置属性为空字符串,对于某些属性可以算是删除,但只删除了属性值,属性名还在,

               有的属性只有一个属性名,也会有作用(如: href属性值为空会刷新界面,

               disabled,readonly,checked这类属性,原本就可以省略属性值)

               

        (1)核心DOM:

            获取属性值:elem.getAttribute("属性名");

            设置属性值:elem.getAttribute("属性名","属性值");

            删除属性值: elem.removeAttribute("属性名");

       

        (2)简化版(HTML DOM):

            获取属性值:elem.属性名;

            设置属性值:elem.属性名="属性值

            删除属性值: elem.属性名=""; - 属性节点删不干净

            特殊点:

             class必须写作className----ES6(2015年)class变成了关键字

             不能操作自定义属性

      

      3.样式:

        a.内联样式

         (1)优点:不牵一发而动全身,优先级最高

         (2)获取样式:elem.style.css属性名;

         (3)设置样式:elem.style.css属性名="css属性值";

         本方法只能获取和设置内联样式

         (4)特殊:css属性名之前使用横杠链接的地方,变为小驼峰

                   如:border-radius----borderRadius

                   

        b.样式表样式

             var sheet=document.styleSheets[i]; //获取想要操作的样式表

             var rules=sheet.cssRules;//获取此样式表中所有的样式规则

             var rule=rules[i];//数出想操作的规则的下标

             console.log(rule.style.css属性名);

             rule.style.css属性名="css属性值";//操作

            

       4.判断是否有某属性,只能判断有没有,不能判断是什么,推荐用elem.getAttribute("属性名");

       获取到值后自己再写比较运算(返回true/false)

            核心DOM:elem.hasAttribute("属性名");

            HTML DOM:elem.属性名!="";

 

      ******优先使用HTML DOM,实现不了的再用核心DOM补充

 

 #### 6.绑定事件的三种方式:

    1、在HTML上书写事件属性

<elem on事件名="函数名(实参)">

缺点:

1、不符合内容与样式与行为的分离原则

2、无法动态绑定,一次只能绑定一个元素

3、不支持绑定多个函数对象

 

2、*在js中使用事件处理函数属性

elem.on事件名=function(){

                  操作;

                }

    优点:

1、符合内容与样式与行为的分离原则

2、动态绑定,一次能绑定多个元素

    缺点:

不支持绑定多个函数对象

 

3、*在js中使用事件API:如果不用考虑IE,那也不错

主流:elem.addEventListener("事件名",callback);

IE:elem.attachEvent("on事件名",callback);

                优点:

1、符合内容与样式与行为的分离原则

2、动态绑定

3、支持绑定多个函数对象

    缺点:有兼容性问题

 

兼容的写法:

if(elem.addEventListener){

elem.addEventListener("事件名",callback);

}else{

elem.attachEvent("on事件名",callback);

}

 

         

7.创建元素及上树的步骤:

       1、创建空标签:

      var elem=document.createElement("标签名");

              

       2、为其设置必要的属性和事件

      elem.属性名="属性值";

              elem.on事件名=function(){}

              

       3、上树:3种

              *父元素.appendChild(elem);//在父元素末尾处追加一个子元素elem

              

              父元素.insertBefore(elem,已有子元素);

              //在父元素追加一个子元素elem,但是放在已有子元素的前面

              

              父元素.replaceChild(elem,已有子元素);

              //在父元素追加一个子元素elem,但是会替换掉已有子元素

              

      *** 4.1、select&option专用创建元素&上树语句:

select.add(new Option("innerHTML","value"));

 

8.删除元素:elem.remove();

9.拓展:

      1、创建变量:新增的一个let关键字:

   let 变量名=值;

           作用:

                 1、解决了声明提前

                    2、带来了块级作用域,一个{}就是一个块,此变量只能在那个{}里面使用

                    3、如果用let去当作下标绑定事件,直接记录着当前元素的下标,不再需要自定义

                    下标,forEach的那个形参i就是let创建的

                    

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

BOM(Browser Object Model)

定义:

  意为浏览器对象模型 专门用于操作浏览器 浏览器自带很多操作,BOM没有标准,但大多数一致规范,旧版IE除外

1、window对象:

     (1)表示全局对象:保存全局变量和全局函数

     (2)指代当前窗口本身

1、属性

1、获取浏览器完整大小:outerWidth/outerHeight

2、获取浏览器的文档显示区大小:innerWidth/innerHeight

3、获取屏幕的完整大小:screen.width/screen.height

2、方法

1、打开链接的新方式

(1)当前窗口打开,可以后退

        HTML实现:<a href="url">内容</a>

        

        js实现: open("url","_self");//写在事件里

(2)当前窗口打开,禁止后退(如电商网站结账页面,不允许后退)

       history:当前窗口的历史记录,能做的就是前进/后退

       

       location:当前窗口正在打开的url,有一个API

                 location.replace("新url");

                 替换url,不跳转,不产生历史记录,无法后退,但因为网址改变了,所以页面会变

(3)新窗口打开,可以打开多个

        HTML实现:<a href="url" target="_blank">内容</a>

        

        js实现: open("url","_blank");//写在事件里

(4)新窗口打开,只打开一个(如电商网站,只准开一个结账页面)

        HTML实现:<a href="url" target="自定义name">内容</a>

        

        js实现: open("url","自定义name");//写在事件里

窗口在底层都有一个名字,如果打开一个已经开着的窗口,先关闭再打开
(5)总结

        (1)任何标签都可以实现跳转

        

        (2)上述各方式的作用:提高用户体验感

        

        (3)a标签的用途:

              a、跳转

              b、锚点

              c、下载按钮:
<a href="xx.exe/rar/zip/7z">下载</a>

              

              d、打开图片和txt文档:
<a href="xx.png/jpg/jpeg/gif/txt">打开图片和txt</a>

              

              e、直接写js不用绑定点击事件:
<a href="javascript:js 代码;">打开图片和txt</a>

              

2、打开新窗口/新链接:

       (1)newW = open("url","target","width=?,height=?,top=?,left=?");//此处不加单位

       

       (2)没有加第三个参数,浏览器和窗口融为一体,加了窗口脱离浏览器独立存在

3、关闭窗口

        window/newW.close();

4、改变窗口大小

        newW.resizeTo(新宽,新高);

5、改变新窗口位置

        new.moveTo(新X,新Y);

6、window的三个框

       (1)警告框:alert("警告文字");

       

       (2)输入框:var user = prompt("提示文字");

       

       (3)确认框:var bool = confirm("提示文字");

7、定时器是window的

8、事件

       (1)window.onload事件:load:加载

            等待其他所有资源加载完毕后才会执行的代码,放在里边的代码最后执行

            

       (2)window.onresize事件:

            窗口大小发生变化就触发,搭配判断innerWidth可以理解为js版本的css媒体查询事件

            

       (3)window.scroll事件:滚动事件,一发生滚动就触发

               a、获取滚动条当前的位置:window.scrollY;

               

               b、获取元素到页面边缘的距离:elem.offsetTop到顶部/elem.offsetLeft到左边

9、本地/客户端存储技术

(1)cookie:已淘汰,存储大小2KB,操作麻烦,需要到处切割,最多保存30天

 

(2)webStorage:H5的新特性之一,存储大小8MB,永久保存

       a、webStorage分类:

            1、sessionStorage:会话级,浏览器一旦关闭,数据就清空

            

            2、localStorage:本地级,不手动清空就永久存在

            

            3、操作:

                (1)添加:xxxStorage.属性名 = "属性值";

                (1)读取:xxxStorage.属性名;

                (1)删除:xxxStorage.removeItem("属性名");

                (1)清空:xxxStorage.clear();

2.BOM的常用对象

(1) history对象:保存了当前窗口的历史记录(过去的url)

          前进: history.go(1);

          后退: history.go(-1);

          刷新: history.go(0);

(2) location对象:保存了当前窗口正在打开的url(现在的url)

          a.常识类问题:

          一个url由几个部分组成?每个部分分别有什么作用?

              答:一个url由五个部分组成

              1.协议: https(加密)/http(未加密)/ftp(传输文件)/ws(直播)

              ****其中https和http属于请求-响应模式

              

              2.主机号|IP地址|域名:域名需要购买,主机号|IP地址是免费

              

              3.端口号:https默认端口: 443,http默认端口: 80,只有默认端口可以省略不写

              

              4.***文件的相对路径|路由

              

              5.查询字符串|请求消息:前端传输到后端的东西,就是form表单提交带来的东西

 

           b.属性

             1.分别获取url五个部分的内容(直接输入location对象就可全部查询)

                 协议:location.protocal;

     域名:location.hostname;

     端口:location.port;

     路由:location.pathname;

     请求消息:location.search;

             

             2.跳转:

                 location="新url" - 替换当前窗口,可以后退

                 location.replace("新url") - 替换当前窗口,禁止后退

                 

             3.刷新:

                 location.reload();

(3)事件周期: 从事件发生,到所有事件处理函数执行完毕的全过程

      3个阶段:

1、捕获阶段:由外向内,记录要发生的事件有哪些

                

2、目标优先触发:目标元素(当前点击的实际发生事件的元素)

                

3、冒泡触发:由内向外,依次执行记录着的事件

(4)获取事件对象event:

    主流:会自动作为事件处理函数的第一个形参传入

IE:event; - IE的全局变量

兼容:event; - 主流和IE均可使用

 

得到了事件对象event可以做什么呢?

   1、获取鼠标的坐标:

          获取鼠标相对于屏幕的坐标:e.screenX/Y

              获取鼠标相对于窗口/客户端/文档显示区域的坐标:e.clientX/Y

             *获取鼠标相对于网页的坐标:e.pageX/Y

 

       2、阻止事件冒泡:- 笔试面试中

主流:e.stopPropagation();

IE:e.cancelBubble=true;

兼容:e.cancelBubble=true;

                //主流和IE均可使用

 

    3、*****利用冒泡/事件委托 - 开发中常用,提升网页性能,事件函数也可以换为箭头函数了

优化:如果多个子元素定义了相同 或 相似的事件操作,最好只给父元素定义一次

原因:每一次绑定一个事件函数,其实都是创建了一个事件对象,

                        创建的事件对象越多,网站性能就越差

                        

淘汰了this, 当前元素, 会改变

使用一个目标元素target:点击哪一个就是哪一个,不会变化的

                        

主流:e.target;

IE:e.srcElement;

兼容:e.srcElement;//主流和IE均可使用

                 

                注意:

                  1.判断元素标签: xx.nodeName,标签名全是大写

                  2.事件处理函数写为箭头函数的时候this失效,使用e.target

 

    4、阻止浏览器的默认行为:

                比如:a标签默认就可以跳转,提交按钮可以提交表单,右键显示一个弹出框,

                F12显示控制台,F11显示全屏,F5自带刷新功能

主流:e.preventDefault();

IE:e.returnValue=false;

兼容:e.returnValue=false;//主流和IE均可使用

                        

            5、新事件:

1、右键事件 - window.oncontextmenu

                        

2、键盘事件:一般来说用于游戏开发较多+都要搭配上键盘的键码

                        

window.onkeydown - 按住和按下,任何键盘按键都可以触发

                                

window.onkeypress - 按住和按下,只有字母、数字、回车、空格

                                                可以触发,其他按键不行

                                                

window.onkeyup - 松开,任何键盘按键都可以触发(比手速的游戏)

 

            6、获取键盘的键码:

e.keyCode;

                        //可以获取到你按了哪个键,每个键都有自己对应的键码,不需要记忆,

                        使用本句输出查看或者搜索

 

*** event可以说是BOM之中最重要的一个点,笔试面试只要考BOM多半都是event

 

IE:不支持HTML5和CSS3和ES5+