学习js的第四周

145 阅读25分钟

一.js基础

1.js的介绍:js是一个运行在服务器端解释型,弱类型面向对象的脚本语言,由三部分组成:ECMAScript(核心语法3/5/6/7/8/9/10/11/12),DOM(和网页挂钩),BOM(和浏览器挂钩)

tips: 1.运行环境:浏览器,打开浏览器就自动运行

2.解释型:在代码运行之前不会检查代码,直接运行,遇到错就报错

3.弱类型:保存的变量可以随意

作用:可以做一切css实现不了的效果

2.js的使用方法:

1.在HTML中写一个script标签,在标签文本中写js内容

2.创建一个.js的文件,在HTML中用script标签的src属性来引入.js文件,在.js文件里写Js

3.输出方式:

1.控制台输出:console.log();

2.页面输出:document.write();此方法支持标签写法,但是搭配点击事件时会把网页内容变没

3.在警告框输出:alert();多次刷新页面时可能会卡住整个页面

4.变量:创建后用于存放值,可以再次修改

语法:var 变量名=值;

作用:之后会反复用到的数据就存到变量里方便以后调用

tips:

1.变量名不能随意。应遵守以下规则:不能以数字开头,建议使用驼峰命名法,尽量见名知意

2.如果变量名是name,就会自动把内容变成字符串类型

3.变量名不能是关键字

4.如果变量只创建不赋值,默认会变成undefined,undefined做不了任何操作

5.可以多个变量名同时创建: var 变量1=值1,变量2=值2...;

5.数据类型

1.值类型

①.string:字符串类型,取值有无数个,必须加上""或''

②.number:数字类型,取值有无数个,直接写

③boolean:布尔型,取值只有true和false,用于做判断

④null:空类型,唯一的作用是释放内存,提升网页的性能

⑤undefined:取值就是undefined,是一个没用的东西,拿来做什么操作都不行

特殊:NaN是数字类型,不是一个有效的数字,没有优点有两个缺点,参与任何的运算都是NaN,参加任何的比较运算都为false

*****页面上的一切数据js获取到之后都是字符串类型的

强制类型转化的方式:

1.字符串两种:

①.var str=x.toString(); x不可以是undefined和null,会报错,它们不能做任何操作,因为它们不是对象

②.var str=String(x);万能的,但是绝对不要手动去用,完全等效于隐式转换

2.数字三种:

①.parseInt(str/num);专门用于将字符串转换为数字,从左到右依次转,遇到不是数字的字符就会停止,如果一来就不认识就会识别为NaN,不认识小数点

②.parseFloat(str);专门用于把字符转化为小数,认识小数点

②.Number(x);万能的,但是绝对不要手动去用,完全等效于隐式转换

3.转布尔:

Boolean(x);万能的,记住为false的东西只有6个:0,"",null,undefined,false,NaN,绝对不要手动去用,在分支结构或者循环结构的条件中会隐式转换为布尔值,只要记得这6个为false

2.引用类型

string Number Boolean Array Function Date Math Regexp(正则表达式) Error Object Global(全局对象)

二.运算符 *

1.算术运算符:+ - * / %

特点:

1.带有隐式转换,会悄悄的把数据的类型变为数字类型:true -> 1 ,false -> 0 ,undefined ->NaN,null -> 0

2.%是取余符号,通常用于做奇偶判断或者用于取数字的后n位

3.+运算符比较特殊,当+的左右两边有字符串的时候,会悄悄的隐式转换左右两边的数据为字符串,此时做的不是+运算而是将两个字符串拼接起来

2.比较运算符:> < >= <= == != === !==

特点:比较运算符的结果一定是个布尔值也带有隐式转换,默认左右为数字,一般用于做判断

tips:

①.如果比较运算符的左右两边都是字符串,则会按位PK两边每个字符的十六进制unicode号(十进制ASCLL码),一般:数字0-9<大写字母<小写字母<汉字。

汉字的第一个字是:一 unicode号是4e00 ascll码是19968

汉字的最后一个字是:龥 unicode号是9fa5 ascll码是40869

②.NaN参与任何的比较运算结果都为false,判断一个值是不是NaN:isNaN()一般前面加!用于判断

③.undefined==null的结果为true,它们做比较的时候要用===,全等运算符的意思为不带隐式转换的比较,即值要相等类型也要相等(!==为不全等)

3.赋值运算符:= += -= *= /= %=

特点:

1.= 意为把=右边的东西赋值给左边

2.其余的是=的升级版,意为先与=后面的东西做计算再将得到的值赋值给变量本身

4.逻辑运算符:&& || !,综合比较,用于写条件(结果一定是一个布尔值)

特点:

&&(与):当全部的条件都满足时就为true,否则为false

||(或):当其中一个条件满足时就为true

!(非):用于颠倒布尔值

5.自增自减运算符:++ --,每次只能增加或减少1

注意:单独使用++或--时,放在值的前后都没有影响,但是参与了其他的表达式返回的结果就会不同,前++返回的值是新值,后++返回的值是旧值,只要使用了值都会变化

6.位运符:>> <<

<<:左移:m<< n,m左移了n位意为m*2的n次方

>>:右移:m>>n,m右移了n位意为m/2的n次方

三.分支结构

1.程序的流程结构

①.顺序结构:默认的,从上往下依次执行

②.分支结构:通过条件判断,选择部分代码执行

③.循环结构:通过条件判断,选择要不要重复执行某一个块代码

2.分支结构(三种)

if...else分支结构:

特点:else if可以写多个,取决于自己,可以做范围判断

1.一个条件一件事:if(条件){
                 操作;
}

2.一个条件两件事:if(条件){
                 操作1;
}else{
        操作2;
  }
  
  3.多个条件,多件事:if(条件1){
                 操作1;
               }else if(条件2){
                 操作2;
               }else if(条件3){
                 操作3;
} 

switch...case分支:

特点:1.问题:默认只要有一个case满足后,会把后面的操作都执行一遍

解决:在每个case操作后面加break(跳出判断)

2.case在做比较的时候不带有隐式转换

3.default可以省略,但是不推荐,不写的话条件都不满足时什么都不会发生

   switch(变量/表达式){
               case1:
               操作1;
               break;
               case2:
               操作2;
               break;
               default;
               默认操作;            
   }

if和switch的区别:

switch的优点:效率高,速度快(等值比较)

缺点:必须要知道结果值才能做判断

if的优点:可以做范围判断

缺点:效率低,速度慢

3.三目运算:简化if...else分支

注意:1.默认操作不能省略,省略会报错;

2.如果操作复杂,不能使用三目运算,操作只能有一句话。

  条件1?操作1:条件2:操作2:默认操作
3.循环结构:反复执行相同或者相似的操作

循环三要素:

1.循环条件:开始-结束,循环次数

2.循环体:做的操作

3.循环变量:记录了当前操作的次数,会不断变化

循环的原理:当循环条件满足时,执行一次操作,同时循环变量变化,不会退出操作,回过头去再次判断循环的条件满足不满足,满足再继续,不满足就跳出循环。

死循环:没有循环条件或者循环条件能一直满足的循环,循环便不会停止的一直做下去,当我们不确定循环的次数的时候需要用到死循环,死循环也会停止,当使用了break就能让循环停止

break:退出整个循环

continue:退出本次循环,下一次循环依然执行

三种循环结构:

1.while循环:

语法:

            var 循环变量=xxx;
            while(循环条件){
                循环体;
                循环变量的变化;
            }
            
            while的死循环:
            while(true){
                循环体
             }

2.for循环:

语法:

              for(变量;条件;变量的变化){
               循环体;
              }
              
              for的死循环:
              for(;;){
              循环体;
              }

3.do...while循环 (没啥用,基本不写)

语法:

                var 循环变量=几;
                do {
                循环体=xxx;
                循环变量的变化;
                }while(循环条件){
                
                }

区别:当第一次循环不满足时while循环不会执行,do...while循环会执行一次;

四.函数

1.概念

function:函数也叫方法,事先预定好以后可以反复调用的代码段。

2.语法:
  1.定义函数(两种) 
      1.声明方式       function 函数名(形参){
                            函数体;
                      }
      2.直接量方式
                    var 函数名=function(形参){
                           函数体;
                    }
                    
  2.调用函数:
           函数名(实参列表);
3.作用:

1.不希望页面一打开就立刻执行

2.希望用户来触发提升用户的体验感

3.函数是js的第一公民,以后每一个独立的功能都要封装成函数

tips:

1.调用带有参数的函数时,必须要传入实参且顺序要一一对应,数量不能多也不能少。

2.当函数调用完后变量会自动被释放

4.作用域(两种) *****

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

2.函数作用域:局部变量和局部函数,在当前函数调用时,内部可以使用

变量的使用规则:优先使用局部的变量,没有局部变量就找全局的,都没有就报错。

缺点:

1.全局污染:全局本身没有变量,但是被函数作用域添加了

解决:不要对函数内未声明的变量进行赋值操作;

2.局部的东西可以使用全局的东西,但是全局的东西不能使用局部的东西;

解决:return(退出函数)

return的特点:

1.如果return后面跟着一个数据将会返回这个数据,但是不会保存起来,想要看到这个数据需要用一个变量保存起来(return 只返回不保存)

2.省略return,默认也会有,会return一个undefined

3.如果需要在全局使用函数返回的结果去做别的操作要记得加上return

4.前辈们提供了的方法基本上都加上了return

5.声明提前

鄙视题常客:

概念:在程序开始执行之前,会把var声明的变量(轻)和function(重),悄悄的集中定义到当前作用域的顶部,但是赋值会留在原地

tips:声明方式创建的函数会完整的提前,直接量方式创建的函数不会完整的提前,只有变量名部分会提前(即直接量方式的提前类似var声明的变量方式)

只要遵守以下规则就能避免声明提前的问题:

1.变量名和函数尽量不要重复

2.先创建再使用

6.方法重载

概念:相同的函数名,根据传入的实参的不同能自动的选择对应的函数去执行,即记住一个方法能执行多个操作,但是js不支持此功能

解决:在函数的内部自带了一个argument类数组对象,使用它来进行判断实参传入的不同执行不同的操作

用法:

1.通过下标获取传入了几个实参:argument[i];

2.通过数组的唯一属性length来获取传入了几个实参:arguments.length

五.数组

1.概念:创建一个变量可以保存多个数据
2.特点:

1.都是线性排列,除了第一个元素,每个元素都有唯一的前驱元素;除了最后一个元素,每个元素都有一个后继元素。

2.下标:即每个元素自己的位置,下标是从0开始的,到数组的最大长度-1结束

3.length:数组的唯一属性,从1开始,到数组的最大长度的值

3.语法:
          1.创建数组(两种)
                1.直接创建: var arr/数组名=[];
                
                2.构造函数: var arr=new Array(数据1,数据2,...);
                
          2.获取数组中的元素:
                数组名[i]
                
          3.添加元素/替换元素:
                 数组名[下标]=新元素;
              如果下标下有元素就是替换,没有就是添加
4.数组的3大不限制:

1.不限制元素类型(优点)

2.不限制元素的长度(优点)

3.不限制下标的越界(缺点)

如果元素的下标越界,返回的值是undefined,不能进行操作

5.数组的唯一属性length ****

用法: 数组名.length

作用:获取数组的长度,方便我们进行对数组进行操作

1.在数组末尾添加新的元素:数组名[数组名.length]=新的数据;

2.获取数组倒数第n个元素:数组名[数组名.length-n];

3.缩容:删除倒数n个元素:数组名.length=n

6.数组的遍历 *****

目的:取出数组里的所有元素来进行相同或者相似的操作

固定公式:

            for(i=0;i<数组名.length;i++){
                      数组名[];
            }

六.DOM

Document Object Model:文档对象类型,提供了一些方法来专门用于操作HTML文档

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

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

3、XML DOM:只可以操作XML,被淘汰了,被JSON数据格式代替了

DOM树的概念:DOM把整个HTML看成一个倒挂的树状结构,树根不是HTML是Document的对象,它由浏览器自动创建,一个页面只有一个树根

DOM树的作用:DOM会将页面上的每一个元素,属性,文本,注释等视为一个DOM元素/节点/对象,我们可以通过树根找到我们想要的任何一个DOM元素/节点/对象(属性和方法)

*****1.查找元素的方法:

两大方法:

一.直接通过HTML的特点来查找元素

①.通过id查找 var elem=document.getElementById("id名");

tips:

1.返回值:找到了就返回此元素,没找到返回null;

2.出现了多个id的话只会找到第一个;

3.此方法不允许使用,一次只能找一个,留给后端去用;

②.***** 通过标签名查找元素:

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

tips:

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

2.js只能直接操作DOM元素,不能直接操作集合,要么通过下标拿到某一个元素来使用,要么遍历拿到每一个元素再来使用

3.可以从已经找到的父元素开始查找

③.**** 通过class来查找元素

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

tips:

与通过标签名查找相同

④.****css选择器查找

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

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

2、***var elems=document.querySelectorAll("任意css选择器的");

优点:

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

2、复杂查找时,非常简单

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

二.通过关系获取元素:(前提:已经先找到了一个元素才可以使用)

父元素:elem.parentNode;

子元素:elem.children;

第一个子元素:elem.fristElementChild;

最后一个子元素:elem.lastElementChild;

前一个兄弟:elem.previousElementSibling;

后一个兄弟:elem.nextElementSibling;

tips:

1.除了子元素,其他获取到的元素都是单个元素,可以直接使用

2.使用关系获取的目的是不影响别的元素,只影响到自己有关系的元素

*****2.操作元素(三个方面:内容,属性,样式)

1.内容:

1.elem.innerHTML 获取和设置标签开始到结束之间的内容,能识别标签

语法:

获取:elem.innerHTML;

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

2.elem.innerText 获取和设置标签之间的纯文本内容,不会识别标签

获取:elem.innerText;

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

3.input.value 专门获取或设置input里的内容

获取:input.value;

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

2.属性:

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

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

简化写法:

获取属性:elem.属性名;

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

简化的缺点:

class必须写为className,不能操作自定义的属性

3.样式

使用样式的3种方法:

1.内联样式

2.内部样式表

3.外部样式表

js的样式操作用于操作内联样式

原因:1.不会牵一发动全身

2.优先级最高

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

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

tips:

1.js里-是减号,css样式里有-号的地方变为小驼峰命名法

2.因为我们是对内联样式进行操作,所以只能获取到内联样式

4.绑定事件

语法:

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

绑定事件的关键字:this

如果单个元素绑定了事件,this只指代这个元素 如果多个元素绑定了事件,this指代当前触发的元素

*****3.创建元素的方式:

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

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

                elem.属性名="属性值";
                elem.on事件名=function(){操作}
                

3.挂载上树/渲染页面:

               父元素.appendchild(elem);

七.数组

1.创建数组:
                方法1:var arr=[];
                
                方法2:var arr=new Array();         
               

注:方法2里如果只放一个数字,会创建出一个长度为这个数字的空数组,内容全是undefined

2.按值传递 ***

1.传递的值如果是原始类型,就是复制了一个文本给对方,两者互不影响。

2.传递的值如果是引用类型,只是保存了地址值,其实是赋值了自己的地址值给对方,两者用的是同一个地址值,会相互影响。

3.释放引用类型

js的底层有一个垃圾回收器,只有垃圾回收器为0的时候才会删除不要的数据

我们要将代码封装为函数,函数的变量会自动释放

4.hash数组 ***

1.使用:

       1.创建一个空数组:var arr=[];
       2.为数组添加自定义的下标并且赋值:
       arr["自定义下标"]=新值;
       
       3.访问元素=arr["自定义下标"]

tips:

1.hash数组的length会失效,永远为0;

2.遍历hash数组不能使用for循环只能使用for in循环,for in也能遍历索引数组,但是建议分开使用

                      for(var i in 数组名){
                               i;
                               数组名[i];
                      }

3.原理 ***

hash算法:将字符串计算出一个尽量不重复的数字字符串内容相同,则计算出来的数字也一定相同。

添加元素:把自定义下标交给hash算法,得到一个数字,直接将你要保存的数据放到这里(地址值)保存起来

获取元素:将指定的自定义下标交给hash算法,得到一个和当初保存时一样的数字(地址值),通过这个地址找到你当初保存的数据再取出使用

4.js里面一切的东西都是对象。除了undefined和null,一切对象的底层都是hash数组

5.数组的API ******

1.数组转字符串:

                   arr.join("自定义连接符");

tips: 二级联动:

1.select的专属事件onchange -只有选中项发生之后才会触发

2.select专属的属性 this.selectedIndex

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

          arr.concat(新值1...)
          自动把传入的新参数放到数组末尾
          

tips:

1.不修改数组,只会返回一个新数组,需要用变量保存

2.可以放数组,会自动把数组打散之后一个一个放进去

3.截取子数组

                arr.slice(开始的下标,结束下标)

tips: 1.不修改数组,只会返回一个新数组,需要用变量保存

2.含头不含尾 ***

3.可以不写结束下标,会直接截取完后面所有的元素

4.开始下标也可以不写,就是两个参数都省略那么就是完全的复制一份副本,这个操作也叫做深拷贝

5.可以写负数,意为倒数第几个,-1就是倒数第1个数

4.删,插,替 ***

                     删除:arr.splice(开始下标,n);

tips:会修改原数组,但是也有返回的值,返回的值就是被删除了的数组,没有删除也会返回一个空的数组

                     插入:arr.splice(开始下标,0,新值...);
                     

tips:

1.原开始下标位置的元素会和后面的元素会自动往后移

2.尽量不要插入新的数组,因为会导致数组变为二维数组

                     替换:arr.splice(开始下标,n,新值...);

tips:删除的个数和插入的个数可以不相同

5.翻转

                     arr.reverse();
                     今日一见,不会再见
                     

6.数组排序:

                       arr.sort();
                 将数组中的元素转换为字符串之后,按位pk,一般不直接使用
                 
                 arr.sort(function(a,b){})
                       此方法衍生的匿名回调函数,常用
                       a指代前一个数
                       b指代后一个数
                       
                  数字的升序:
                      arr.sort(function(a,b){
                                return a-b;
                      })
                 数字的降序:
                      arr.sort(function(a,b){
                                return b-a;
                      })

tips:

1.网页上的所有排序功能底层都是数组,因为js中只有数组可以排序

2.以后只要网页上有随机的功能,那么他的底层一定用到了随机数

7.栈和队列:添加元素和删除元素

栈:就是一端封闭的数组,只能一个端进出

                     开头进:arr.unshift(新值1...)
                     开头出:arr.shift();  一次只能删除一个
                     
                     头进头出的缺点:会改变后面元素的下标
                     
                     尾部进:arr.push();
                     尾部出:arr.pop();

队列:就是从一端进,另一端出的数组

                     开头进:arr.unshift(新值1...)
                     尾部出:var last=arr.pop();
                     
                     头进头出的缺点:会改变后面元素的下标
                     
                     尾部进:arr.push();
                     开头出:arr.shift();
                     

8.es5提供的3组6个API:

           1.判断:
                   every:每个,每个都满足返回true,有一个不满足就返回false,类似&&
                   var bool=arr.every(function(val,i,arr){
                               return 条件;
                   })
                   
                   some:一些,每个都不满足返回true,有一个满足就返回true,类似||
                   var bool=arr.some(function(val,i,arr){
                               return 条件;
                   })

            2.遍历:
                  forEach:直接修改原数组
                  arr.forEach(function(val,i,arr){
                               直接写操作;
                   })
                   
                   map:不直接修改原数组
                  arr.map(function(val,i,arr){
                               return 直接写操作;
                   })
             
            3.过滤和汇总:
                  过滤:var subArr=arr.filter(function(val,i,arr){
                               return 判断条件;
                   })
                  
                  汇总:var result=arr.filter(function(prev,val,i,arr){
                               return prev+val;
                   },基础值)
    

tips:

1.6个API都是为了简化for循环的操作

2.箭头函数:为了简化一切回调函数的一个公式:function去掉,()和{}之间用=>连接,如果形参只有一句话就可以把形参的()省略,如果函数体只有一句话可以把{}去掉。

6.周期性定时器:每过一段时间就自动执行一次
                     开启:timer=setInterval(function(){
                            操作;
                     },间隔时间(单位:毫秒))
                     
                     结束:clearInterval(timer)

鼠标移入和移出事件:

                        elem.onmouse(over/out)=function(){
                                 操作:
                        }
7.二维数组:数组元素,又引用着另一个数组
                       创建:var arr=[                            [],
                            [],
                            []
                       ];
                       
                       访问:arr[行下标,列下标]
                       
                       特殊:列下标越界,返回undefined
                       行下标越界得到是报错

遍历二维数组:两层循环,外层循环控制行,内层循环控制列

                       for (r=0;r<arr.length;r++){
                             for(var c=0;c<arr[r.length];c++){
                                   console.log(arr[r][c]);
                             }
                       }

八.string字符串

1.string的概念

字符串:多个字符组成的只读字符数组

tips:

字符串和数组有相同点:

1.字符串中的个数:str.length;

2.获取字符串中的字符:str[i];

3.可以遍历

4.所有数组不修改原数组的API,字符串也可以使用(concat,slice)

2.**** stringAPI:

1.转义字符:\

作用:

1.把字符串和程序冲突的字符转为原文

2.包含特殊功能的符号:\n换行;\t制表符(和敲tab一个效果)

3.输出unicode码的字符:\u4e00 一;\u9fa5 龥

2.* 大小写转换:

转大写:x.toUpperCase();

转小写:x.toLowerCase();

作用:把字符中的每一个字符统一的转化为大写或小写,做验证码的比较时常用

3.获取字符串中的指定位置的字符:str.charAt(),没啥用,不如str[i];

4.获取字符串中指定位置字符的ASCII码:

                  var ascii=str.charCodeAt(i);
                  
             ascii码转原文:
                  var a=String.fromCharCode(ascii);
                  

5.*** 检索字符串:

                  var i=str.indexof("关键字",开始下标)
               从左到右的检索关键字的第一个字符的位置,开始下标可以省略,默认从0的位置开始查找

返回值:找到了就返回第一个关键字的第一个字符的下标,没找到就返回-1,通常用返回值做判断。

6.拼接字符串:

      var str=str.conact;
      但是对于字符串来说不然直接+拼接

7.*截取字符串

             var substr=str.slice()
             var substr=str.substring()
             var substr=str.subStr(开始下标,n)n是个数

8.替换字符串:

             str.replace("固定关键字","新内容")

9.**** 分割字符串:

作用:把字符串转化为数组

                     var arr=str.split("自定义切割符");
                  如果切割的是“”,会切散每个字符串

10.去掉空白字符

                       str.trim/trimStart/trimEnd()

九.Math和Date

1.Math

1.Math对象:专门提供了数学计算的API

2.Math的API:

1.取整:

                1.上取整:超过就取下整数,小数位不能超过15var num=Math.ceil(num) 
                
                2.下取整:
                var num=Math.floor
                
                3.四舍五入取整:
                var num=Math.round(num);
                
                4.num.toFixed(d)
                d是保留小数的位数
                
                缺点:结果是一个字符串,要配合parseFloat()

2.乘方和开方:

                  Math.pow(底数,幂)    简化:底数**幂
                  
                  开方:Math.sqrt()        只能开方

3.最大值和最小值

                   Math.max/min()
                   自动从()找到最大值和最小值但是不支持数组
                   
                   数组的写法:
                   Math.max/min(apply(Math,arr))

4.绝对值:负数变正数:Math.abs();

5.*** 随机数

                 Math.random() 在0-1之间取一个随机的小数搭配上parseInt使用,只能取到0但是不可能取到1
                 
                
                       
2.Date

1.Date对象提供了操作日期和时间的API

2.创建:

                 1.创建一个当前日期:
                   var now=new Date();
                   
                  2.创建一个自定义时间:
               var birth=new Date ("yyyy/MM/dd hh:mm:ss");
                 
                 3.创建一个自定义时间:
              var birth=new Date(yyyy,MM,dd,hh,mm,ss)
              
                4.复制一个日期:日期的所有API都会直接修改原日期,在调用API之前要先复制        
                var end=new Date(birth)
                

2.使用:

1.两个日期对象之间,可以相减(大-小),得到一个毫秒差,换算出自己想要的任何一部分

2.API

FullYear(年)

Month(月) 取值:0-11

Date(日) 取值:1-31

Day(星期) 取值:0-6,星期天是0

Hours(小时) 取值:0-23

Minutes(分) 取值:0-59

Seconds(秒) 取值:0-59

Milliseconds(毫秒)

每一个分量有一对get/set方法

tips:

1.Day只有get方法,没有set方法

2.如果set超出了取值会自动进制

3.想对某个分量进行加减操作

                    date.setXXX(date.getXXX()+(-n))
                    

4.格式化日期为本地字符串:date.toLocaleString(),垃圾有兼容性问题

十.BOM

1.BOM的概念

Browser Object Model 浏览器对象模型,专门用于操作浏览器的,但是使用不多,不如ES和DOM,浏览器很多操作都是自带的,且BOM没有标准,各个浏览器都有自己的定义,但是大部分浏览器都是一致规范的,除了老IE

2.window对象:两个角色

1.全局对象

2.指代当前窗口本事

3.属性

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

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

3.获取屏幕的大小:跟window没关系:screen.width/height 做桌面应用

4.方法

1.打开链接的新方式,提升用户的体验

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

               open("url","_self");

2.当前窗口打开,不能后退

               location.replace("新url");
               

tips:

1.history:当前窗口的历史记录,因为有了历史记录才会有能后退的窗口

2.此方法叫替换,不是跳转,不会产生历史记录,自然不能后退,但是网址被替换了,使用场景:电商网站结账之后不允许后退

3.新窗口打开,可以打开多个

                 open("url","_blank")
                 

4.新窗口打开,只能打开一个:

                 open("url","自定义一个name");
             

tips:窗口的底层都有一个名字,如果打开了一个已经开着的名字的窗口,他会把这个窗口关闭后再打开

作用:

1.任何的标签都能设置跳转

2.提升用户的体验感

3.a标签的其他用法:

①.跳转,锚点

②.下载按钮:

               <a href="xxx.exe/rar/zip/7z"></a>

③.打开图片或txt文件:

               <a href="xx.png/jpg/jepg/gif/txt"></a>
               

④.直接写js:

              直接书写js-不需要绑定点击事件:<a href="javascript:js代码;">   一般不用

5.打开新窗口/新连接:open("url","target","width=?,height=?,left=?,top=?");

tips:

1.如果没加第三个参数,窗口会和浏览器融为一体

2.如果加了第三个参数,窗口会脱离浏览器独立存在

3.关闭窗口:window.close();

4.改变窗口大小:newW.resizeTo(新宽,新高)

5.改变窗口的位置:newW.moveTo(新x,新y)

6.window提供了三个框:

警告框:alert("")

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

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

7.定时器也是window的

5.事件:

1.window.onload事件 等别的资源加载完成后再加载该事件中的代码

2.window.onresize事件 窗口大小发生变化就触发,搭配判断innerWidth,可以理解为js的css媒体查询方式

3.window.onscroll事件:滚动事件 滚动就触发搭配

①.获取滚动条的当前位置:window.scrollY

②.获取元素距离页面顶部有多远:elem.offsetTop/Left

6.本地存储技术

cookie:淘汰了,存储的大小只有2kb,操作复杂,要到处切割,最多存储30天

webStorage:H5带来的新特性,存储大小有8M,永久存储,操作简单

webStorage的学习:

分类:

1.sessionStorage:会话级,只要浏览器关闭了就自动死亡

2.localStorage:本地级,只要不清空,就永远存在

使用:

               1.添加
               localStorage.属性名="属性名"
               2.读取:
               localStorage.属性名
               3.删除
               xxStorage.removeItem("属性名");
               4.清空:
               xxxStorage.clear();
               
7.BOM的常用对象

1、history对象:保存了当前窗口的历史纪录(过去的url) 前进:history.go(1); 后退:history.go(-1); 刷新:history.go(0);

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

***程序员常识:一个url由几部分组成?分别每个部分有什么用? - 以后再学习服务器端和数据库的时候会有很大的帮助

tips:5部分

1、协议:*https(加密)/*http(未加密)/ftp(传输文件)/ws(直播)... 前两个都属于叫做请求-响应模型

2、主机号|IP地址|域名:域名是需要花钱购买的,主机号|IP地址是免费,127.0.0.1才真的是叫做主机号,只能自己访问自己

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

4、***文件的相对路径|路由:百度加密了

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

属性: 获取url的5个部分的内容

1.协议:location.protocal;

2.域名:location.hostname;

3.端口:location.port;

5.路由:location.pathname;

6.请求消息:location.search;

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

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

刷新:location.reload();

3.*****event事件对象

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

3个阶段:

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

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

3、冒泡触发:由内向外,依次执行我们之前记录着的要发生的事件

2、*****获取事件对象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可用,主流也可用

4、阻止浏览器的默认行为:比如:a标签默认就可以跳转,提交按钮可以提交表单,右键自带一个弹出框,F12自带一个控制台,F11自带全屏功能,F5自带刷新功能

		主流:e.preventDefault();
		老IE:e.returnValue=false;
		兼容:e.returnValue=false;//不光老IE可用,主流也可用

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

5、获取键盘的键码:

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

十一.递归

1.递归:

简单来说就是再函数之中再一次调用了函数自己,迟早有一天会停下来专门用于遍历层级不明确的情况 - DOM树和数据(children只能找到儿子层,找不到孙子层)

2.使用

    function 函数名(root){
	1、第一层要做什么直接做

	2、判断有没有下一层,如果有下一层则再次调用此方法,只不过传入的实参是自己的下一层		
}
函数名(实际的根)

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

缺陷:不要过多使用,性能相对较差,同时开启大量的函数调用,浪费内存,我们只在一个情况:层级不明确

递归 vs 纯循环

递归:优点:简单易用

缺点:性能低

纯循环:优点:几乎不占用性能

缺点:难的一批

2、绑定事件:3种方式:

1、在HTML上书写事件属性

	<elem on事件名="函数名(实参)"></elem>
	缺点:
		1、不符合内容与样式与行为的分离原则
		2、无法动态绑定,一次只能绑定一个元素
		3、不支持绑定多个函数对象

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

	elem.on事件名=function(){操作}
	优点:
		1、符合内容与样式与行为的分离原则
		2、动态绑定,一次能绑定多个元素
	缺点:
		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、符合内容与样式与行为的分离原则
		2、动态绑定
		3、支持绑定多个函数对象
	缺点:有兼容性问题

十二.正则表达式

1、*****正则表达式:定义字符串中字符出现规则的表达式

作用:切割 替换 验证

语法:

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

后缀:g:找全部 i:忽略大小写

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

tips:

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

2、问题:正则表达式默认只要满足就不管后续了,而我们做验证的人,希望的是用户从头到尾按照我们的要求来,希望从头到尾完全匹配:

解决:前加^,后加$,两者同时使用,代表要求从头到尾完全匹配/^[备选字符集]$/ - 只要做验证必加

特殊:如果备选字符集中的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、密码强度验证:2-4位,可以输入数字、字母,但是必须出现一位大写和一位数字的组合

(?![]+$):在已有的正则范围基础上除去某几个范围

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

	比如:
	/(?![0-9a-z]+$)(?![A-Za-z]+$)[0-9A-Za-z]{2,4};//2-4位,可以输入数字、字母,但是必须出现一位大写和一位数字的组合
	/(?![0-9a-z]+$)(?![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 phone="13452390312";
		var reg=/(\d{4})\d{4}(\d{3})/;
		
		phone=phone.replace(reg,(a,b,c)=>{
			return b+"****"+c;
		})
		
		console.log(phone);
3、正则对象:
创建:
	1、直接量:var reg=/正则表达式/后缀;
	2、构造函数:var reg=new RegExp("正则表达式","后缀");

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

十三.对象

1、*****Object:对象 - Array/String/RegExp/Date... 对象具有属性和方法,都是预定义好的,现在我们可以学习自定义对象 - js是基于原型的面向对象语言

面向对象 - 三大特点:封装、继承、多态

1、***开发方式:

1.面向过程:过程 - 开始->结束

2.面向对象:对象(属性和方法),js有一句话万物皆对象。

使用场景:以后任何操作都要封装在一个对象之中,但是新手并不太推荐,难度较大

为什么要面向对象:现实生活中所有的数据都必须包含在一个事物之中才有意义

2、*****封装/创建/定义:封装自定义对象:3种

1、*直接量方式:

		var obj={
			"属性名":属性值,
			...,
			"方法名":function(){操作},//可以简化为箭头函数
			...
		}

		强调:
			1、其实属性名和方法名的""可以不加,建议加上,数据格式JSON,他必须在键上加上""
			2、访问对象的属性和方法:
				obj.属性名;	===	obj["属性名"];
				obj.方法名();	===	obj["方法名"]();
				使用.去访问对象的属性和方法,更简单
				***js中一切都是对象,除了undefined和null,一切对象的底层都是hash数组
			3、访问到不存在的属性,返回undefined
			4、可以随时随地的添加新属性和新方法
				obj.属性名=新值;
				obj.方法名=function(){};
			5、如果我希望遍历出对象所有的东西,必须使用for in,obj[i]才能拿到,不要使用.会出问题
			6、***如果你希望在对象的方法里,使用对象自己的属性,写为this.属性名
				*****难点:this的指向:
					1、单个元素绑定事件,this->这个元素
					2、多个元素绑定事件,this->当前元素
					3、定时器中的this->window
					4、箭头函数this->外部对象
					5、函数中this->谁在调用此方法,this就是谁
					6、构造函数之中this->当前正在创建的对象

2、预定义构造函数方式:

		var obj=new Object();//空对象
		//需要自己后续慢慢添加属性和方法
		obj.属性名=新值;
		obj.方法名=function(){};

	一次只能创建一个对象,适合创建单个元素的时候,第二种方法完全是垃圾

3、自定义构造函数方式:2步

		1、创建自定义构造函数
			function 类名(name,age,hobby){
				this.name=name;
				this.age=age;
				this.hobby=hobby;
			}
			千万不要在里面创建方法,每个对象都会创建出一个相同的方法,浪费内存

		2、调用构造函数创建对象
			var obj=new 类名(实参,...);

	面向对象
		优点:
			1、所有的属性和方法都保存在一个对象之中 - 更符合现实更有意义
			2、每个功能特地分开写 - 便于以后维护
			3、铁锁链舟 - 一个方法触发多个方法联动
		
		缺点:对新手不友好,尤其是this的指向问题

3、*****继承:父对象的成员(属性和方法),子对象可以直接使用

继承的作用:代码重用!提高代码的复用性,节约了内存空间!提升了网站的性能!

何时继承:只要多个子对象公用的属性和【方法】,都要集中定义在父对象之中

	1、***如何找到原型对象(父对象):保存了一类子对象共有属性和共有方法
		1、对象名.__proto__; //必须先有一个对象
		2、构造函数名.prototype;//构造函数名几乎人人都有,除了Math和Window,new 构造函数名();//Array、String、Date、RegExp...

	2、*面试题:两链一包:作用域链和【原型链】和闭包
		每个对象都有一个属性:__proto__,可以一层一层的找到每个人的父亲,形成的链式结构,就称之为叫做原型链
		可以找到父对象的成员(属性和方法),作用:找共有属性和共有方法
		最顶层的是Object的原型,上面放着方法toString,人人都可以使用toString
		JS万物皆对象

	3、有了原型对象,可以设置共有属性和共有方法
		1、原型对象.属性名=属性值;
		2、原型对象.方法名=function(){}

1、*****继承面试笔试题:

1、判断是自有还是共有:

1、判断自有:obj.hasOwnProperty("属性名");

如果结果为true,说明是自有属性,如果结果为false,有两种可能,说明可能是共有,也可能是没有

2、判断共有:

                  if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj){//in关键字,会自动查找整条原型链上的属性,找到了结果为true,找不到结果为false
			共有				
		}else{
			没有
		}

		完整公式:
			if(obj.hasOwnProperty("属性名")){
				自有
			}else{
				if("属性名" in obj){
					共有
				}else{
					没有
				}
			}

2、修改和删除:自有和共有

	自有:
		修改:obj.属性名=新属性值;
		删除:delete obj.属性名;
	共有:
		修改:原型对象.属性名=新属性值;千万不要觉得,自己能拿到,就能直接修改,这样很危险,并没有修改原型的东西,而是在本地添加了一个同名属性
		删除:delete 原型对象.属性名;如果你对着本地直接删除,那么此操作直接无效

3、*如何为老IE的数组添加indexOf方法:

		if(Array.prototype.indexOf===undefined){//老IE
			Array.prototype.indexOf=function(key,starti){
				starti===undefined&&(starti=0);
				for(var i=starti;i<this.length;i++){
					if(this[i]===key){
						return i;
					}
				}
				return -1;
			}
		}
		var arr1=[1,2,3,4,5];
		var arr2=[2,4,6,8,10];

4、*如何判断x是不是一个数组:4种方法:千万别用typeof(),只能检查原始类型,不能检查引用类型,如果检查引用类型得到的结果都是一个object。

	1、判断x是否继承自Array.prototypeArray.prototype.isPrototypeOf(x);
		结果为true,说明是数组,结果为false,说明不是数组
	
	2、判断x是不是由Array这个构造函数创建的
		x instanceof Array;
		结果为true,说明是数组,结果为false,说明不是数组

	3Array.isArray(x); - ES5新增的方法,只有数组可以这么使用
		结果为true,说明是数组,结果为false,说明不是数组

	4、*输出【对象的字符串】形式
	       在Object的原型上保存着最原始的toString方法
	       原始的toString输出形式:[object 构造函数名]
	       ***多态:子对象觉得父对象的成员不好用,就在本地定义了同名函数,覆盖了父对象的成员,不严格定义:同一个方法,不同的人使用,效果不同,有多种形态
	       固定套路:
			Object.prototype.toString.call(x)==="[object Array]"

5、实现自定义继承:

	1、两个对象之间设置继承
		子对象.__proto__=父对象

	2、多个对象之间设置继承
		构造函数名.prototype=父对象;
	在创建对象之前就设置好继承关系

2、class关键字:简化面向对象(封装、继承、多态)

   class 类名 extends 老类{
	constructor(name,age,hobby,...){//放在constructor里面的都是自有属性
		super(name,age);
		this.hobby=hobby;
	}//放在constructor外面的都是共有方法
	//还会继承到老类所有的API,也可以添加新的
}

4、*****Function:闭包

作用域:

1、全局:随处可用,可以反复使用,缺点:容易被污染

2、函数:只能在函数调用时内部可用,不会被污染,缺点:一次性的,是会自动释放的

***函数的执行原理:

	1、程序加载时
		创建执行环境栈(ECS):保存函数调用顺序的数组
		首先压入全局执行环境(全局EC)
		全局EC引用着全局对象window
		window中保存着我们全局变量

	2、定义函数时
		创建函数对象:封装代码段
		在函数对象之中有一个scope(作用域)属性:记录着函数来自己的作用域是哪里
		全局函数的scope都是window

	3、调用前
		在执行环境栈(ECS)压入新的EC(函数的EC)
		创建出活动对象(AO):保存着本次函数调用时用到的局部变量
		在函数的EC中有一个scope chain(作用域链)属性引用着AO
		AO有一个parent属性是函数的scope引用着的对象

	4、调用时:
		正是因为有前面三步,才来带变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错

	5、调用完:
		函数的EC会出栈,没人引用AO,AO自动释放,局部变量也就释放了

*****闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊

何时使用:希望保护一个可以【反复使用的局部变量】的时候

如何使用:

		1、两个函数进行嵌套
		2、外层函数创建出受保护的变量
		3、外层函数return出内层函数
		4、内层函数再操作受保护的变量

	强调:
		1、判断是不是闭包:有没有两个函数嵌套,返回了内层函数,内层函数再操作受保护的变量
		2、外层函数调用了几次,就创建了几个闭包,受保护的变量就有了几个副本
		3、同一次外层函数调用,返回的内层函数,都是在操作同一个受保护的变量

	缺点:受保护的变量,永远都不会被释放,使用过多,会导致内存泄漏
	
            

1、三个事件需要防抖节流

共同点:触发的速度飞快

			1、elem.onmousemove - 鼠标移动事件
			2input.oninput - 每次输入/改变都会触发
			3、onresize - 每次窗口改变大小都会触发

		防抖节流的公式:
		
	
		function fdjl(){
			var timer=null;
			return function(){
				if(timer!==null){clearTimeout(timer);timer=null;}
				timer=setTimeout(()=>{
					操作
				},500)
			}
		}
		
		var inner=fdjl();

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

5.******两链一包:

1、作用域链:以函数的EC的scope chain属性为起点,经过AO,逐级引用,形成的一条链式结构,我们就称之为叫做作用域链

作用:查找变量,带来了变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错

2、原型链:每个对象都有一个属性叫做.proto,可以一层一层的找到每个对象的原型对象,最顶层的就是Object的原型,形成的一条链式结构,我们就称之为叫做原型链

作用:查找属性和方法,哪怕自己没有也会顺着原型链向上找,怪不得人人都能用toString(),因为他在最顶层

3、闭包:希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊

作用:专门用于防抖节流