WEB前端第三十七课——jsBOM操作-DataParse、jsEngine、性能、history、道岔、closure

  • A+
所属分类:Web前端
摘要

1.数据解析  将不能被直接使用的数据,通过某种方法转变为可以直接使用的数据的过程,称为数据解析

1.数据解析

  将不能被直接使用的数据,通过某种方法转变为可以直接使用的数据的过程,称为数据解析

  最常见的数据解析就是将字符串数据解析为对象数据

  代码示例如下:

<html lang="en"> <head>     <meta charset="UTF-8">     <title>数据解析</title>     <style>         span{display: inline-block; width: 90px;}         .submit{             margin: 5px 50px;             padding: 2px 5px 2px 5px;             height: 30px;             width: 70px;             letter-spacing: 1px;             text-align: center;         }         input{height: 20px;margin: 3px 0px;}         button{width: 90px;height: 30px;letter-spacing: 3px;margin: 5px 40px;}     </style> </head> <body>     <form action="">         <span>Name:</span><input name="userName" type="text"/><br/>         <span>Age:</span><input name="age" type="text"><br/>         <span>Sex:</span><input name="sex" type="text"><br/>         <span>Nationality:</span><input name="nation" type="text"><br/>         <input type="submit" class="submit" value="Submit"> <!--    <input type="button" class="submit" value="Submit">-->  <!--不具有提交信息的功能!--> <!--    <button type="submit" class="submit" value="">Submit</button>-->  <!--有提交信息的功能!-->     </form>     <button>数据解析</button>     <script>         var btn=document.querySelector('button');         btn.onclick=function () {             var getStr=document.location.search; //获取当前网页地址中的查询信息             console.log(getStr);             var getArr=getStr.slice(1).split('&');  //将字符串截取后指定分隔符切片,返回值为数组             console.log(getArr);             var resObj={};             for (var i=0;i<getArr.length;i++){                 var getObj=getArr[i].split('=');  //将数组中的每一个元素,通过分隔符再次分别拆分成数组                 console.log(getObj);                 resObj[getObj[0]]=getObj[1];  //向对象中写入属性和属性值,即键值对             }             console.log(resObj);             var resObjKsArr=Object.keys(resObj);  //获取对象的全部属性,返回值为数组             console.log(resObjKsArr);             return resObj;         }     </script> </body> </html> 

  知识碎片:

    ① <input>标签的name属性作用:

      name属性规定<input>标签的名称

      用于在js中引用元素,或提交表单后引用表单数据

      只有设置了 name属性的表单元素,才能在提交表单时传递元素的Value值

    ② <input type='submit'>与<button>的区别

      <input type='submit'>与<button type="submit">具有相同作用

      <button>应用场景更多,可实现更多复杂的功能和效果

      <input type='submit'>通常作为表单提交按钮的习惯性用法

    ③ 获取当前HTML的URL内提交信息

    ④ 字符串、数组、对象之间转换

      split,根据指定的符号将字符串进行分割,分割后的所有子字符串整合成为一个数组返回

      join,将数组转换为字符串,默认用逗号隔开

      点号和中括号运算符都可以用于为对象属性赋值,当属性不存在时添加属性,当属性存在时修改属性

2.JavaScript引擎

  JavaScript引擎由两部分构成:渲染引擎、js解释器

  渲染引擎作用:

    ① 解析代码:将HTML代码解析为DOM树

    ② 对象合成:CSS和DOM合成一颗渲染树

    ③ 布局:计算出渲染树的布局

    ④ 绘制:将渲染树绘制到屏幕

    注意,上述四个步骤不一定严格按照顺序执行

  JavaScript解释器:

    能够将 js代码解释成可以在网页中实现的工具

3.页面加载优化

  ① defer延迟

    defer属性规定应该等待所有HTML文档加载完成后,再判断 js脚本是否执行

    避免因外部文件过大或者网络卡顿造成的文件阻塞

    defer属性仅适用于外部脚本

    书写格式:<script src="test_script .js"  defer></script>

  ② async异步

    <script>标签中的 js脚本默认是在DOM加载过程中同步执行的,通过 async属性可以改变脚本的执行方式

    设置 async属性后,DOM加载与 js脚本加载异步执行,即同时进行

    async优点:避免了因DOM文件过大导致的“文件加载阻塞”

    async缺点:无法确定 js脚本到底何时执行(完成),且async属性仅对外部 js脚本生效

    书写格式:<script src="test_script .js"  async ></script>

  两种方式的应用:

    如果 async=“async”,外部js脚本相对于页面其余部分异步执行

    如果不使用 async且 defer=“defer”,外部 js脚本将在页面完成解析时执行

    如果 async与 defer都不使用,则在浏览器解析页面之前,立即读取并执行外部 js脚本

    通常在优化页面加载时 async使用较多,但如果外部js脚本不影响文档内容,可以使用 defer以便加快处理文档的速度

  note:defer与 async都是一个布尔属性,因此,“元素节点 .defer || async”的返回值为 true || false

4.浏览器性能优化

  ① reflow(回流),当页面中的部分或者全部元素改变宽度和高度、位置发生变化、删除或者增加元素、某个(些)元素隐藏或显示时,这时页面的重新加载称为回流

  ② repaint(重绘),当页面中的可见性发生变化时,我们说页面发生了重绘,比如背景颜色、文字颜色等

  ③ 回流必将引起重绘,重绘不一定引起回流

  由此可知,重绘的代价是高昂的,因为浏览器必须验证DOM树上其他节点元素的可见性

       回流更是浏览器性能的关键,因为其变化涉及到部分页面甚至整个页面的布局,一个元素的回流会导致其所有子元素以及DOM中紧随其后的祖先元素的回流

  如果减少重绘和回流,提高浏览器性能?

    ① 不要一项一项的去改变样式,尽可能一次性写完,中间不被打断

    ② 读写 DOM尽量放在一起

    ③ 使用文档碎片,var temp=document.createDocumentfFragment();

      创建文档碎片充当临时容器,减少 js和HTML之间的交互,示例如下:

      temp .appendChild( creatNewElem1 );

      temp .appendChild( creatNewElem2 );

      temp .appendChild( creatNewElem3 );

      document .body .apependChild( temp );

    ④ 使用 fixed或 absolute可以减少回流和重绘

    ⑤ 把发生重绘的代码推迟到下一次重绘发生时一起执行

      window.requestAnimationFrame( function(){

        for( var i=0; i<div.length; i++){

          div[i].style.backgroundColor='red';

        }

      };);

5.window.history对象

  表示整个浏览器的页面栈对象

  (栈为水杯容器,后进先出;堆为管道容器,先进先出)

  对象中提供了一些属性和方法帮助更好地控制整个浏览器中页面的访问

  ① window .history .back(); 跳转到栈中的上一个页面

  ② window .history .forward(); 跳转到栈中的下一个页面

  ③ window .history .go(num); 跳转到栈中的指定页面(当前页num=0)

  ④ window .history .length;栈中页面的数量

  note:通过window .history对象中提供方法进行页面跳转并不会向栈中添加新的页面

     而通过 window.location.href或者 <a>标签进行的跳转,则会向栈中添加新的页面

     在指定位置添加页面(内容)时,会将该位置之后的页面(内容)退栈

6.函数的“道岔”

  语法:函数 .call(函数的调用者,函数参数1,函数参数2,...);

     函数 .apply(函数的调用者,[函数参数1,函数参数2,...]);

  函数的调用者是 call和 apply的第一个参数,而后的参数是执行函数需要的参数

    call和 apply都是window提供的,能够改变函数的实际调用者,也就是函数中 this的指向

    call和 apply的第一个参数必须写(可以为 null/none),而其余参数可以不写

    call() 方法传参数时,用逗号分隔每个参数;而apply() 方法传参数时,采用数组的形式传递

7.闭包

  很多时候,需要在函数外读取函数内部的局部变量,但正常情况下在 js中是不允许的,

  而通过闭包方式将函数内部的局部变量传递到函数外部

  所谓闭包就是在函数内部再封装一个读取局部变量的函数,并将这个内部函数作为返回值供外部调用

  闭包的主要用途:

    ① 通过闭包,在函数外部读取函数内局部变量的值

    ② 让局部变量始终生存在内存当中,避免被垃圾回收机制杀死

  闭包的注意事项:

    ① 由于闭包会使函数中的变量被保存在内存中,内存消耗过大,所以不能滥用,否则会造成网页的性能问题,在IE中可能导致内存泄漏

      解决方法:在结束函数之前,将不使用的局部变量全部删除

    ② 闭包会在父函数外部改变父函数内部变量的值,一定不要随意改变父函数内部变量的值

      如果把父函数当做对象(Object),那么闭包就好比是对象的公用方法(Public Method),而内部变量就是对象的私有属性(PrivateValue)

    ③ 由于闭包的实际调用者都是 window,因此所有闭包中的 this均指向了 window

      如果一定要在函数中通过 this调用函数中的变量,可以使用 call或 apply变更闭包中 this的指向

8.this用法小结

  ① this在正常函数中,谁调用的函数,this指向谁

  ② this在闭包中,闭包中的this指向 window

  ③ 间隔调用和延迟调用,setInterval和 setTimeout中的 this指向 window

  ④ 事件中的 this

    HTML中,this指向 window

    DOM0中,指向绑定该事件的元素

    DOM2中,IE环境 this指向window,非IE环境 this指向绑定该事件的元素

  ⑤ 自执行函数,this指向 window,自执行函数语法:( function(){ 函数体 }() );

  ⑥ call()和 apply()方法,this指向方法中的第一个参数