JavaScript基础

406 阅读1小时+

JavaScript基础

一、JavaScript的定义和使用方法

**JavaScript是一个运行在浏览器端的解释型弱类型面向对象的脚本语言**

1.浏览器端:环境  自带JavaScript解释器,打开浏览器自动运行
2.编译型:程序执行前先检查语法是否正确,不正确直接不运行
  解释型:程序执行前不需要先检查语法是否正确,直接运行,碰到错误停止
3.强类型:变量保存的数据,严格按数据类型决定
  弱类型:数据类型由数据决定
         1    -->  number 数字
         "1"  -->  string 字符串
4.面向对象
5.特点:一切编辑工具都可以编写js代码/完成一切css完成不了的

js的使用方法:
1.在HTML页面上书写一个script标签,再在里面书写type="text/javascript" (不推荐使用)
2.外部引入

二、检查错误的方式 -- 打桩输出/输出的方式

1.在控制台输出日志      console.log();
2.在页面上输出日志      document.write();
3.在弹出框上输出日志    alert();
  扩展:用户输入框      var 保存=prompt("提示文字")
             例如      var r=prompt("请输入半径");
             

三、变量和常量

(一)变量***

  语法: var 变量名=值;
  特殊:
       1.不能以数字开头
       2.建议使用驼峰命名法和下划线命名法
       3.语义化
       4.如果变量名是name,数据类型一定是数字
       5.变量名不能是关键字
       6.变量可以只创建不赋值
       7.如果多个变量连续创建,用逗号隔开
   

(二)常量

   创建后不允许修改
   语法: const常量名=值;
   

四、数据类型的分类

(一)原始/基本/值类型***

1.number  -  数字     取值无数(颜色蓝色)    
2.string  -  字符串   取值无数,取值需要加' '或者" "(颜色黑色)
3.boolen  -  布尔     取值  true/false
4.null    -  空       取值唯一  null
             作用:释放变量释放内存,节约内存空间,提升网页性能(颜色灰色)
5.underfined 报错     取值唯一 (颜色灰色)

(二)引用/对象类型

有11个...

(三)运算符

1.算术运算符***

' + - * / %

特殊
  (1" % " 取余,俗称模
       作用:
       1.判断奇偶数  任意数%2
       2.取出某个数字后n位  1234%10   - 4
                           1234%100 - 34 2)带有隐式转换,默认:左右两边转为数字后运算
       true       - 1        flase    - 0
       underfined - NaN      null     - 0
       "1000"     - 1000     "1000px" - NAN
    NaN:Not A Number:不是一个有效数字,但是是数字类型
      缺点:参与任何算术运算结果都是NaN
           参与任何比较运算结果都是flase
           
  (3)特殊的 + 运算
       如果碰上一个字符串,左右两边都会悄悄转为字符串+运算,拼接

2.比较/关系运算符

' < > >= <= != == === !==

结果一定是一个布尔值
带有隐式转换,默认两边转为数字后再比较大小

特殊:
(1)如果参与左右为字符串,则按位pk,每个字符的十六进制 unicode号
     数字0-9 < 大写A-Z < 小写a-z < 汉字
     常识:
       汉字第一个字是一,unicode号是4e00,ascii码是19968
       汉字最后一个字是龥,unicode号是9fa5,ascii码是40869
 

3.赋值运算符

' = += -= *= /= %=

1)赋值:将右边的保存在左边变量名中
(2)运算后变回变量本身    i=i+1 -->i+=1

4.逻辑运算符

' && || !

1)&&  与  全满足才为true2)||  或  全不满足才为false3) ! 非  取反
 
 结果一定是布尔值 true/false

5.自增自减运算符

自增:每次固定只能+1

前++,返回的是加了以后的新值
后++,返回的是加了之前的旧值

6.位运算

左移:m<<n  读作m左移了n位,翻译:m*2的n次方
右移:m>>n  底数只能为2

五、分支结构

程序的流程控制语句:3种

(一)顺序结构

默认:从上向下一次执行每一句话

(二)分支结构

通过条件判断,选择部分代码执行

1.if..else

语法:

1)一个条件,一件事,满足就做,不满足就不做
    if(条件){
             操作;
             }
    
(2)一个条件,两件事,满足就做第一件,不满足就做第二件
    if(条件){
              操作;
              }else{
              默认操作;
              }
 
 (3)多个条件,多件事,满足谁就做谁
    if(条件){
              操作1;
              }else if(条件2){
              操作2;
              }else{
              默认操作;
              }
             

注意:

   1.if...else的数量不定
   2.else可以不写但不推荐
   3.分支走了一条路就不走其他路
   

2.switch...case分支

语法:

Switch(变量/表达式){
                    case1;
                    操作1breakcase2;
                    操作2breakdefault;
                    默认操作;
                    }
                    
特殊:
(1)存在的问题:默认只要一个case满足后就会将后续所有操作全部执行
     解决:   break;
     建议每一个case操作后面都跟上一个break
     有的地方也可以不加break
     比如:最后一个操作default,可以忽略break
           如果中间多个条件,做的操作都一样,可以省略中间
(2case在做比较的时候 是不带隐式转换的
(3default可以忽略,但是不推荐

3.if和Switch的区别

switch..case:
  优点:执行效率高,速度快,比较用做等值比较
  缺点:必须先知道结果
if..else..
  优点:比较时做范围判断,不用提前知道结果
  缺点:执行效率慢,速度慢

建议:代码开发完后,要做代码优化,尽量少用if..else..

4.三目运算:简化分支

语法:

条件?操作1:默认操作;
条件1?操作1:条件2?操作2:默认操作;

注意:

1)默认操作不能省略,省略会报错
(2)操作只能有一句话,操作多句话还是推荐使用switch或者if

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

(三)循环结构

  • 通过条件判断,选择要不要重复执行某块代码

  • 循环三要素:循环条件/循环体/循环变量

    执行原理: 
     首先创建循环变量,判断循环条件,如果条件满足
     则做一次循环体操作,再次判断是否符合条件
     满足则做一次循环操作...直到条件不满足,才会退出循环
     
    特殊:
     1.有时候会用到死循环;默认永远不会停下来的循环
       不确定循环次数时使用
       whiletrue){死循环}
     2.死循环的停止
       break      退出整个循环
       continue   退出本次循环
    

1.while循环

语法

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

2.for循环

语法

forvar 循环变量=几;循环条件;循环变量变化){
    循环体;
    }
    

特殊

死循环:for(;;){}

3.do..while循环(废物)

语法

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

4.while和for的区别

原理上几乎没有区别

不确定循环次数时使用   while 循环
确定循环次数时使用     for   循环

5.while和do..while的区别

区别只有第一次,如果第一次条件都满足,那么两者没有区别
但是如果第一次条件不满足,那么while一次都不会执行
                        do..while至少执行一次

(四)强制(显示)数据类型转换:

当隐式转换出来的东西我们不想要的时候,需要先强制转换

1.转字符串

(1)var str=x.taString();

x不能underfined和null,会报错,因为她们不是可识别对象

(2)var str=string(x);

  • 万能的,任何人都可以转为字符串
  • 但不要手动使用,完全等效于隐式转换,还不如 +""

2.转数字***

(1) parseInt(str/num);***

parse解析 Int整型 专门用于将字符串转为整数

执行原理:
   从左向右一次读取转换每个字符,碰到非数字字符就停止转换
   如果一开始就不认识则为NaN,不认识小数点

(2)parseFloa(str);

parse解析 Float浮点型 专门用于将字符串转为小数点

 执行原理:
    几乎和parseInt一样,认识第一个小数点 

(3)number(x);

  • 万能的,不要手动使用,完全等效于隐式转换
  • 还不如-0 *1 /1

3.转布尔

boolean(x);

  • 万能的,不要手动使用,还不如 !!x
  • 只有6个为false:0,"",underfined,null,false,NaN

六、function的基础

(一)概念

function也加函数也叫方法,[先预定义]好

以后可以[反复使用]和[代码段]

(二)如何使用函数

1)定义/创建/声明:
   function 函数名(){
      函数体/代码段;
   }
   
(2)调用函数
    1.在js内部写:函数名();  
      程序员写几次就调用几次
    2.在HTML上绑定事件:

-公式

   <elem onclick="()"> </elem> 
   鼠标移入*  onmouseover
   鼠标移出*  onmouseout

(三)什么时候使用函数

  1. 不希望页面打开后立即执行
  2. 希望用户来触发,提升用户体验感
  3. 以后每一个独立的功能(作业)都需要封装成一个函数

(四)带有函数形象的函数

(形式参数)形参:一个不需加var,不需要赋值的变量 语法

  function 函数名(形参){
           函数体/代码段;
  }
  

带有形参的函数时,必须传入实参,顺序和数量必须一一对应

总结:不带参数的函数,用于执行一些固定操作
      带参数的函数:可以根据我们传入的实参不同,做得不同
      

(六)自定义函数:function***

1.创建

(1)[声明方式]创建函数

语法

function 函数名(形参列表){
         操作;
         return 返回值/结果;
         }      

(2)[直接量方式]创建函数 - 不推荐

语法

var 函数名=function(形参列表){
         操作;
         return  返回值/结果
         }

2.调用

var接住返回的结果=函数名(实参列表)
  • 其实return本意是退出函数,但如果return后跟着一个数据
  • 顺便将数据返回函数作用域的外部,但是return只负责返回,不保存
  • 所以调用函数时自己那个变量来接住他
  • 如果有一天你在全局希望拿着函数的结果去做其它操作,记得加return

3.作用域***

(1)全局作用域:全局变量+全局函数

(2)函数作用域:局部变量+局部函数[当前函数调用时,内部可用,优先使用局部]

特殊(缺点):
  1.不要对函数中未声明的变量直接赋值 - 全局污染
  2.局部可以使用全局,但全局不能使用局部
    解决方式:return

4.声明提前***(只出现笔试)

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

  • 声明方式创建的函数会完整的提前

  • 直接量方式创建的函数只有变量名部分会提前

    为什么平时遇不到?? 遵守以下规则:变量名和函数名尽量不要重复/先创建后使用

5.重载***

重复的函数名,后面会覆盖前面的

目的:减轻程序员压力,记住一个方法就可以执行很多操作
解决:在函数内部自带一个arguments的对象(类似数组对象)
     不需要我们去创建,可以接受所有实参
     默认length长度为0
固定套路:
  1.通过下标去获取传入的某一个实参
    arguments[i]-i0开始
  2.通过length去获取到底传入了几个实参
    arguments.length
    通过判断传入实参的不同,在内部去写判断
    从而变相的实现重载
    

七、数组的基础***

(一)数组的概念

创建一个变量可以保存多个数据,可以节约内存提升网站性能

数组都是线性排列:
    除了第一个元素,每个元素都有唯一前驱元素
    除了最后一个元素,每个元素都有唯一后继元素
    
**元素的位置叫下标,从0开始,在最大长度结束**

(二)创建数组

1.直接量方式***
  var arr=[];  //空数组
  var arr=[数据1,...]
2.构造函数方式
  var arr=new Array();  //空数组
  var arr=new Array(数据1,...);
  

(三)获取数组中的元素

数组名[i]

(四)后续添加/替换元素

下标处没有则为添加,有则为替换

(五)数组具有三大不限制

1.不限制元素的类型
2.不限制元素的长度
3.不限制下标越界  -  underfined

下标越界的解决方式:

数组中的唯一属性length,语法:数组名.length(长度从1开始)

三个固定套路:
   1.向末尾添加元素: arr[arr.length]=新数据
   2.获取数组的倒数第n个元素: arr[arr.length-n];
   3.缩容:删除倒数n个元素  arr.length=n;
   

(六)遍历数组

固定公式:
   for(var i=0;i<arr.length;i++){
       arr[i];  //当前次元素
       }
       

八、DOM:文档对象模型*******

DOM:Document Object Model,用于操作HTML文档

(一)DOM树概念

  • HTML看做一个倒挂的树状结构,但树根不是html,是document的对象
  • document对象:不需要我们创建,由浏览器的js解释器自动创建,一个页面只有一个树根
  • 作用:可以通过树根找到我们想要的任意DOM元素/节点/(属性和方法)对象
  • DOM会将页面上的每个元素,文本等视为一个DOM/节点/对象

(二)查找元素

1.通过ID查找元素:

var elem=document.getElementById"id值")
特殊:
1.返回值,找到了返回当前找到DOM元素,没找到返回一个null
2.如果出现多个相同ID,只会找到第一个
3.记住控制台输出的样子,这才叫一个DOM元素/节点/对象,才能操作
4.忘记此方法,留给后端
5.其实不用查找,id直接可用

2.通过标签名查找元素*******

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

特殊:
  1.返回值,找到了返回一个类数组DOM集合,没找到得空集合
  2.js只能直接操作DOM元素,不能直接操作DOM集合***
    (解决:要么拿到某个下标,要么遍历拿到每一个)
  3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素

3、通过 class 查找元素*******

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

特殊:
1、返回值,找到了返回一个类数组DOM集合,没找到得到空集合
2、js只能直接操作DOM元素,不能直接操作DOM集合,解决:要么下标拿到某一个,要么遍历拿到每一个。
3、不一定非要从document开始查找,如果从document去找,会找到所有的元素,可以换成我们已经找到的某个父元素

4、通过关系去获取元素:前提条件:必须先找到一个元素才可以使用关系*******

通过关系去获取元素
父元素elem.parentNode;单元素
子元素elem.children;集合
第一个子元素elem.firstElementChild单元素
最后一个子元素elem.lastElementChild;单元素
前一个兄弟elem.previousElementSibling;单元素
后一个兄弟elem.nextElementSibling;单元素
  • 为什么要通过关系去找元素呢?
  • 不希望影响到别人,只希望影响到自己的关系网

5.直接找元素******

任意css选择器

   var elem=document.querySelector("任意CSS选择器")
 quary查询  selector选择器:查询css选择器
 缺陷:只能找到单个元素
      如果匹配到了多个,也只能返回第一个,没找到null
      
   var elems=document.querySelectorAll("任意css选择器")
 优点:找到了是集合,没找到是空集合
      复杂查找时,非常简单
      返回时是一个【静态集合】,NodeList
  • 面试题:document.getXXX和document.queryXXX的区别?
  • 1.后者更适合复杂查找
  • 2.动态集合和静态集合的区别?
    • 动态集合:不支持forEach,DOM变化后再次查找,让页面和数据保持一致,效率低。

    • 静态集合:支持forEach,DOM变化后不会再次查找,让页面和数据没有保持一致,效率高。

(三)操作元素

前提:先找到元素,才能操作元素,3方面

1、内容:

(1)elem.innerHTML***

获取和设置开始标签到结束标签之间的内容,支持识别标签的

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

(2)elem.innerText***

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

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

elem.innerText-获取和设置开始标签到结束标签直接的纯文本,不识别标签

(3)input.value - 专门获取/设置input里的内容

单标签input专属

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

2、属性:

**(1)获取属性值:**
  核心DOMelem.getAttribute("属性名");
  HTML DOMelem.属性名
    
**(2)设置属性值:**
  核心DOMelem.setAttribute("属性名","属性值");
  HTML DOMelem.属性名="属性值"  

    (3)删除属性:
    只删除了属性值,属性名还在 
    (类似hrefdisabledreadonly等)
  **核心DOM**     elem.removeAttribute("属性名")
  HTML DOMelem.属性名
  
      (4)判断有没有:
    只能判断有没有(推荐:elem.getAttribute("属性名");)
    **核心DOM**     elem.hasAttribute("属性名")
  HTML DOMelem.属性名!="";
    

    HTML DOM简化版的缺点:
  1class必须写为className 
         ES6(2015年)class变成了一个关键字
  2、不能操作自定义属性
      
  建议:优先HTML DOMHTML DOM实现不了在用核心DOM补充

3、样式:

使用样式的方式:3种
  1、内联样式***
  2、内部样式表
  3、外部样式表 - 一阶段做开发用的都是外部样式表
	
 二阶段我们就要用js来操作【内联样式】
  1.不会牵一发动全身
  2.优先级最高

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

    特殊点:
  1、css属性名,有横线的地方,去掉横线,变为小驼峰命名法
	border-radius     -----  borderRadius
      2、小缺陷:获取时,我们只能获取到内联样式
                因为我们目前学的就是内联样式的操作

4、绑定事件

elem.on事件名=function(){
	操作;
        关键字this - 这个 ***
	如果单个元素绑定事件,this->这个元素
	如果多个元素绑定事件,this->当前触发事件元素
	}
  • 一切的获取,往往都是为了判断
  • 一切的设置,可以说是添加也可以说是修改

5.操作内容

innerHTML/innerText/value

6.创建元素和上树

1)创建空标签
 var elem=document.createElement("标签名")
 (2)为其设置必要的属性和事件
 elem.属性名="属性值";
 elem.on事件名=function(){操作}
 (3)挂载上树/渲染页面:
 父元素.appendChild(elem);
 insetBefore(elem,已有子元素);放已有子元素前
 replaceChild(elem,已有子元素;替换已有子元素)
 

7.删除元素

elem.romove();

扩展

1.创建变量:新增let关键词可代替var

  • let 变量名=值;
  • 作用:
    • 解决了声明提前
    • 带来了会计作用域,一个{}就是一个块,此变量只能在{}里使用
    • 如果用let当下标去绑事件,会记录当前元素的下标,不需要自定义

2.类数组转普通数组

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

九、数组的基础(补充)***

(一)创建数组

1.直接量

 var arr=[值1,...]

2.构造函数

 var arr=new Arrey(值1,...);
 

3.new Array()num;(有坑)

意为创建了一个长度为num的空数组,里面没有任何东西,只有无数的underfined。

(二)按值传递***

面试题:var a=x;var b=a;修改ab变不变?或修改ba变不变?

答:
1.传递的如果是原始类型:(字符串,数字等...)
  其实是复制了一个副本给对方
  两者互不影响
2.传递的如果 是引用类型:(js中除原始类型,其它都是引用类型)
  因为引用类型比原始类型大很多
  不能保存在变量本地,只保存了地址值
  所以其实是将地址值赋值给了对方
  两者相互影响
  

(三)释放引用类型

  • 需要释放每一个变量
  • 原理:js底层有一个垃圾回收器,只有垃圾计数器为0的时候才会删除不要的数据

十、hash数组(关联数组)自定义下标***

(一)创建空数组

    1.创建空数组:var arr=[];
    2.为数组添加自定义下标并且赋值:arr["自定义下标"]=新值

(二)访问元素

    arr["自定义下标"]

(三)强调

- hash数组的 length失效了,永远为0!

- 遍历hash数组:不能再使用for循序,必须使用for in循环

- 纯自动化,专门为了遍历hash数组存在的

  for(var i in 数组名){
              i;          //下标
              数组名[i];   //当前次元素,=后面赋值的内容
  }
  • for in循环不仅可以遍历hash数组,也能遍历索引数组
  • 建议:索引数组依然是for,hash数组再使用for in

(四)hash数组的原理***

  • hash算法:把字符串计算出一个尽量不重复的数组(地址值)
  • 字符串的内容相同,则计算出来的数字也一定相同

添加元素:

  • 将自定义下标交给hash算法,得到一个数字(地址值),将要保存的数据放在里面保存起来

获取元素

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

(五)js里面的一切都是对象

  • 除了underfined和null,js里面的一切都是对象
  • 一切对象的底层都是hash数组

十一、数组的API

(一)arr转str***

  var str=arr.join("自定义连接符");
1.笔试题:将数组里面的内容拼接成一句话/单词
       (其实就是拼接了一个空字符串)
         
    var arr=["h","e","l","l","o"," ","w","o","r","l","d"];
    var str=arr.join("");
    console.log(arr.join(""));
2.将数组拼接为DOM页面元素(第一次遇到数据渲染页面)
  <body id="bd">
    <script type="text/javascript">
      //以后我们前端会从后端-数据库拿出所有的数据
      //假设我们已经拿到了
         var arr=["-请选择-","北京","南京","西京","东京","重庆"];
  //将数组拼接为页面标签字符串
  //var str="<开始标签>"+arr.join("</结束标签><开始标签>")+"</结束标签>";
         var str="<h1>"+arr.join("</h1><h1>")+"</h1>";
         bd.innerHTML=str;
  </script>
  </body>
  
3.二级联动
<body>
	城市选择:
	<select></select>
	<select></select>	
		
	<script type="text/javascript">
	var sels=document.getElementsByTagName("select");
	//生成一级的数据
	var arr1=["-请选择-","北京","南京","西京","东京","重庆"];
	//生成二级的数据 - 二维数组:数组中再次引用了数组,再次细分分类
	var arr2=[
		["-请选择-"],
		["-请选择-","北京1","北京2","北京3","北京4","北京5"],
		["-请选择-","南京1","南京2","南京3","南京4","南京5"],
		["-请选择-","西京1","西京2","西京3","西京4","西京5"],
		["-请选择-","东京1","东京2","东京3","东京4","东京5"],
		["-请选择-","重庆1","重庆2","重庆3","重庆4","重庆5"]	
        ];
	
	sels[0].innerHTML="<option>"+arr1.join("</option><option>")+"</option>";

	sels[0].onchange=function(){
		var i=this.selectedIndex;
		sels[1].innerHTML="<option>"+arr2[i].join("</option><option>")+"</option>";
	}
	sels[0].onchange();
	</script>
</body>
  • select专属事件 onchange
  • 只有在选中项发生变化时出发
  • select专属属性 selectIndex
  • 获取当前选中项下标

(二)数组的拼接 concat***

添加元素的新方式,将传入的实参全部拼接到arr末尾

  var newArr=arr.concat(新值1,arr1,...);
    
  • 特殊
  • 1.不修改原数组,返回一个新值
  • 2.count支持传入数组参数,悄悄的将传入的数组打散为单个元素再拼接

(三)截取子数组 slice***

根据传入的开始下标截取到结束下标

         var subArr=arr.slice(starti,endi+1);

-特殊

  • 1.不修改原数组,返回一个新数组
  • 2.含头不含尾
  • 3.endi可以省略不写,意为从starti一直截取到结尾
  • 4.starti可以省略不写,如果两个实参都省略,意为从头到尾复制一遍这种拷贝是深拷贝,复制了一个副本给对方
  • 5.支持负数参数,-1代表倒数第一个

以上API都不会修改原数组


以下API都会修改原数组

(四)删插替***

1.删除

   var dels=arr.splice(starti,n);//n代表被删除的个数
  • 特殊
  • 虽然直接修改原数组,但也有返回值,返回的是被删除的数据组成的新数组

2.插入

  arr.splice(starti,0,新值1,...);//
  • 特殊
  • 原来starti位置的元素和后续元素自动向后移动
  • 尽量不要插入一个数组,会导致我们的数组有一维和二位混合,不利于遍历

3.替换

  var dels=arr.splice(starti,n,新值1,...);//
  • 特殊
  • 删除的个数和插入个数可以不同

(五)翻转数组

不常用

  arr reverse ();//

(六)数组排列

1.冒泡排序 不推荐

固定公式

   var arr = [31, 21, 54, 4376, 69, 8, 8, 65];
	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
		}
	}
}

2.数组排序 arr.sort()

默认:将数组中的元素转为字符串后,再按位pk每个字符的unicode号(Ascii码)

  • //如果a-b返回的是一个正数:说明后一个>前一个
  • //如果a-b返回的是一个负数,说明后一个<前一个
  • //如果a-b返回的是一个0,说明后一个==前一个
  • //而sort方法会根据你返回的正数、负数、0,来自动考虑要不要交换位置

升序排列

var arr = [3, 6, 5, 1, 2, 11, 4, 123, 122];//匿名回调函数
     arr.sort(function(a,b) {
            //console.log(a); 后一个数字
            //console.log(b); 前一个数字
	    return b-a; //a-b为升序,b-a为降序
	})
console.log(arr);
  • 强调
  • 网页上只要有功能带有排序,底层一定为数组
  • 网页上只要有随机功能,底层一定用了随机数公式

(七)栈和队列

  • 添加元素和删除元素的新元素
  • 栈其实就是数组,只不过一端封闭,只能从另一端进出
  • 优先使用最新的数据
   //开头进:向前添加,会导致其他元素下标变化
     arr.unshift(新值,...);
   //开头出:删除元素,向前添加
     var.first=arr.shift();
   //结尾进:向后添加
     arr.push(新值1,...);
   //结尾出:向后添加
     var.last=arr.pop();
     
   //结尾进,开头出的缩写
   arr.push(arr.shift());
       
  • 扩展
1.开启
  timer=setInterval(function){
        操作;
  },间隔毫秒数)
  
2.停止  clear Interval(timer)
  
3.鼠标移入*  onmouseover

4.鼠标移出*  onmouseout

(八)二维数组

数组的元素,又引用着另一个数组(在一个数组中,希望再次细分每个分类)

  • 创建
   var arr2=[
	["-请选择-"],
	["-请选择-","北京1","北京2","北京3","北京4","北京5"],
	["-请选择-","南京1","南京2","南京3","南京4","南京5"],
	["-请选择-","西京1","西京2","西京3","西京4","西京5"],
	["-请选择-","东京1","东京2","东京3","东京4","东京5"],
	["-请选择-","重庆1","重庆2","重庆3","重庆4","重庆5"]	
    ];
  • 访问

    arr[行下标][列下标]

-特殊

  • 列下标越界返回underfined

  • 行下标越界返回报错。因为行下标越界得到underfined后,没有资格再加[]操作。

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

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

(九)ES5提供的API

  • 简化for循环
  • prev:前一个,val:当前值,i:当前值的下标,arr:当前数组本身

1.判断

(1)every:满足所有才为true,类似&&

   var bool=arr.every(function(val,i,arr)){
       ruturn 判断条件;
   }

(2)some:满足一个就为true,类似||

   var bool=arr.some(function(val,i,arr)){
       ruturn 判断条件;
   }

2.遍历

(1)forEach:直接修改原数组

   arr.forEach(function(val,i,arr)){
       操作;
   }

(2)map:不修改原数组返回一个新数组

   var newArr=arr.map(function(val,i,arr)){
       ruturn 操作;
   }

3.过滤和汇总

(1)过滤:筛选filter,原数组不变

   var subArr=arr.filter(function(val,i,arr)){
      return 判断条件;
   }

(2)汇总:reduce

   var subArr=arr.reduce(function(prev,val,i,arr)){
       ruturn prev tval;
   },基础值)

(十)ES6箭头函数

  • 简化一切匿名回调函数
  • 固定公式
  • 去掉function,()和{}之间添加=>
  • 如果形参只有一个,那么()可省略
  • 如果函数体只有一句话,那么{}也可以省略
  • 如果函数体只有一句话并且是return,那么ruturn和{}都可以省略

(十一)eval函数

eval()函数:可以结束一个字符串str作为参数,并把这个参数作为脚本代码来执行,如果在计算器中不使用eval()则为字符串,不能进行运算,结果为underfined---》只能用于脱数组的衣服

十二、String*****

(一)String的概念*****

  • 字符串:多个字符组成的只读字符数组(只读:不会修改原字符串,都会返回一个新字符串)
  • 和数组的相同点
  • 1.字符串中的个数:str.length
  • 2.获取字符串中的某个字符:str[i];
  • 3.遍历字符串
  • 4.所有数组不修改原数组的API,字符串也可以使用(concat、slice)
  • 和数组的不同点
  • 所有数组直接修改原数组的API,字符串都不可以使用
  • 比如排序只有数组可以使用

(二)引用/对象类型***

  • String Number Boolen -->包装类型
  • Array Function Date Math RegExp(正则
  • Error 错误
  • Object(面向对象开发方式)
  • Global(全局对象)- 只有在浏览器中被window对象代替了,自然保存着全局变量和全局函数,只不过windows可以省略不写。node.js中全局对象就叫global

包装类型***

  • 专门用于将原始类型的值,封装成一个引用类型的对象
  • 因为原始类型的值,原本就是没有任何属性和方法,意味着原始类型本身就是不支持去做任何操作的,前辈们为了方便程序员操作将这三个提供了包装类型(提供了属性和方法)
  • 使用:只要你试图使用原始类型的变量调用属性或方法的时候,自动包装
  • 释放:方法调用完毕后,自动释放包装类型,又变成了原始类型

(三)SrtingAPI*****

1.转义字符

  • 作用:
  • 1.将字符串中和程序冲突的字符转为原文
  • 2.包含特殊功能的符号
  • --换行:\n
  • --制表符:\t -->大空格,跟按tab效果一样
  • 3.输出unicode编码的字符
  • \u4e00 - ASCII:19968
  • \U9FA5 - ASCII:40869

2.大小写转换

  • 将字符串中每一个字符【先统一】转为大写或者小写再比较
  • 小写:var upper=str. toUpperCase();
  • 大写:var upper=str. toLowerCase();

3.获取字符串中指定位置的字符

str.charAt(i) ==>不如str(i) (变量中下标为i的值)

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

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

5.检索字符串

检查索引,检查下标,获取关键字的下标

var i=str/arr.indexOf("关键字")
  • 从starti位置开始,查找右侧第一个关键字的第一个字符的位置
  • starti可以省略,默认从0位置开始查找
  • 返回值
  • 找到了返回第一个关键字第一个字符的下标位置
  • 没找到,返回-1
  • 判断有没有
  • 强调
  • 数组也能只有此方法,数组这个方法是后期才添加上的,老IE的数组没有此方法

-笔试题

   var str="no zuo "
   var str="no zuo no die no can no bibi no";
	012345678901234567890123456789
			
	//鄙视题:找到所有的关键字的下标
	var index=-1;					                 while((index=str.indexOf("no",index+1))!=-1){
		console.log("找到了,下标为:"+index);
	}

6.拼接字符串

var newStr=str.concat("新字符串",...)
还不如+运算

7.截取字符串***

   var subStr=str/arr.slice(starti,endi+1);
   //用法和数组的用法完全一致
   var subStr=str.substring(starti,endi+1);
   //用法几乎和slice一致,但是不支持负数参数
   var subStr=str.substr(starti,n);
   //n代表的是截取的个数,不必考虑含头不含尾

8.替换字符串

var newStr=str.replace("固定关键词"/正则表达式,"新内容");

9.切割/分割/分隔字符串

作用:将字符串转为数组

 var arr=str.spilt("自定义切割符")

注意

  • 1、切割后,切割符就不存在了
  • 2、如果你的切割符些的是" ",切散每一个字符

10.去掉空白字符串

str.trim/trimStart/trimEnd()

11.扩展(js如何创建元素,生成随机数)

js如何创建元素 二维结构

  • 1.创建空标签:

    var elem=document.createElement("标签名");
    
  • 2.为其设置必要的属性和事件

    elem.属性名="属性值";
    elem.on 事件名=function(){操作}
    
  • 3.挂载上树/渲染页面

  • 父元素.appendChild(elem);

生成随机数

 arr(Math.random()*(max-min+1)+min)
 

十三、Math对象

(一)概念

  • Math对象:专门提供数学计算机的API
  • 强调:可以直接使用
  • 属性:PI,其他为科学计数法,几乎用不到

(二)Math的API

1.取整

1)上取整:超过一点点,就取下一个整数
   var num=Math.ceil(num);
   //小数位数不能超过15位,否则此方法只能取整,不能上取整2)下取整:无论超过多少,都会省略小数部分
   var num=Math.floor(num);
   (3)四舍五入取整:
   var num=Math.round(num);//只看小数位数的第一位

以上三个都局限很大

  • 取整的方式:以上三个+parseInt(str去掉单位)+num.toFixed(d)
  • num.toFixed(d)
  • 优点:
  • 1.可以四舍五入,并且保留指定小数位数
  • 2.解决浏览器的四舍五入的误差,2-1.6=3.99999...
  • 缺点
  • 结果是一个字符串,建议搭配parseFloat()使用

  • 笔试题:不允许使用toFixed的情况下,自己封装一个函数
  • 由用户传入数字和保留位数,实现四舍五入操作
<script type="text/javascript">
	function toFixed(num,d){
	num*=(10**d);
	num=Math.round(num);
	num/=(10**d);
	return num;
}
			
	var result=toFixed(Math.PI,2);
	console.log(result);

</script>

2.乘方和开方***

  • 乘方:Math.pow(底数,幂); -> 更简化:底数**幂
  • 开方:Math.sqrt(num); - 仅仅只能开平方

3.最大值和最小值***

var max/min=Math.max/min(a,b,c,d,e,f,g,...);
//自动在你传入的数字中比较出最大值或最小值
  • 问题:本身不支持数组参数

  • 解决:固定用法:

     Math.max/min.apply(Math,arr);
    //apply具有打散数组的功能
    

4.绝对值

Math.abs(-1);//1

5.随机数 Math.random***

  • Math.random(); 在0-1之间去一个随机的小数
  • 搭配上parseInt,只能取到0,但是不可能取到1,意味着取不到最大值
  • 公式:parseInt(Math.random()*(max-min+1)+min)
  • 强调:
  • 只要以后网页中某一块有随机的功能,他的底层一定用到了随机数

十四、Date对象:日期对象,提供了操作日期和时间的API。

(一)创建:4种

  • 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);
       //修改月份,从0~11,0代表1月
    

4、复制一个日期:

  • 为什么:日期的所有API都是直接修改原日期的,无法获得修改之前的日期

  • 所以,在执行API之前先进行复制,然后再操作复制后的日期

      var end=new Date(start);
    
  • 使用:

  • 1、两个日期对象之间,可以相减(大-小),得到一个毫秒差,换算出自己想要的任何一部分 - 日期的本质其实就是保存了一个毫秒数 - 做倒计时的关键

  • 创建日期的最后一种方式,绝对没人用:

    var date=new Date(毫秒数);
    //计算机元年:1970年1月1日 8点整
    

(二)API:

  • 分量:时间的单位
  • 年月日星期:FullYear Month Date Day
  • 时分秒毫秒:Hours Minutes Seconds Milliseconds
  • 每一个分量都有一对儿getXXX/setXXX的方法
  • 其中getXXX负责获取一个分量的值
  • 其中setXXX负责设置一个分量的值
  • 特殊:

1、取值范围:

1)FullYear - 当前年份的数字
  (2Month - 0~113Date - 1~314Day - 0~60代表是星期天
  (5)Hours - 0~236)Minutes、Seconds:0~59
  日期你如果设置超出范围,会自动进制

2、Day,没有set方法

3、如果希望对某个分量进行加减操作:

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

4、格式化日期为本地字符串:

    date.toLocaleString(); 
    //垃圾:具有兼容性问题
    //我们一般会选择自己创建一个格式化方法来格式日
    //用了此方法会失去一些东西:日期的自动进制、日期的API
    //但是你也会获得一些东西:字符串的API

(三)定时器:

1、周期性定时器:每过一段时间就会执行一次,先等后做**
    开启:timer=setInterval(callback,间隔毫秒数);
    停止:clearInterval(timer);

2、一次性定时器:等待一段时间,只会做一次就结束了
    开启:timer=setTimeout(callback,间隔毫秒数);
    停止:clearTimeout(timer);
        

简写:setInterval(()=>getTime(),500)

  • 同步技术:代码必须一行一行的执行,前面没做完,后面就等着
  • 定时器是我们第一次见到的异步技术:无论我这一块代码多么的耗时,也不会卡住后续代码

十五、BOM:Browser Object Model - 浏览器对象模型

  • 专门用于操作浏览器的,但是它使用的不多,远不如ES和DOM,浏览器很多操作都是自带的,而且BOM没有标准,
  • 各个浏览器都有自己的定义,但是大部分浏览器的都是一致规范的,除了老IE(8-)

(一)window对象:扮演着两个角色:

  • 1、全局对象:保存着全局变量和全局函数
  • 2、指代当前窗口本身:

属性:

  • 1、获取浏览器的完整大小:outerWidth/outerHeight
  • 2、获取浏览器的文档显示区域的大小:innerWidth/innerHeight - 获取每台电脑的浏览器的文档显示区的大小**
  • 3、获取屏幕的完整大小:跟window没关系:screen.width/height; - 我们目前学习的都是浏览器应用(网页),并不会去做桌面应用

方法:

打开链接的新方式:

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

   HTML:<a href="url">内容</a>
   JSopen("url","_self");
  • (2)当前窗口打开,禁止后退:

  • 使用场景:比如电商网站,结账后不允许后退

            history:当前【窗口的历史记录】前进后退
	    location:当前【窗口正在打开的url】:
	    location.replace("新url");
          //替换当前页面,不会产生历史记录

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

          HTML:<a href="url" target="_blank">内容</a>
	  JSopen("url","_blank");
  • (4)新窗口打开,只能打开一个

  • 使用场景:比如电商网站,只允许用户打开一个结账页面

 HTML:<a href="url" target="自定义一个name">内容</a>
 JSopen("url","自定义一个name");
  • 其实窗口的底层都是有一个名字的,如果打开了一个已经开着的名字的窗口的,他会把他关闭掉,再次打开

  • 学完这块,我们知道了两个点:

  • 1、以后的跳转,任何标签都可以

  • 2、提升用户的体验感

  • a标签的其他用途:

  • 1、跳转

  • 2、锚点

  • 3、下载按钮:

<a href="xx.exe/rar/zip/7z">下载</a>
  • 4、打开图片和txt文档:
   <a href="xx.png/jpg/jpeg/gif/txt">
   打开图片和txt</a>
  • 5、直接书写js-不需要绑定点击事件
<a href="javascript:js代码;">打开图片和txt</a>

打开新窗口/新链接:

newW=open("url","target","width=?,height=?,left=?,top=?");

特殊:

  • 1、如果没有加第三个参数,那么窗口会和浏览器融为一体

  • 2、如果你加了第三个参数,那么窗口会脱离浏览器独立存在

  • 3、关闭窗口:window/newW.close();

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

  • 5、改变新窗口的位置:newW.moveTo(新X,新Y);

  • 6、window提供了三个框:***

    警告框:alert("警告文字");
    输入框:var user=prompt("提示文字");
    确认框:var bool=confirm("提示文字");
      
    
  • 7、定时器也是window的*****

  • 8、事件:

  • (1)window.onload事件 - load - 加载:等待其他所有的资源加载完毕后才会执行的代码,放在里面的代码其实要最后才会执行

  • (2)window.onresize事件 - 窗口如果大小发生了变化,就会触发,搭配上判断innerWidth可以理解为是js版本的css媒体查询*

  • (3)window.onscroll事件 - 滚动事件,一旦滚动就会触发***

     获取滚动条当前的位置:
         window.scrollY
     获取元素距离页面顶部有多远:
         elem.offsetTop/offsetLeft
    
  • 9、本地/客户端存储技术:***

  • cookie:淘汰了,存储的大小只有2kb,而且操作极其麻烦,尤其要到处切割,只能最多保存30天

  • webStorage:H5带来了一个新特性,存储的大小有8mb,永久保存,而且非常简单

  • 分类2种:

  • 1、sessionStorage - 会话级,只要浏览器一旦关闭,数据就会死亡了

  • 2、localStorage - 本地即,只要你不清空,就会永久存在

  • 两者的用法是一模一样的,不用创建,直接可用

  • 操作:

  • 1、添加:xxxStorage.属性名="属性值";

  • 2、读取:xxxStorage.属性名;

  • 3、删除:xxxStorage.removeItem("属性名");

  • 4、清空:xxxStorage.clear();

(二)history对象

  • 保存当前窗口的正在打开的url(现在的url) *

  • 程序员常识 *

    1.协议:***
    https(加密)/http(未加密)/ftp(传输文件)/ws(直播)
            location.protocal;
    2.主机号/IP地址/域名:
    域名需要花钱购买,主机号/IP地址免费
    主机号:127.0.0.1  只能自己访问自己
            location.hostname;
    3.端口号
    https默认端口为443,http默认端口为80
    默认端口可以省略不写
            location.port
    4.路由/文件的相对路径:***
            location.pathname;
    5.请求消息/查询字符串:***
            location.search;
    
  • 跳转

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

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

十六、递归

(一)递归和纯循环

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

注意:

  • 算法:深度优先!优先遍历当前节点的子节点,子节点遍历完毕才会跳到兄弟节点
  • 缺陷:不要过多使用,性能相对较差,同时开启大量的函数调用,浪费内存,只有【层级不明确】时使用

区别:递归 vs 纯循环

  • 递归:
    • 优点:简单易用
    • 缺点:性能低
  • 纯循环:
    • 优点:几乎不占用性能
    • 缺点:难的一批

(二)绑定事件: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、支持绑定多个函数对象
	缺点:有兼容性问题

(三)扩展:select&option:

select&option只有他们可以简化创建元素&上树:

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

十七、BOM事件*********

(一)事件周期

  • 从事件发生,到所有事件处理函数执行完毕的全过程
    • 1.捕获阶段:由外向内,记录要发生的事件
    • 2.目标优先触发:当前点击的事迹发生事件的元素
    • 3.冒泡触发:由内向外

(二)获取时间对象event

  • 主流:会自动作为事件处理函数的第一个形参传入
  • 老IE:老IE全局都有这个变量

(三)事件对象event的功能

- 1.获取鼠标的坐标

获取鼠标的坐标
获取鼠标相对于屏幕的坐标e.screenX/Y
获取鼠标相对窗口/客户端/文档显示区域的坐标e.clientX/Y
获取鼠标相对于网页的坐标e.pageX/Y

- 2.阻止事件冒泡(笔试面试中

阻止事件冒泡(笔试面试中
主流e.stopPropagation();
老IEe.cancelBubble=true;
兼容e.cancelBubble=true;

- 3.利用冒泡冒泡*********

  • 开发中常用,提升网页性能,事件可换箭头
  • 优化:如果多个元素定义了相同或相似的事件操作,最好只给父元素定义一次
  • 每一次绑定一个事件函数,其实都是创建了一个事件对象,会影响网站性能
目标元素 target
主流e.target;
老IEe.srcElement;
兼容e.srcElement;

- 4.阻止浏览器的默认行为

阻止浏览器的默认行为
主流e.preventDafault;
老IEe.returnValue;
兼容e.returnValue;

新事件:右键事件/键盘事件

右键事件/键盘事件
右键事件window.oncontextmenu;
键盘事件
按住和按下,任何键盘按钮都可以触发window.onkeydown;
按住和按下,只有字母,数字,回车,空格可以触发window.onkeypress
松开,任何键盘按键都可触发window.onkeyup

- 5.获取键盘的键码

 e.keyCode:

老IE不支持HTML5和CSC3和ES5+

扩展:

  • 图片的加载速度比js执行速度慢,所有js执行完,图片还未加载完
  • 解决: img.onload - 图片加载完毕后才会执行的代码
  • 图片隐藏了,就该删除掉

(四)事件委托

1、如何判断目标元素是什么标签:

xx.nodeName; - 得到大写标签名

2、事件处理函数可以写为箭头函数

this就会失效,所以必须使用目标元素target

3、this的指向:******

 1、单个元素绑定事件,this->这个元素
 2、多个元素绑定事件,this->当前元素
 3、箭头函数,this->外部对象
 4、函数中,this->当前正在调用函数的这个人
 5、定时器中,this->window
 6、构造函数之中this->当前正在创建的对象

(五)事件的取消绑定

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

(六)强制改变this的指向*****

call/apply:临时的替换了函数的this - 借用 语法:

     函数名.call(借用的对象,实参,...);
 //单独传入每个实参
     函数名.apply(借用的对象,arr); 
 //只能传入一个实参要求是一个数组,apply其实会悄悄的打散数组
	强调:call/apply:相当于立刻调用函数,立即执行的

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

  • 1、创建了一个和原函数功能完全相同的新函数
  • 2、将新函数的this永久绑定为了指定对象,别人都借不走
  • 3、将新函数的部分参数永久固定

语法:

   var 新函数=函数名.bind(永久对象,永久实参,...); 
   //不是立刻执行,需要自己调用
  强调:bind绑定的新函数没办法被call/apply再次借走

-推荐:借,白嫖! 三个固定套路:

1Math.max/min.apply(Math,arr) - 也能支持数组参数:
2Object.prototype.toString.call/apply(x)==="[object Array]";
    //鄙视题:判断xx是不也是一个数组
3、类数组转为普通数组:
  (1)接住=Array.prototype.slice.call/apply(类数组对象)
      (2)接住=Array.from(类数组对象)

十八、ES6:

  • 学过了:let、const关键字、箭头函数

(一)模板字符串

可以直接识别变量,不再需要+运算去拼接了,而且实现了一个简答的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);
    
    只要以后见到:
        方法名({里面放着键值对就是使用了ES6的解构赋值})
    

(三)Set和Map新的数据类型:

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

var s=new Set(arr);
...s - 三个点扩展运算符,可以脱掉数组的外套
一句话完成:[...new Set(arr)] - 不用记忆任何API

2、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:忽略大小写

(二)备选字符集:/^[备选字符集]$/

强调:

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

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

  • 解决

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

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

    比如:
	一位数字:[0-9];
	一位字母:[A-Za-z];
	一位数字、字母、下划线:[0-9A-Za-z_]
	一位汉字:[\u4e00-\u9fa5]

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

(三)预定义字符集:简化了备选字符集

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

(四)量词:规定一个字符集出现的次数:

1、有明确数量:
	字符集{n,m}:前边相邻的字符集,至少n个,最多m个
	字符集{n,}:前边相邻的字符集,至少n个,多了不限
	字符集{n}:前边相邻的字符集,必须n个

2、无明确数量:
	字符集?:前边相邻的字符集,可有可无,最多1个
	字符集*:前边相邻的字符集,可有可无,多了不限
	字符集+:前边相邻的字符集,至少一个,多了不限

(五)选择和分组:

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

(六)指定匹配位置

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

(七)密码强度验证:

题目: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}/;
//至少要有下划线

(八)支持正则表达式的字符串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的时候,正则出现了分组,我们会得到更多的形参
			//再形参a的后面就会出现n个形参,就看你有多少个分组
			//第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);

总结

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

3、正则对象:

创建:

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

4.API:

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

二十、动画库

  • animate.css文件是一个动画库:放着很多很多的动画。
    • 如何使用:

1、打开百度:搜索animate.css 得到网址
	http://www.animate.net.cn/
	https://animate.style/
2、下载 - 你们不用做这个操作
3、引入此文件
4、挑选你喜欢的动画,把class放到那个元素上
5、并且要记得设置上animation-duration:3s; 执行时长
6、还需要根据不同的动画,设置不同的初始效果,才会更好看

二十一、Object:对象********

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

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

(一)***开发方式:

  • 面向过程:

  • 过程 - 开始->结束,其实我们一致的开发方式都是面向过程:先干什么再干什么最后干什么

  • 面向对象:

  • 对象(属性和方法),js有一句话万物皆对象,假设一个人是一个对象的话:

    • 属性:身高、体重、姓名、性别、爱好、智商、情商..
    • 方法:吃饭、睡觉、跑步、拉粑粑、打字、上课...
  • 何时使用面向对象

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

  • 为什么要面向对象:

  • 现实生活中所有的数据都必须包含在一个事物之中才有意义

(二)封装/创建/定义:封装自定义对象: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.属性名

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的指向问题

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

  • 代码重用!提高代码的复用性,节约了内存空间!提升了网站的性能!
  • 何时继承:
  • 只要多个子对象公用的属性和【方法】,都要集中定义在父对象之中

1、如何找到原型对象(父对象):***

保存了一类子对象共有属性和共有方法

 1、对象名.__proto__; //必须先有一个对象
 2、构造函数名.prototype;
     //构造函数名几乎人人都有
     除了MathWindownew 构造函数名();
     //Array、String、Date、RegExp...

2、面试题:两链一包:作用域链和【原型链】和闭包*

  • 1、作用域链:

    • 以函数的EC的scope chain属性为起点,经过AO,逐级引用,形成的一条链式结构,我们就称之为叫做作用域链。
    • 作用:查找变量,带来了变量的使用规则:优先使用自己的,自己没有找全局,全局没有就报错(面向对象)
  • 2、原型链:

    • 每个对象都有一个属性叫做.__proto__,可以一层一层的找到每个对象的原型对象,最顶层的就是Object的原型,形成的一条链式结构,我们就称之为叫做原型链
    • 作用:查找属性和方法,哪怕自己没有也会顺着原型链向上找,怪不得人人都能用toString(),因为他在最顶层(面向过程)
  • 3、闭包:

    • 希望保护一个可以【反复使用的局部变量】的一种词法结构,其实还是一个函数,只是写法比较特殊
    • 作用:专门用于防抖节流

3、设置共有属性和共有方法

		1、原型对象.属性名=属性值;
		2、原型对象.方法名=function(){}

4、继承判断是自有还是共有:*****

(1)判断自有:
   obj.hasOwnProperty("属性名");
//如果结果为true,说明是自有属性
//如果结果为false,有两种可能,说明可能是共有,也可能是没有
 (2)判断共有:
if(obj.hasOwnProperty("属性名")==false&&"属性名" in obj){
    //in关键字,会自动查找整条原型链上的属性
    //找到了结果为true,找不到结果为false
	共有				
}else{
	没有
}

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

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

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

6、*如何为老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];

7、如何判断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 构造函数名]
      
    

8、多态:

子对象觉得父对象的成员不好用,就在本地定义了同名函数,覆盖了父对象的成员,不严格定义:同一个方法,不同的人使用,效果不同,有多种形态

固定套路:

   Object.prototype.toString.call(x)==="[object Array]"

9、实现自定义继承:

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

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

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

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

(五)Function:闭包*****

作用域:21、全局:随处可用,可以反复使用
    缺点:容易被污染
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、内层函数再操作受保护的变量
                    
                    function outer(){}

outer() 强调:

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

缺点: 受保护的变量,永远都不会被释放,使用过多,会导致内存泄漏 - 不可多用 问题:应该在哪里去使用呢?

  • 三个事件需要防抖节流 - 共同点:触发的速度飞快
    • 1、elem.onmousemove - 鼠标移动事件
    • 2、input.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();
		}

(六)保护对象:保护对象的属性和方法

1、四大特性:

    {
        value: 1001, 
        //实际保存值的地方
        writable: true, 
        //开关:控制着是否可以被修改 - 默认值:都为true
        enumerable: true, 
        //开关:控制着是否可以被for in循环遍历到 
          //- 默认值:都为true
        configurable: true 
        //开关:控制着是否可以被删除 
          //- 默认值:都为true,总开关:一旦设置为false,其他特性不可以在修改,而且它本身也是一旦设置为false,不可逆
    }
    
修改四大特性:

(1)单一写法
        Object.defineProperty(对象名,"属性名",{
                修改四大特性
        })
调用一次方法只能保护一个属性的四大特性

(2)复合写法
        Object.defineProperties(对象名,{
                "属性名":{修改四大特性},
                ...
        })
至少方法只调用了一次

2、三个级别:

	1、防扩展:防止添加
		Object.preventExtensions(obj);

	2、密封:防止添加和删除
		Object.seal(obj);

	3、冻结:防止添加和删除和修改
		Object.freeze(obj);

3、动态数据***

		Object.defineProperty(obj,"name",{
			get:()=>{
				console.log("获取数据会进行拦截");	
			},
			set:v=>{
				console.log("设置数据会进行拦截");
				v;//拦截到的新数据
				d1.innerHTML=v;
			}
		})

vue中的所有数据都是动态数据,意味着他的底层就是做了拦截操作

(七)对象的深浅拷贝:*

1、浅拷贝:

		var obj1={"name":"obj1"};
		var obj2=obj1;

2、深拷贝:

		var obj1={"name":"obj1"};
		var obj2={...obj1}

3、深拷贝(以后如何脱掉后端传来的数据)

    后端穿衣服:var jsonText=JSON.stringify(obj1); 
    前端脱衣服:var jsonObj=JSON.parse(jsonText);
		此方法也能实现深拷贝

(八)Error对象:报错分析*

以后工作/学习的目的:

  • 1、快速找到错误
  • 2、记得要放用户

1、***浏览器自带4种错误类型:可以快速找到自己的错误

	语法错误:SyntaxError - 一定是你的符号写错了
	引用错误:ReferenceError - 没有创建就去使用了
	类型错误:TypeError - 不是你的方法,你却去使用了
	范围错误:RangeError - 只有一个API会碰到:num.toFixed(d);//d取值范围:0~100之间

2、只要发生错误,就会报错导致后续代码终止(闪退),我们不希望

错误处理: 就算发生错误,我们也不希望报错,而是给出一个错误提示,让后续代码可以继续执行

语法:

    try{
            只放入你可能出错的代码
    }catch(err){
            发生错误后才会执行的代码
            alert(err);
            //err就是我们的错误提示:只不过是英文的
            alert("中文的错误提示,来提示用户");
    }
  • try...catch...的性能非常差,几乎是所有代码里最差的,放在try中的代码效率会被降到最低
  • *可以用一个技术代替他:分支结构
  • *开发经验:记住一切的客户端输入/用户输入都是坏人 - 但是你不必担心,只要你做好该做的防护就不会出错(!isNaN、正则)

3、抛出自定义错误,只要是错误,后续代码都不会执行

	throw new Error("自定义错误消息");

4、ES5:严格模式

    开启:"use strict"; - 写在任何一个作用域的顶部都可以
    作用:
            1、禁止了全局污染,使用变量之前必须先创建变量
            2、将静默失败升级为了错误

5、柯里化函数

把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术

function add(a){
	return function(b){
		return function(c){
			console.log(a+b+c);
		}
	}
}
add(3)(5)(7)

二十二、百度/高德地图:

(一)定位技术有哪些?

  • 1、GPS - 美国(卫星定位):
    • 需要缴纳版权费用|安全性低
  • 2、北斗 - 中国自主:
    • 最初并不是民用,而是军用,使用的是惯性定位(定位并不精准)
    • 后期发展为了民用,添加了卫星定位了(更精确了) 物联网、车联网...
  • 3、基站定位
    • 信号的范围发射,可以检测到你现在的信号属于哪个范围。
  • 4、IP定位

(二)开发者如何使用:

  • 1、打开百度:搜索百度地图开放平台
  • 2、注册、登录百度账号
  • 3、拉到最下面、点击立即注册成为开发者
  • 4、进入控制台
  • 5、应用管理->我的应用->创建应用->实名认证->获得密钥(AK)
  • 6、鼠标移动到导航条->放到开发文档上->web开发->JavaScript API->示例DEMO
  • 7、挑选出你喜欢的地图,然后复制全部代码(HTML/CSS/JS),到你需要的位置
  • 8、查询经纬度:api.map.baidu.com/lbsapi/getp…
  • 9、百度地图你看上的每一个都可以混搭在一起,但是一定要注意版本:普通版(老) 和 webGL(新),是不可以混搭的

二十三、匿名函数:没有名字的函数

(一)自调:只能执行一次

好处:函数中的没用的变量是会自动释放的,他可以用于代替全局代码写法,两者很相似:都只会执行一次,但是自调会释放 语法

        (function(){
                console.log(1);
        })();

(二)回调:匿名函数不是自调,就是回调

	elem.on事件名=function(){}
	arr.sort(function(){})
	var obj={
		"方法名":function(){}
	}
	一切的回调函数,都可以简化为箭头函数

二十四、设计模式:

不仅仅局限于前端,它是一种编程思想,越来越复杂,对于我们前端人员要求也越来越高了。可以了解一下21种设计模式

(一)单例模式:

  • 也称之为单体模式,保证一个类仅有一个实例对象,并且提供一个访问它的全局访问点,为三阶段的vue,new Vue();

  • 举例:一个班级只有一个班主任,只有一个太阳,一个国家只有一个主席,"唯一" "便于访问(全局访问的)",行为对象变成做单例

  • 如何实现:

    • 利用ES6的let不允许重复声明的特性,刚好就符合了单例的特点

        let obj={
                "name":"袍哥1",
                "getName":()=>this.name,
        }
      
  • 缺点

    • 1、污染命名空间(容易变量名冲突)
    • 2、维护时不容易管控(搞不好就直接覆盖了)

推荐写法:

        var h52301=(function(){
                let state=null;
                return function(name,age){
                        this.name=name;
                        this.age=age;
                        if(state){
                                return state;
                        }
                        return state=this;
                }
        })();

        h52301.prototype.sayHello=function(){
                console.log(this.name);
        }

        var llc=new h52301("兰林传",18);
        var yxw=new h52301("因性温",19);

        console.log(llc);
        console.log(yxw);
        console.log(yxw==llc);

        llc.sayHello();
        yxw.sayHello();

        何时使用:我们的页面只有一个弹出框

(二)发布订阅模式 :

为三阶段vue的bus总线用到的底层原理就是我们的发布订阅模式

let obj={};
//创建订阅者
function on(id,fn){
        if(!obj[id]){
//判断有没有此id(有没有这个人),没有就创建一个空数组
                obj[id]=[];
        }
        obj[id].push(fn);
}
on("老袍",(msg)=>{console.log("小兰来了",msg)});
on("老袍",(msg)=>{console.log("小尹来了",msg)});
on("老袍",(msg)=>{console.log("小张来了",msg)});
on("老袍",(msg)=>{console.log("小李来了",msg)});
on("老袍",(msg)=>{console.log("小赵来了",msg)});
console.log(obj);//{"老袍":[fn,fn,fn,fn,fn]}

//发布者的操作
function emit(id,msg){
        obj[id].forEach(fn=>fn(msg));
        //obj["老袍"].forEach
}
btn.onclick=()=>{
        emit("老袍","一支穿云箭");
}

(三)事件轮询:

js其实是单线程引用,代码必然是从上向下,一步一步的执行,如果某一块代码非常耗时,可能会导致整个页面卡住,尤其如果你把js放在head之中,会看到页面是一个白板

1、宏任务:

不会再卡住我们的单线程应用,可以让后续代码先走,我们慢慢跟着来,但是问题在于,多个宏任务同时存在,到底谁先执行谁后执行,分不清

  • (1)定时器:setInterval和setTimeout
  • (2)Ajax

2、微任务:

ES6提供的Promise对象 - 可以控制异步代码,依然是异步代码,但是可以控制执行的顺序了

    function ajax1(resolve){
            setTimeout(()=>{
                    console.log(1);
                    resolve();
            },Math.random()*5000);
    }

    function ajax2(){
            return new Promise(resolve=>{
                    setTimeout(()=>{
                            console.log(2);
                            resolve();
                    },Math.random()*5000);
            })
    }

    function ajax3(){
            return new Promise(resolve=>{
                    setTimeout(()=>{
                            console.log(3);
                            resolve();
                    },Math.random()*5000);
            })
    }

    new Promise(ajax1).then(ajax2).then(ajax3);
    //promise的回调函数提供了一个形参函数,可以用于放行
    console.log("后续代码");

二十五、Node_js基础

(一)基本内容:

1、服务器端概念:

  • 简单来说就是一台电脑
  • 生活中:微机
  • 商业中/国家中:小型机(造价几十万好的上百万)、中型机、大型机、超级计算机

拥有服务器的方式:

  • (1)买一对中小型公司不友好

  • (2)买一台配置好一点的微机 - 对于别的行业的公司也不太划算

  • (3)租云服务器 - 腾讯云、阿里云、新浪云、百度云... 配置自选:配置越好,价格越高,按年收费

  • 对于开发人员来说

    • 硬件服务器 - 人人都有一台电脑
    • 软件服务器 - 中间件(软件可以将你的电脑变成一台服务器,人人都可以来访问你,就是我们要学习的Node.js

软件架构:服务器很重要

(1)C/S - Client客户端/Server服务器端

举例:
        QQ、微信、大型网络游戏
优点:
        1、用户体验感较好
        2、运行稳定
        3、对带宽的要求低

缺点:
        1、占硬盘空间
        2、更新过于麻烦 - 服务器端和客户端都要更新

(2)B/S - Browser浏览器端/Server服务器端

    举例:
            网页版QQ、微信、游戏

    优点:
            1、几乎不占硬盘
            2、更新简单 - 只需要更新服务器端
            3、电脑在垃圾都可以玩得起

    缺点:
            1、用户体验感较差(越来越好,尤其是现在出了个云平台,根本不用考虑你的电脑好不好,配置如何)
            2、对带宽的要求高(还好现在的网速越来越快的)

2、Node.js概述:

  • 不是JS,但是语法和JavaScript非常相似,他的竞争对手:Java、C++、C#、Python...

  • 做的功能绝对不是特效!做的事和服务器端其他语言是一致(和数据库进行交互,成为了一个前端到数据库的中间桥梁)

  • 目的:

    • 1、使用代码搭建一个服务器&文件系统(服务器文件可以放在任何位置,但是不在你的电脑里,你可以根据网址来访问到我的东西)
    • 2、Node.js如何沟通前端和数据库
    • 3、全栈:图书管理系统(HTML+CSS+JS+Node+Mongo)

(二)Node.js安装:node-v18.15.0-x64.msi

检查是否安装成功:打开cmd输入:node -v - 查看版本号,如果有版本号代表你已经安装成功!

(三)Node.js运行模式

1、交互模式 - 临时测试
	打开cmd输入:node回车,就可以开始敲你的"js"代码

2、脚本/文件模式 - 正式开发中
	1、先创建xx.js,里面书写自己的代码
	2、打开cmd输入:node 文件的绝对路径

3、安装插件
	vscode - code runner
        对着文件出右键,第一个选项就是code runner,或者 右上角有一个开始按钮
	

(四)Node.js知识:

1、js和node的区别

  • 相同点:
    • 都可以使用一切的ECMAScript的东西包括一切的API都可以使用,在服务器端不存在任何浏览器,所以不必担心兼容问题
  • 不同点:
    • 1、JavaScript:DOM+BOM - 做特效
    • 2、Node.js:虽然没有DOM+BOM,但是他却又10万以上+的模块等待我们学习

2、模块(module):

每一个xx.js文件,都可以称之为是一个模块

(1)公开/暴露自己的成员

exports:Node.js自带的一个预定义变量,可以直接使用,是一个对象,放在此对象里面的东西,就是允许公开的东西

  • 语法:

      1exports.属性名=属性值;
      2module.exports={
              属性名:属性值,
              ...
            }
    
      错误导出法:
              exports={
                      name:"袍哥",
                      age:18,
                      hobby:"学习"
      				}
      	
    

(2)导入/引入其他模块

require:Node.js自带的一个预定义变量,可以直接使用,是一个函数,函数中需要书写出引入模块的路径

  • 语法: var x=require("./文件名")

鄙视题:exports和module.exports有什么区别?

1、语法,写法,用法不同
2、都是用于公开暴露自己的成员的
        但是exports={},写法是错误的
        其实Node.js底层有一句话:exports=module.exports
        其实真正做公开功能的是module.exports
        如果你使用了	            exports={};//你创建了一个新的空对象,把module.exports,所以不在具有公开的功能

3、模块的分类:

(1)官方模块

1、Global模块:不需要引入的,可以直接使用
1、五个预定义变量,可以直接使用
    (1)__filename - 获取当前文件完整的绝对路径
    (2)*__dirname - 获取当前文件绝对路径,不包含文件的名字,何时:vscode某的同学可能不支持node.js上书写相对路径,只能写绝对路径 - 等我们学习了文件系统
    (3)*exports - 空对象,可以用于公开暴露自己的成员
    (4)*require - 函数,可以用于导入其他模块
    (5)***module - 指代当前模块本身,甚至包含着以上4个操作
2、定时器(周期性、一次性、瞬间定时器):定时器不是当初的js,只不过用法和当初一摸一样
3console也不是当初的console,只不过用法和当初一摸一样
2、querystring模块:解析查询字符串,使其变成一个对象,可以获取到前端传到后端的消息
        需要引入:var qs = require('querystring');
        作用:解析url查询字符串部分的功能
        var obj=qs.parse("查询字符串");
        想要获得前端传来的每一个部分:obj.键名;
        

垃圾:如果前端传来的是一个完整的url网址,他就解析不了了!

3、url模块***
需要引入:var url = require('url');
作用:提供了解析url各个部分的功能
var objUrl=url.parse("网址",true);
//支持第二参数,是一个布尔值,默认为false,一旦设置为true,自动使用querystring模块的parse方法去解析查询字符串部分
  • 真正的重点:
    • 1、查询字符串:objUrl.query.键名; - 前端form表单提交传到后端的东西
    • 2、路由/文件相对路径/请求地址:objUrl.pathname - 判断路由的不同,去读取不同的HTML发送给我们的用户看
4、Buffer模块:

缓冲区,可以将数据变成一个16进制的数字,后面的一些API可能会导致我们被动都到Buffer,但是你也别怕,因为Node.js中大部分的API,是支持Buffer

5、fs模块*****
需要引入:
var fs = require('fs');

*异步读取文件:
fs.readFile("文件路径",(err,buf)=>{
    buf->读取到的内容
})

异步写入文件:
fs.writeFile("文件路径","新内容"/buf,()=>{
    console.log("写入完毕后,要做什么,必须放在这里面");
})//会替换掉原来的东西

异步追加文件:
fs.appendFile("文件路径","新内容"/buf,()=>{
    console.log("写入完毕后,要做什么,必须放在这里面");
})//会替换掉原来的东西

强调:只有异步才能更完美的发挥Node.js的特点(快)
6、http模块 - 超级重点:搭建服务器
//引入了http(搭建服务器)、url(区分开路由和请求消息)、fs(读取文件响应给用户看)
var http=require("http");
var url=require("url");
var fs=require("fs");
//创建服务器应用
var app=http.createServer();
//为其绑定监听端口
app.listen(80);
//为其绑定请求事件:http:请求 - 响应模式,必须要有一个请求,才有一个响应
app.on("request",(req,res)=>{
	//req:request(请求)对象,他有一个属性叫做req.url,看了一获取到前端传到后端的路由和请求消息,但是路由和请求消息是融为一体的,不方便我们获取某个部分,所以我们引入了url,进行解析,分开两部分
	var objUrl=url.parse(req.url,true);
	//保存路由
	var router=objUrl.pathname;
	if(router=="/" || router=="/index.html"){
        //判断路由的不同,读取不同的页面给用户看
		//res:response(响应)对象,他有一个方法:res.end(响应的内容) - 可以响应给前端想要的东西
		fs.readFile("./public/html/index.html",(err,buf)=>{
			res.end(buf);//res.end只能用一次
		})
	}
})

扩展: 字符串有一个API:math var rs=str.match(reg);和indexOf几乎一致,但是支持正则,我们不关心为多少,只关心为不为null

强调: 一切的src和href都是一个请求都是一个路由,这个请求就需要后端来解析,根据不同的请求响应不同的内容

(2)第三方模块

多到数不清出,提供了很多官方模块没有的东西,有一个网址npm可以去下载 - 明天我们在学习

(3)自定义模块

Node.js最大的特点:

  • 快、非常快 - 以前最快的是php,js的速度是php的十六倍
  • 因为官方提供的东西少,甚至连数据库的操作API都没有提供的
  • 使用了chrome浏览器的v8引擎

4、模块(每个.js文件)的分类

  • (1)官方模块:不需要下载,再安装Node.js环境的时候就已经自带了,但是有的模块需要引入:require("模块名");
  • (2)第三方模块
  • (3)自定义模块:自己书写的xx.js:require("./模块名");

自定义模块:

  • 1、文件模块:

    • 创建xx.js去公开需要公开的内容,主模块要引入,必须写为require("./模块名");
  • 2、目录模块:3种用法

    • 1、比如创建m1的文件夹,在其中创建index.js的文件,去公开需要公开的内容,主模块要引入,必须写为require("./m1");
    • 2、比如创建m2的文件夹,在其中创建xx.js的文件,,去公开需要公开的内容,主模块要引入,必须写为require("./m2");必须再创建一个package.json的配置文件,写入:{"main":"xx.js"}
    • 3、创建一个文件夹必须名为:node_modules,再在其中创建出m3文件夹,在其中创建index.js的文件,去公开需要公开的内容,主模块要引入,必须写为require("m3");
  • 3、如何下载第三方模块:

    • npm工具:Node Package Manager:Node.js的模块/包管理器,专门用于管理第三方模块的,作用:下载、更新、删除、维护包之间的依赖关系

    • 打开网址:npm官网www.npmjs.com/

    • 搜索你需要用到的模块:尽量用带有完全符合标签的那个包,或者是 第一个包:

        1、打开cmd:检查npm是否安装成功:npm -v
        2、在你的项目之中,再打开cmd
        3、下载:npm i 包名
        4、更新:npm up 包名
        5、删除:npm un 包名
      

二十六、mongo就是基于json的数据库

(一)安装&启动:

  • 1、解压我提供的mongodb-win32-x86_64-2008plus-ssl-3.6.11.zip文件
  • 2、打开bin文件夹,里面有:mongo.exe(客户端) 和 mongod.exe(服务器端)
  • 3、如何启动:
    • 在bin文件夹中打开cmd:输入:.\mongod.exe --dbpath=你想要保存的绝对文件夹路径; - 服务器开启成功,而且那个文件夹就保存着你以后要存储的所有的数据
    • 不要关闭mongo服务器的cmd
    • 再打开一个cmd:输入:.\mongo.exe - 在上一个命令行可以查看我们是否链接成功 - 客户端开启成功

(二)mongo的语法:都是在客户端cmd输入

1、数据库的操作
        1、查询所有数据库:show dbs
        2、创建/切换数据库:没有就创建,有了就切换:use 数据库名称
        3、查看当前选中的数据库:db
        4、创建数据表:db.createCollection("表名") - 无限,一定要先创建数据表后,我们才能查看到自己创建的数据库
        5、删除数据库:db.dropDatabase(); - 一旦删除不能恢复,不推荐,因为要坐牢

2、数据表的操作
        1、创建数据表:db.createCollection("表名",{size:5242880,capped:true,max:5000}) - 最大存储空间为5mb,最多存储500个,意味着这个数据表做了限制,不推荐
        2、查看目前所有的数据表:db.getCollectionNames();
        3、删除数据表:db.表名.drop();

3、*****数据的操作
        1、增:db.表名.save({键值对,...}) - 一次只能插入一条数据
                db.表名.save([{},{},{},....]) - 一次插入多条数据
                举例:db.user.save([{name:"付楠",age:18,pwd:"666666",email:"fn@qq.com",vip:"0"},{name:"袍哥",age:19,pwd:"999999",email:"pg@qq.com",vip:"1"}])

        2、删:db.表名.remove({}) - 不推荐,删除数据库中所有的数据
                     db.表名.remove({name:"任小波"}) - 会删除数据库中name:"任小波"的所有数据

        3、改:db.表名.update({条件},{$set:{新内容}});
                举例:db.表名.update({name:"任小波"},{$set:{pwd:"123123"}});

        4、*查:db.表名.find(); - 找所有
              db.表名.find({pwd:"666666"}); - 找到所有的密码为666666的数据
              db.表名.find({},{name:1,pwd:1}) - 找到所有的数据,但是只返回name和pwd
              db.表名.find().sort({age:1}) - 按照age升序排列,-1为降序排列
              db.表名.find({age:{$gte:18}}) - 拿到所有age大于等于18的数据
              db.表名.find({name:/正则/}) - 甚至可以用正则(模糊查询)
              db.表名.find().skip(5).limit(5) - 跳过前5条,再拿5条,理解为5-10条数据(第几个分页条显示第几条数据-第几条数据)
              db.表名.find().count() - 获取到此表有多少条数据(做出分页条)

(三)安装mongoDBCompass软件:

图形化界面,直观、好看、方便 - 仅仅只用于给我们方便查看

(四)Node.js操作mongoDB:

1、安装第三方模块:mongoose

2、使用步骤:
    1、引入:const mongoose = require('mongoose');
    2、连接数据库:mongoose.connect("mongodb://127.0.0.1/数据库名称");
    3、创建出一个新的数据表的同时,设置数据类型的控制,防止用户乱输
        const UserSchema=mongoose.Schema({
                age: Number,
                pwd: String,
                email: String,
                vip: String,
                name: String,
        })
        //		模型名    类型限制     
        var User=mongoose.model("User",UserSchema,"数据表名");
    4、增:
        var x=new User({
        //仅仅只是创建出了一个x对象,并没有放入到数据库之中
                age: "20",
                pwd: "123123",
                email: "dy@qq.com",
                vip: "0",
                name: "dy",
        })

        x.save((err)=>{
                console.log("新增成功后要干什么");
        })

    5、删:
            User.remove/deleteOne/deleteMany({条件},(err)=>{// - 作者不推荐remove在mongoose之中使用
                    console.log("删除成功后要干什么");
            })

    6、改:
            User.update/updateOne/updateMany({条件},{新内容},(err)=>{// - 作者不推荐update在mongoose之中使用
                    console.log("修改成功后要干什么");
            })

    7、查:
            User.find({条件},(err,result)=>{
                    result就是你的查找到的结果
            })

    强调:mongoose不要下载,一会儿用我传给你们的

    目前:前端能传到后端的技术,只有一个:form表单,action属性可以随便自定义一个路由名称,后端解析此路由就可以通过objUrl.query.键名得到想要的部分

二十七、Ajax:Asynchronous JavaScript And XML*****

(一)同步交互和异步交互的概念:

  • 1.同步交互:

    • 用户向服务器端发起请求,直到服务器端进行响应的全过程,用户是不可以做其他事情的(等)
    • 典型:表单提交、网址请求 - 都属于同步交互
  • 2.异步交互:

    • 用户向服务器端发起请求,直到服务器端进行响应的全过程,用户是可以做其他事情的(不等)
    • 典型:ajax请求

(二)Ajax的定义

  • 直译:异步的JavaScript和XML - 前端技术
  • 不严格的定义:页面不完全刷新,只会导致页面局部发生改变的技术
    • 见过的异步技术/代码:
      • 1、定时器 - 做特效
      • 2、mongoose操作数据库的增删改查 - 操作数据库
      • 3、ajax - 目的:在不刷新页面的情况下和服务器端进行交互 - 可以将服务器端的数据放到前端(比较验证、数据渲染)

(三)使用步骤:

1、创建ajax核心对象:

	var xhr=new XMLHttpRequest();

2、建立和服务器端的连接

	xhr.open("GET/POST","路由");

3、向服务器端发送请求消息

xhr.send();//但是此方法很特殊:
        1、如果你是GET请求,send方法会失效,但是还不能省略,必须写为:
                xhr.open("GET","路由?key=value&key=value&...");
                xhr.send(null);

        2、如果你是POST请求,send方法可用,必须写为:- 暂时不能用
                xhr.open("POST","路由");
                xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
                xhr.send("key=value&key=value&...");

        get:获取 - ajax一般都是使用get,去找服务器端那东西的 - 举例:跟安全性不挂钩的,搜索框
        post:发送 - 举例:跟安全性挂钩,登录、注册

4、绑定状态监听事件

	xhr.onreadystatechange=()=>{
		if(xhr.readyState==4&&xhr.status==200){
			xhr.responseText - 服务器端相应的文本,ajax就难在你拿到东西了要干什么
		}
	}

readyState的请求状态
0 尚未初始化
1 正在发送请求
2 请求完成
3 请求成功,正在接受数据
4 数据接受成功
status的请求状态
200 表示请求成功
202 请求被接受但处理未完成
400 错误的请求
404 资源未找到
500 内部服务器错误,如asp代码错误

二十八、数据格式:

(一)XML:

1、面试题:HTML、XHTML、DHTML、XML分别是什么?

  • HTML - 网页:预定义了很多标签,我们学习后,就可以使用他们写出网页
  • XHTML - 更严格的网页:HTML5 -> XHTML -> HTML4.01,比如: - <input />、<input disabled="disabled">
  • DHTML - 动态效果网页:在离线端,我们的网页也具有动态的特效:其实不是新技术也不是新概念,而是现有技术的一个整合统称:HTML+CSS+JS(dom)
  • XML - 配置文件|数据格式:没有提供过任何预定义标签!全靠自定义

2、使用XML

	1、创建xx.xml文件
	2、必须写上声明标签:<?xml version="1.0" encoding="utf-8"?> - 必须放在第一行第一列
		version - 版本号:目前有的版本只有1.0和1.1,但是1.1升级并不理想,没有人使用,所以1.0可以说是唯一版本,而且你学了以后都不用在学了,以后都不会更新了,因为已经淘汰了,有更棒的人(JSON)
		encoding - 编码格式
	3、必须写上一个根标签,而且只能写一个根标签,而且必须是双标签
	4、里面你随意,你想放什么就放什么
	5、恭喜你,学完了

	开发中,正常来说后端会想办法将数据库的数据整理为一个xml格式的文件
  • 前端:依然使用ajax去获取xml
    • 1、路由 写为 "xx.xml"
    • 2、xhr.responseText 换成 xhr.responseXML - 可以使用【核心DOM】去操作你需要的东西 - 淘汰的原因,现在来获取数据都要使用核心DOM,太麻烦了

(二)JSON:JavaScript Object Notation:JS对象表示法,本身就是JS的一部分

作用:数据格式 类似于 XML
好处:比XML 更简洁、更快、更容易解析 

1、哪些属于JSON字符串:
	(1'[1,2,3,4,5]';
	(2'{"key":value,...}';
	(3'[{},{},{},{}]';
	()'{"names":[1,2,3,4],"ages":[1,2,3,4]}'

2、后端把数据库的数据取出来整理为一个JSON字符串:
          var jsonTxt=JSON.stringify(jsonObj);

3、前端依然使用ajax去获取响应数据,真正重要的:                                 
           xhr.responseText;
      将JSON字符串解析为一个JSON对象:那么:2种方法 - 脱衣服
	1eval("("+xhr.responseText+")");
	2、*JSON.parse(xhr.responseText);

1、jQueryUI:基于jQuery(基于JavaScript的一个框架,是三大框架出现之前,最火的一个,但是现在已经被淘汰了)的开源网页用户界面代码库 - 提供了HTML、CSS、JS的一个插件库 三大框架:Vue(中国人的框架)、React、Angular(在国内几乎没有市场) 组件库:组件,组成网站一部分的部分,代码重用,一般不具备JS功能:比如导航条、图文显示... 插件库:跟组件差不多,只不过带有JS功能 - 选项卡、轮播...

如何使用插件库:
	1、下载jQueryUI - 不需要你们做
	2、必须在页面上进行引入: - 顺序不能错,一定要先引入jquery.js再引入jquery-ui.js
		<link rel="stylesheet" type="text/css" href="jquery-ui-1.13.2.custom/jquery-ui.css"/>
		<script src="jquery-ui-1.13.2.custom/external/jquery/jquery.js" type="text/javascript" charset="utf-8"></script>
		<script src="jquery-ui-1.13.2.custom/jquery-ui.js" type="text/javascript" charset="utf-8"></script>
	3、挑选出你需要的/喜欢的插件,直接梭到你的项目中
	4、根据设计图,来修改样式 - 修改不成功,只有一个可能:权重不够
	5、使用ajax去获取数据库中的数据,来进行页面渲染
	6、千万别忘了调用jQuery提供的xx方法来实现功能

	个人比较推荐的JQUI的插件:
		1、选项卡/标签页
		2、菜单
		3、手风琴/折叠面板
		4、模糊查询/自动完成
		5JQ动画/特效
		6、交互部分自己试试

二十九、前端框架

使用jQuery简化了核心DOM 必须先引入:

<script src="jquery-ui-1.13.2.custom/external/jquery/jquery.js" type="text/javascript" charset="utf-8"></script>

jQuery中$:

	作用:
		1、查找元素:$("JQ选择器"); - 包含一切css选择器的,不需要记忆:推荐网址:https://www.w3school.com.cn/jquery/jquery_ref_selectors.asp - 底层就是document.querySelectorAll
		2、创建元素:$("<标签></标签>"); - document.createElement
		3、可以将DOM转为JQ:$(DOM对象);
		4、代替了window.onload - $(callback);面试题:两者的区别?
			1window.onload - 等待所有资源(html、css、其他js、图片、视频、音频。。。)加载完毕才会执行,效率降到了最低,而且一个页面只能写一次
			2、$(callback) - 只是等待DOM加载完毕就会执行,性能比window.onload要高,而且一个页面能写多次
		底层用到了一个人:重载:arguments - 可以通过判断用户传入的实参的不同执行不同的操作

(一)查找元素:

	1、除了直接查找:$("JQ选择器");
	2、通过关系查找:至少要先找到一个人才可以使用关系:
		父:parent();
		子:children();
		前一个兄弟:prev();
		后一个兄弟:next();
		其他兄弟:siblings();
	JQ自带隐式迭代,不需要遍历,可以对集合直接做操作

(二)操作元素:

	1、内容:
		获取:$("xx").html/text/val();
		获取:$("xx").html/text/val("新内容");

	2、属性:
		获取:$("xx").attr("属性名");
		设置:$("xx").attr("属性名","属性值");

	3、样式:
		1、可以操作class1、添加class:$("xx").addClass("新class") - JS中没有此操作,只能替换
			2、删除class:$("xx").removeClass()
					如果不传参,删除所有的class名
					如果传入,删除对应的class3、切换class:$("xx").toggleClass("新class")
	
		2、直接操作css
			获取:$("xx").css("css属性名");
			设置:$("xx").css("css属性名","css属性值");
			一句话设置多个样式:
				$("xx").css({
					css属性名:"css属性值",
					...
				});
	

(三)JQ的遍历:

	$("一堆人").each((i,val)=>{

	})
	
		

(四)JQ上树&删除:

	上树:父亲.append(儿子)
	删除:$("xx").remove();

(五)JQ动画:

	1、显示 - $("xx").show();
	2、隐藏 - $("xx").hide();
	3、切换 - $("xx").toggle();
		如果不传参数,是瞬间显示,瞬间隐藏
		可以传入实参:$("xx").api("动画名称",时长);
  • JQ不可以用以前DOM的语法,DOM也不可以用JQ的语法,但是两者其实可以互换

    • JQ->DOM:$("xx")[下标];
    • DOM->JQ:$(DOM)
  • jQuery的组成部分:

    • 1、jquery.js
    • 2、jQueryUI.js
    • 3、jQuery-Mobile.js - 但是现在三阶段有uniapp
    • 4、QUnit - 测试用来测试JavaScript代码的一个工具

三十、后端框架

    Node.js的第三方框架:express,需要使用npm去下载它,express中有两个核心概念
0、下载:在你的项目路径下打开cmd:npm i express

1、引入后发现express是一个函数,创建服务器应用,还要设置监听端口!
	var express=require("express");
	var app=express();
	app.listen(端口号);

2、路由:客户端发来的请求中的一部分,也称呼叫做相对路径,通过判断路由的不同响应不同的内容。
	
	1、app.get("路由",(req,res)=>{//req和res不是以前的req和res,用法会与原生Node有所不同
		1、req->依然是请求对象,保存着前端传来的请求消息:req.query.键名;
		2、res->依然是响应对象,可以为前端发数据,也可以为前端发页面:
			1、发数据:res.send("想要发的东西");
			2、发文件:res.sendFile("文件的路径");
	     })

	2、特殊:post请求要稍微麻烦一点点,尤其在于获取前端传到后端的请求消息,因为post是隐式提交,所以需要某些东西才能看得见他
	     app.post("路由",(req,res)=>{//req和res不是以前的req和res,用法会与原生Node有所不同
		1、req->依然是请求对象,保存着前端传来的请求消息:31、需要引入一个第三方模块(中间件的语法):var bp=require("body-parser")
			2、使用中间件的语法:app.use(bp.urlencoded({extended:false}))
			3、req.body.键名;

		2、res->依然是响应对象,可以为前端发数据,也可以为前端发页面:
			1、发数据:res.send("想要发的东西");
			2、发文件:res.sendFile("文件的路径");
	     })

	现在不管是form表单还是ajax,都可以自行选择使用get还是post了

	如果是全栈开发,一个人随便搞,但是如果是前后端分离开发,那么要沟通,路由是什么

3、中间件:express本身就是一个功能极简的框架,完全路由和中间件两部分构成
	中间件其实就是一个函数,但是它也可以访问req和res两个对象,处于路由之前 - 可以理解为是现实生活中的一个保安、保镖、秘书

	中间件的功能包括:
		可以执行任何代码
		可以修改请求和响应对象
		可以终止请求
		可以放行你到下一个中间件/路由 - 中间件可以写多个

	语法:
		app.use((req,res,resolve)=>{
			一切你想要执行的代码,中间件代码
			resolve();//放行的函数
		})

	固定套路:
		1、*获取post的请求消息,见上面 - app.use(bp.urlencoded({extended:false}))
		2、*内置中间件加载一切静态资源:app.use(express.static("静态资源的文件夹名"));

三十一、gulp

 自动化构建工具(打包工具):项目经理/小组长使用的 - 学习目的:体验流程
 作用:
   *1、复制文件
   *2、压缩(css/js/图片...)
   *3、降级ES6为ES5,降级语法 - 因为ES5之前语法其实都没有变化,ES5只是提供了一些新的API,目的:支持兼容老IE
    4、将scss/less编译为css - 不需要学习,现在的编辑器都自带此功能
    5、重命名 - 不推荐,html引入href、src的地方名字都要进行修改
  • *为什么打包:
    • 上线过后,不可能使用源代码(1、太大了 2、别的成员/外界也能看的懂)
    • 肯定使用的是处理过后的代码,目的:1、为了提升网站效率(文件更小) 2、安全性(加密)

  • *gulp固定操作安装:
 1、cmd必须先全局安装gulp(不安的话,cmd提示:gulp不是内部命令) - 必做(运行gulp必要方式),一次性安装永久可用
        npm i --global gulp
2、cmd再你的项目中局部安装 - 可以不做,直接复制代老湿的node_modules到你的项目之中
        npm i gulp
3、cmd在你的项目初始化gulp - 必做 
        npm init
       注意:名字可以自己写,但是不能有大写&中文,然后一路回车到底
4、配置完成,开始编写属于你自己的gulpfile.js文件!!!必须是这个名字

使用gulp:

 1、先引入var gulp=require("gulp");
  API1、布置任务:
   gulp.task("任务名",()=>{
	//任务要做什么操作
   })

   执行任务:
     cmd里面输入gulp 任务名; - gulp基于node,但是属于是一个独立的软件
     如果想不写任务名,默认执行default任务名的操作

2、*复制
   gulp.src("入口文件路径"); -- 选中某个、某些源文件
   gulp.pipe(); -- 管道 -- 输送/插件操作
   gulp.dest("出口路径"); -- 输送到哪里去?

三十二、SVN工具(1-):集中式版本管理控制工具

  • 作用:项目管理
    • 集中式:服务器只有一台电脑,所有人可以把自己完成的工作,传送到服务器上,任何人(客户端)都可以访问
    • 缺点:如果服务器坏了就完了
    • 优点:没有放在云端,安全性一定是极高的,如果泄露了一定是内鬼,如果项目真的是需要很安全的,你的电脑应该也会装上监控软件

如何使用:

	1、项目经理:
		1、安装svn服务器端:VisualSVN-Server-4.3.2-x64.msi
		2、为此项目组的每个开发者创建出账号密码
		3、创建项目仓库
		4、把仓库地址和你的账号私发给你
		5、承受压力、核算项目周期、核算项目成本、监督项目进度、陪伴加班...

	2、开发人员
		1、安装svn客户端:TortoiseSVN-1.14.1.29085-x64-svn-1.14.1.msi - 记得重启一下电脑(不重启可能看不到小图标)
		2、对着任意位置右键:svn checkout - 检出/拉取仓库,填上仓库地址
		3、在文件夹(仓库)里面做开发
		4、每天下班前提交到服务器:在项目文件夹里面,写代码的位置,右键svn commit,填入日志,在提交
		5、每天上班前更新一下:右键svn update

  GIT工具(9+):三阶段学习 - 分布式版本管理控制工具

三十三、websocket - HTML5提供的了一个新特性

(一)HTML5新特性10个:

	一、语义化标签
	二、新增Input表单的类型、和属性
	三、audiovideo音频和视频
	四、Canvas绘图
	五、SVG绘图 - 因为程序员大部分都不会画画,就算学会了,画出来也很丑,而现在有框架echart.js,可以帮助你实现画图功能(数据可视化 - 折线图、柱状图、饼状图...)
	六、地理定位
	七、拖拽API
	八、WebStorage - sessionStorage和localStorage
	九、WebWorker - 没用
	十、WebSocket

(二)websocket的概念

http协议 属于请求-响应模型,只有客户端发起请求,服务器端才能响应消息,没有请求就没有响应,
一个请求,只能得到一个响应,有些场景中,此模型就不太行了:比如:实施走势图、在线聊天室等等...
解决:
        1、ajax+定时器 - 请求过于复杂了,服务器的压力太大,而且不够频繁(心跳请求、长轮询)
        2、websocket协议:简称ws协议:属于广播-收听模型,客户端连接到服务器端就不会再断开了,永久连接的,
                         双方可以随意的向对方发送消息,且是不对等的发送,WS协议专门用于完成实施走势图、在线聊天室等等...

(三)如何使用ws:

1、基于Node.js的第三方模块包,下载引入: var ws=require("ws");

2、分为三方面:

    1、依然使用node.js搭建http服务器和文件系统 - 可以用express简化

    2、搭建ws服务器
            //搭建ws服务器并且设置了监听端口号
            var server=new ws.Server({port:8008});	
            //绑定了连接事件,是不自己断开的,可向客户端发送消息,或者,接收消息
            server.on("connection",socket=>{
                    console.log("11111---有人来连接上了");
                    //后端->前端
                    socket.send("消息")
                    //前端->后端
                    socket.on("message",data=>{
                            data->前端说的话,只不过是一个buffer类型
                    })
            })

    3、搭建ws客户端
            //连接到ws服务器端
            var socket=new WebSocket("ws:127.0.0.1:8008");
            //前端想要接收消息
            socket.onmessage=e=>{
                    e.data;
            }
            //前端说话:
            socket.send("消息");

三十四、各大版本更新

(一)ES5:

1、保护对象:

16大特性
    Object.defineProperties(obj,{
        "属性名":{
                value:,
                writable:true/false,
                enumerable:true/false,
                configurable:true,false
                get:()=>{
                        拦截操作
                },
                set:()=>{
                        拦截操作
                }
        }
    })

    23个级别
       防扩展:Object.preventExtensions(obj);
        密封:Object.seal(obj);
        冻结:Object.freeze(obj);

(2)数组新增的六个API:

判断:arr.every/some((v,i,arr)=>判断条件)
遍历:arr.forEach((v,i,arr)=>操作)                    var newArr=arr.map((v,i,arr)=>操作)
过滤和汇总
        var subArr=arr.filter((v,i,arr)=>判断条件)
        var sum=arr.reduce((prev,v,i,arr)=>prev+v);

(3)call、apply-借用

    语法:
    Array.prototype.slice.call(借用的人,实参1,....)
    Array.prototype.slice.apply(借用的人,arr)	

 bind-买
    语法:
    var 新的slice=Array.prototype.slice.bind(指定的人,永久实参1)

(4)严格模式:"use strict"


(二)ES6:超级大版本:

1、模板字符串:${name}

2、let 变量名=值;

3、箭头函数

4、for(var v of arr){ v - 值 }

5、解构赋值 new Vue({}) - 很多框架底层都用到了解构赋值

6、Set和Map [...new Set(arr)] - 数组去重变回数组

7、class关键字 - 简化面向对象的三大特点:封装、继承、多态

class plane extends flyer{//extends有两个作用:1、继承自有属性全部都不用再写,只需要写一次super(),2、自动继承到共有方法
    constructor(name,speed,rl){//放在constructor里面的都是自有属性
            super(name,speed);
            this.rl=rl;
    }
    fly(){//flyer提供的fly方法不好用,我自己封装了一个,覆盖他的 - 多态
                return `${this.name}正在以时速${this.speed}飞行,可以容纳${this.rl}人`;
        }
}

8、Promise - 让异步有顺序的执行,但是还是异步

new  Promise(ajax1).then(ajax2).then(ajax3);

一定要放行,且前一个return Promise才可以连.then操作

9、模块化开发 - 目的:1、分工合作 2、新的引入方式
语法

1、分支模块要公开自己的成员
        export var obj={
                ...
        }

2、主模块要引入:
        import {obj} from "./文件路径"

3HTML在引入主模块的时候要注意设置类型:
        <script src="主模块路径" type="module"></script>

(三)ES7:

1、ArrayAPI:includes

ES7之前,如果我们想要判断一个数组中是否包含某个元素,需要通过 indexOf 获取结果,并且判断是否为-1ES7之后,我们可以通过includes来判断数组中是否包含一个指定元素,得到结果直接就是一个布尔值
	var arr=[1,2,3,4,5];
	//原来
	console.log(arr.indexOf(6)!=-1);
	//现在
	console.log(arr.includes(3))
	console.log(arr.includes(6))

2、指数运算符:

	在ES7之前,如果我们想要计算数字的乘方,必须通过 Math.pow(底数,幂);
	在ES7之后,增加了 ** 运算符 ,可以对数字进行乘方操作
	Math.pow(2,3) -> 8
	2**3	         -> 8

(四)ES8:

1、Object.values

作用:可以将一个对象转为数组
之前我们可以通过 Object.keys 获取一个对象所有的key
可以针对对象操作:
    var obj={
            name:"袍哥",
            age:18,
            hobby:"学习"
    }
    console.log(Object.keys(obj));//["name","age","hobby"];

// 在ES8中提供了 Object.values 获取一个对象所有的value
        console.log(Object.values(obj));//["袍哥",18,"学习"]

2、Object.entries

作用:将对象、数组、字符串 变为 二维数组
通过 Object.entries 可以获取到一个数组,数组中会存放可枚举属性的键值对数组
        console.log(Object.entries(obj));//[["name","袍哥"],["age",18],["hobby","学习"]]

也可以针对数组、字符串进行操作,数组和字符串会将下标作为key

*3、StringPadding

    某些字符传我们需要对其进行前后的填充,来实现某种格式化操作,ES8之中就给字符串添加padStart和padEnd方法,分别填充前面和后面
    //日期格式化,为个位数,前面添加了一个0
    var h="8";
    var m="3";
    var s="50";
    console.log(`${h.padStart(2,"0")}:${m.padStart(2,"0")}:${s.padStart(2,"0")}`)

4、尾部逗号的添加,不会报错了

5、async 和 await *****

async作为一个关键字放到函数前面,用于表示函数是一个异步函数,异步函数也就意味着该函数不会阻塞后续代码
        async function f1(){
                return "我是f1函数";
        }
        f1().then(rs=>{
                console.log(rs);
                console.log("得到结果要干什么就在这里操作")
        });
        console.log("后续代码");
意味着任何函数都可以变为异步

await是等待的意思,那么他等待的是什么呢,他后面又该跟着什么呢?其实它后面可以放任何表达式,不过我们更多的是放一个返回Promise对象的表达式
注意:await 关键字只能放在async函数里面
        async function f1(){
                return 1;
        }
        async function f2(){
                return 2;
        }
        async function f3(){
                return await f1() + await f2();
        }
        f3().then(rs=>{
                console.log(rs);
        });
        console.log("后续代码");

(五)ES9:

*扩展运算符:...
,ES9过后不光数组,对象也可以使用了

//脱掉数组的衣服
var arr=[32,1,54,76,98,7,23,54,24,764];
console.log(Math.max.apply(Math,arr));
console.log(Math.max(...arr));

//脱掉对象的衣服
var obj1={a:1,b:2,c:3}
var obj2={...obj1,d:4}
console.log(obj2);

//c穿上了对象的衣服
function f1({a,...c}){
        console.log(a);
        console.log(c);
}
f1({a:1,b:2,c:3})

(六)ES10:

1、flat方法会按照一个可指定的深度遍历递归你的数组,并将所有的元素与遍历到的子数组中的元素合并为一个新数组

    var arr=[1,[2,[3,[4,[5,6,7,8,9]]]]]
    console.log(arr.flat(4));//[1,2,3,4,5,6,7,8,9]

2、flatMap:两个方法二合一flat和map,先执行map在执行flat,但是flat只能脱1层

    var arr=["hello world","你好 中国","hello h52301"];
	var newArr=arr.flatMap(v=>v.split(" "));
	console.log(newArr);//["hello","world","你好","中国","hello","h52301"];

3、trimStart/trimEnd


(七)ES11:

全局对象全新写法:

  • 在浏览器中可以通过window访问全局对象
  • 在Node.js中可以通过global来访问对象
  • 在ES11中对全局对象添加了一个新的名字,统一了规范:globalThis

for...in循环标准化
在ES11之前,虽然很多浏览器支持for...in来遍历对象,但是并没有被ECMA标准化


(八)ES12:

逻辑赋值运算符

	function f1(a){
		a||="默认值";
			
		console.log(a);
	}
	f1();//a=默认值

	var obj={
		name:"袍哥"
	}	
	obj&&=obj.name;
	console.log(obj);//袍哥

(九)ES13:

字符串、数组API:at();
可以通过at方法获取字符串、数组的元素
var arr=[1,2,3,4,5,6];
console.log(arr.at(0));
console.log(arr.at(2));
console.log(arr.at(-1));
console.log(arr[arr.length-1])

var str="hello world";
console.log(str[str.length-3])
console.log(str.at(-3))