javascript第四周-ES5&ES6&DOM

ES5提供了新的API,ES6简化了一些语法,学习完整的DOM操作--意味着会遇到很多渲染页面的案例,会比较难

一、ES5:

1、保护对象:保护对象的成员(属性和方法)

     (保护对象对于我们程序员并没有多大用处,不用)

      如何保护:

       1、运用属性的四大特性:

          Object.defineProperties(obj,{
              "属性名":{
                     value:实际保存值,
                     writable: true/false,//开关:控制着这个属性名是否可以被修改
                     enumerable: true/false,//开关:控制着这个属性名是否可以被for in循环遍历到
                     configurable: true/false,//开关:控制着这个属性名是否可以被删除 - 这一句是总开关,一旦设置为false,其他特性不允许在修改,一旦设置为false不可逆
              }
          })

       2、用三个级别:

              1、防扩展:禁止给对象添加新属性

                     Object.preventExtensions(obj);

              2、密封:禁止给对象添加新属性和删除属性

                     Object.seal(obj);

              3、冻结:禁止给对象添加和删除和修改

                     Object.freeze(obj);

2、*****数组的新的API:3组6个

       1、判断:判断结果一定是一个布尔值

         every:每一个 - 要求每一个元素都要满足,结果才为true,只要有一个不满足就为false - 类似于&&

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

        some:有一些 - 要求每一个元素都不满足,结果才为false,只要有一个满足就为true - 类似于||

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

       2、遍历:将数组中的每个元素取出来执行相同或相似的操作:

              forEach:遍历数组,直接修改原数组

arr.forEach(function(val,i,arr){
            直接做操作
 })

              map:遍历数组,不修改原数组返回一个新数组

var newArr=arr.map(function(val,i,arr){
           return 操作的结果
  })

       3、过滤和汇总:

              过滤:筛选出自己想要的,但是不会修改原数组

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

              汇总:把数组中的每个元素汇总到一起

var sum=arr.reduce(function(prev,val,i,arr){
                   return prev+val;
      },基础值);//基础值会和最后的结果加在一起

         以上6个API的底层都是for循环,目的 - 简化for循环 - 以后能不写for就不写for  

3、Object.create():根据父对象创建子对象,继承已经设置好了

var 子对象=Object.create(父对象,{
 "自有属性名":{四大特性},
               ...
          });

4、面试时:严格模式:很严格

          开启:在你的任何作用域的顶部加上一句话:"use strict";

          功能:1、禁止给未声明的变量赋值 - 解决全局污染

                2、静默失败升级为报错

5、*****call/apply/bind:不是自己的方法也可以使用 - 笔试面试也很容易碰到

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

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

          函数名.apply(借用的对象,arr); - 只能传入一个实参是一个数组,apply其实会悄悄的将数组打散

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

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

              3件事:

   1、创建了一个和原函数完全相同功能的新函数
   2、将新函数中的this永久绑定为了指定对象,别人都借不走了
   3、将新函数中的部分参数永久固定   
         用法:var 新函数=原函数.bind(指定对象,永久实参,...) - 不是立刻执行的,需要自己调用

         强调:bind绑定的新函数没有办法被call/apply借走

          固定套路:

              1、Math.max/min.apply(Math,arr);

              2、Object.prototype.toString.call/apply(arr);

              3、***类数组转为普通数组:类数组名称=Array.prototype.slice.call/apply(类数组);

ES5没有什么简化,是提供了一些API  

二、ES6:简化ECMAScript - 语法较大的变化

1、*模板字符串:

可以在字符串中放入变量 - 不需要再做字符串拼接,在字符串中实现了一个简单的js的环境

`我的名字叫${name}`

2、*块级作用域:尽量以后【优先】使用let创建变量

 let 变量名=值;

        作用:1、禁止声明提前

              2、添加了块级作用域,一个{}就是一个块

              3、记录着当前触发事件的元素的下标

3、***箭头函数:简化回调函数:

        公式:去掉function,()和{}之间添加=>,形参如果只有一个,则省略掉(),函数体如果只有一句话,省略{}, 函数体只有一句话并且是return,return和{}都省略

        特殊:千万不要将事件也简化为箭头函数 - 暂时

4、for...of循环:不用

        for(var v of 数组名){
              v;//value当前值
        }

        缺点:1、不能修改原数组,只能返回新数组

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

5、 *****解构赋值:

       顾名思义:解析结构后进行赋值 - 赋值的新方式,并且得到了增强

       如果赋值符号,左右两边的结构一样,就会悄悄的解开/脱掉结构再一一进行赋值

       语法:

1、像数组一样的解构赋值
              var [a,b,c]=[1,2,3];
              
2、像对象一样的解构赋值
              var {a,b=默认值,c}={c:值,a:值,b:值}; - 没有传值时,使用默认值
              
3、调用函数时,传递实参的顺序无所谓了
                     function zwjs({name,age,hobby}){
                            return `${name}今年${age}岁喜欢${hobby}`
                     }
                     console.log(zwjs({age:128,hobby:"打太极",name:"张三丰"}));
                     
 4、函数的返回的结果,可以有多个
                     function f1(){
                            var a=1;
                            var b=2;
                            return [a,b];
                     }
                     var [rs1,rs2]=f1();
                     console.log(rs1);
                     console.log(rs2);
         之前和以后可能会碰到很多API都带有个解构赋值的操作:xx.API({})

6、Set和Map类型:

  *Set:非常的类似于数组,保存/读取数据,作用:去重数组

         1、创建:var s=new Set(arr);
         2、别的API我们一个都不学,比数组差远了
         3、将set转回数组:var arr=[...s]

Map:非常的类似于对象,保存/读取数据,没有任何卵用,还不如对象

         1、创建:var m=new Map();
         2、不要记忆任何API,需要的时候,console.log输出看看原型有些什么方法

7、*****class关键字:简化面向对象(封装、继承、多态)开发 - react框架

       老版面向对象:封装、继承不方便,多态还有可能出现覆盖的情况

 class old类{
              constructor(name,age,hobby){//自有
                     this.name=name;
                     this.age=age;
                     this.hobby=hobby;
              }//共有
              函数名(){
              }
       }

 class new类 extends old类{
              constructor(name,age,hobby,salary){//自有
                     super(name,age,hobby);//自动调用你继承的old类的constructor方法
                     this.salary=this.salary;
              }//共有
       }
       extends关键字会继承到old类的constructor和函数

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

      1、分支模块要公开

 export var xxx={}

       2、主模块要引入

import {xxx} from "./js路径"

   特殊: 1.理论来说xxx要和公开的xxx名字保持一致

                2.但是也可以修改别名{xxx as 名字},一旦改了别名就不可以再用xxx

       3、在HTML引入时:

 <script src="主模块.js" type="module"></script>

9、*****Promise对象:承诺了ajax - 三阶段有一些API里自带了此功能

       问题:ajax异步操作,没有办法保证只执行的顺序

       解决:Promise

                    function ajax1(resolve){
                            $.post("02.php","hide=1",(data)=>{
                                   document.write(`<h1>${data}</h1>`);
                                   resolve();
                            })
                     }
                    

                     function ajax2(){
                           return new Promise((resolve)=>{
                                      $.post("02.php","hide=2",(data)=>{
                                              document.write(`<h1>${data}</h1>`)
                                              resolve();
                                        })
                            })
                     }

                    
                     function ajax3(){
                            return new Promise((resolve)=>{
                                 $.post("02.php","hide=3",(data)=>{
                                          document.write(`<h1>${data}</h1>`);
                                          resolve();
                                   })
                            })                           
                     }                    
                     new Promise(ajax1).then(ajax2).then(ajax3);

三、DOM

1、什么是DOM:Document Object Model(文档对象模型)

         将每一个标签/元素/属性/文本/注释,看做了一个DOM节点/元素/对象(提供了一些操作元素的属性/方法)

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

          1、HTML - 网页

          2、XHTML - 更严格的网页

          3、DHTML - 动态的网页:D:Dynamic:其实并不是新技术、新概念,是将现有技术的整合的统称,使我们的网页在离线状态依然具有动态效果

                             DHTML:HTML+CSS+JS(dom);

          4、XML - 数据格式

     DOM:原本是可以操作一切结构化文档的 HTML 和 XML,后来为了方便各类开发者分为3个部分

       1、核心DOM:【无敌】,既可以操作HTML又可以操作XML

                  缺点:API比较繁琐

       2、HTML DOM:只能操作HTML,API简单,缺点:比如属性部分,只能访问/设置标准属性,不能操作自定义属性  

       3、XML DOM:只能操作XML,XML基本已经被淘汰了 - 现在最流行的数据格式JSON                     

       开发建议:优先使用HTML DOM,HTML DOM满足不了在用核心DOM补充

2、DOM树:

树根:document - 不需要我们创建,一个页面只有一个document对象,由浏览器的JS解释器自动生成

          可以通过树根找到每一个DOM元素/节点/对象,提供了很多很多的API

3、每个DOM元素都有三大属性:

       1、xx.nodeType:描述节点的类型

              document节点:9

              element节点:1

              attribute节点:2

              text节点:3

              以前有用,判断xx是不是一个页面元素 - 因为以前我们找元素的方法和大家现在不一样

        2、xx.nodeValue:属性节点的值,说白了获取属性值

              以前有用,获取一个属性节点的值

        3、***xx.nodeName:节点的名称 - 判断xx是什么标签

              注意:返回是一个全大写的标签名

4、DOM--找元素

总结:现在【找元素】的方式:

       1、直接找元素:getXXX、querySelectorXXX

       2、通过关系

       3、层级不明确才用递归  

1.*通过 关系 获取元素

       父:xx.parentNode

       子:xx.children - 集合,只能找到子级儿子,不能找后代

       第一个儿子:xx.firstElementChild

       最后一个儿子:xx.lastElementChild

       前一个兄弟:xx.previousElementSibling

       后一个兄弟:xx.nextElementSibling

2.*****递归:层级不明确

简单来说就是函数中,又一次调用了函数自己,迟早有一天会停下来

       何时使用:遍历DOM树,专门用于【遍历层级不明确】的情况,既可以遍历层级不明确的DOM,也可以遍历层级不明确的数据

       如何使用递归:2步

 function 函数名(root){
             1、第一层你要做什么操作直接做
             2、判断他有没有下一级,如果由下一级再次调用此函数,只不过传入的实参是他的下一次
              }

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

       缺点:同时开启大量的函数调用,浪费的内存,只有一个情况采用:【遍历层级不明确】

3.遍历层级不明确的API:TreeWalker:一个在DOM树上行走的人

       缺陷:专门为遍历层级不明确的DOM准备

       如何:

 1、创建tw:
         var tw=document.createTreeWalker(根元素,NodeFilter.SHOW_ELEMENT);

 2、反复调用nextNode方法找到每一个元素
                     while((node=tw.nextNode())!=null){
                            node要做什么操作;
                     }

4.*API直接查找元素:

   1、通过HTML的一些特点去找元素

       1、id:var elem=document.getElementById("id"); - 找到了是单个元素,没找到null

       2、tagname/class/name:var elems=document.getElementsByTagName/ClassName/Name("标签名/class名");  - 找到了是集合,没找到空集合

       建议:表单控件元素尽量可以不用写class,因为必写name

   2、通过css选择器去获取元素:

       1、单个元素:var elem=document.querySelector("任意css选择器");

              强调:万一选择器匹配到多个,只会返回第一个

         2、多个元素:var elems=document.querySelectorAll("任意css选择器");

              强调:找到了返回集合,没找到返回空集合

              更适合做复杂查找  

       面试题:getXXX 和 querySelectoXXX 有什么区别?

              返回结果不同:

                     1、getXXX,获取到返回的是一个动态集合HTMLCollection

                     2、querySelectoXXX,获取到返回的是一个静态集合NodeList

                     动态集合 vs 静态集合

             1、动态集合:根据DOM树的改变,是动态集合也一起改变,每一次修改DOM树,都会悄悄的再次查找DOM

            缺点:每次都会悄悄重新查找,效率较低,不能使用forEach

           2、静态集合:每一次修改DOM树,静态集合不会发生变化,只会认准你找的时候的第一次找到的结果

            优点:每次不会悄悄重新查找,效率较高,可以使用forEach

5、DOM--操作元素:

<elem 属性名="属性值" style="样式名:样式值">内容

强调:页面上获取和设置的一切数据类型都是字符串

1、元素的内容:

       *1、elem.innerHTML:获取或设置开始标签到结束标签之间的HTML代码,没有兼容性问题,可以识别标签

              获取:elem.innerHTML

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

       2、elem.textContent:获取或设置开始标签到结束标签之间的纯文本,具有兼容性问题,不能识别标签

              获取:elem.textContent

              设置:elem.textContent="新内容"

              *老IE:elem.innerText;//第一次碰到小三上位,原本是只有老IE才可以使用的,但是随着各个浏览器的发展,IE没有将就大家,反而是其他主流浏览器去将就了老IE  

       *3、input.value:获取或设置单标签(能写内容的单标签)的内容的

              获取:input.value;

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

2、元素的属性:

       *1、获取属性值:

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

              HTML DOM:elem.属性名;  

       *2、设置属性值

              核心DOM:elem.setAttribute("属性名","属性值");

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

       *3、删除属性:

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

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

          4、判断属性:垃圾,只能判断有没有,不能判断具体是什么

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

              真的想要判断,更推荐:

                     if(elem.getAttribute("class")=="d1"){

                            使用获取的方式能判断出具体是什么class

                     }

       强调:HTML DOM确实简单,但是需要注意:

              1、class写为className

              2、只能操作标准属性,不能操作自定义属性

              3、删除的时候,删不干净,有的属性删不干净依然具有功能,比如href没有属性值默认为刷新、disabled就算没有属性值依然是禁用操作...,跟推荐删除的时候使用核心DOM

3、元素的样式:

       1、内联样式:优先级最高,一定会覆盖其他的样式

              仅仅当前元素可用,不会牵一发动全身

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

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

              唯一的缺点:获取样式时,也只能获取内联样式  

       2、样式表:

                     //1、获取你想要操作的样式表

                     var sheet=document.styleSheets[1];

                     //2、获取这个样式表中所有的样式规则

                     var rules=sheet.cssRules;

                     //3、数出你想要操作的那个样式规则

                     var rule=rules[30];

                     //4、操作:获取和设置

                     console.log(rule.style.background);

                     rule.style.background="purple"

4、创建元素和渲染DOM数据:3步

       1、创建空标签:

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

       2、为这个空标签添加必要的东西(属性或事件)

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

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

       3、将在内存中创建的元素渲染到DOM树上

              *父元素.appendChild(elem);//将elem追加到父元素里面当了最后一个儿子

              父元素.insertBefore(elem,已有子元素);//将elem追加到父元素里面当了儿子,会插在已有子元素的前面 - 导致所有元素的下标都会改变

              父元素.replaceChild(elem,已有子元素);//将elem追加到父元素里面当了儿子,会替换掉已有子元素

5、删除元素:elem.remove();

  核心DOM已经全部完毕了:增、删、改、查(DOM结构:元素、文本、属性、样式)

6、HTML DOM常用对象:【简化】核心DOM

       1、image对象:仅仅只是简化了创建语句

              创建:var img=new Image();//完全等效于var img=document.createElement("img");

              注意:不是人人都有构造函数创建方式

       2、form对象:简化了查找元素

              查找form元素:var form=document.forms

              查找form元素中的表单控件:var input=form.elements

              专属事件:form.onsubmit=function(){//提交事件,只会在提交的一瞬间触发:防止用户输入错误也能提交

                            return false;//阻止条件

                       }

       3、*select对象:

              属性:1、*select.options;//得到select下面所有的option,完全等效于xx.children

                    2、*select.selectedIndex;//获取到当前选中项的下标 - 只要是做联动就必然会用到

              方法:1、*select.add(option);//完全等效于appendChild                     2、select.remove(i);//删除掉下标i的option

              专属事件:select.onchange=function(){//只有选中项发生变化的时候才会触发}

       4、*option对象:仅仅只是简化了创建语句

              *创建:var opt=new Option("innerHTML","value");

       建议:HTML DOM别的无所谓,关键select和option:如果你想要一句话将option创建出来放入到select中:                      select.add(new Option("内容","值"))

扩展:

1、浏览器提供了3个弹出框

   1、用户输入框:var user=prompt("提示文字","默认值");

   2、警告框:alert("警告文字");

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

2、百度/高德地图:

      固定步骤:

                     1、打开百度:搜索 - 百度地图开放平台,点击进去lbsyun.baidu.com/

                     2、注册/登录百度账号

                     3、拉到最下面,注册为开发者

                     4、应用管理->我的应用->创建应用

                     5、名字随意,选择浏览器端,白名单写为*,获取到了密钥:WP10kgGrxWG2KEsbL3atLd5vdw74Nrwz

                     6、鼠标放到导航栏上,开发文档->javascript API->示例DEMO

                     7、选择你喜欢的地图,然后修改经纬度

                     8、如果你同时看上了多个地图,可以混搭,但是千万记住(webgl版和普通版不能混搭其他都可以)

                     9、作用:为了你的网站看上去更美观、更专业、