每日思考(2020/01/17)

Posted ericzlin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日思考(2020/01/17)相关的知识,希望对你有一定的参考价值。

题目概览

  • Standards模式和Quirks模式有什么区别
  • 浏览器是怎样判断元素是否和某个CSS选择器匹配?
  • 造成内存泄漏的操作有哪些

题目解答

Standards模式和Quirks模式有什么区别

  • 定义:quirks模式是浏览器的怪异模式,该模式下浏览器对页面的渲染会比较怪异。平时使用的都是standards模式,又称strict模式
  • QUIRKS来历:在W3C标准出台以前, 浏览器在对页面的渲染上没有统一规范,产生了差异 (Quirks mode或者称为Compatibility Mode);由于W3C标准的推出, 浏览器渲染页面有了统一的标准(CSScompat或称为Strict mode也有叫做Standars mode), 这就是二者最简单的区别。W3C标准推出以后,浏览器都开始采纳新标准, 在标准出来以前,很多页面都是根据旧的渲染方法编写的,如果使用新的标准来渲染,将导致页面显示异常。使以前的页面能够正常浏览,浏览器都保留了旧的渲染方法 这样浏览器渲染上就产生了Quircks mode和Standars mode, 两种渲染方法共存在一个浏览器上
  • 如何开启浏览器的QUIRKS模式:关键在于html文件第一行的声明,!doctype html如果我们把这一行删除掉,或者在这一行随意加上几个字母, 使浏览器无法识别,那么就开启了浏览器的quirks模式
  • 判断哪种模式:js中使用document.compatMode,如果输出结果为backCompat,则开启了quirks模式,如果输出结果为css1compat,则开启的是standards模式
  • 区别:
    • 盒模型的宽高包含内补丁和边框:在W3C标准中,如果设置一个元素的宽度和高度,指的是元素内容的宽度和高度,而在Quirks模式下,IE的宽度和高度还包含了padding和border。IE5.5及以下的浏览器即使在Standards模式下,也会有这个问题
    • 可以设置行内元素的高宽:在Standards模式下,给span等行内元素设置wdith和height都不会生效,而在quirks模式下,则会生效
    • 可设置百分比的高度:在standards模式下,一个元素的高度是由其包含的内容来决定的,如果父元素没有设置百分比的高度,子元素设置一个百分比的高度是无效的
    • 用margin:0 auto设置水平居中:使用margin:0 auto在standards模式下可以使元素水平居中,但在quirks模式下却会失效,quirk模式下的解决办法,用text-align属性:body{text-align:center};#{content:text-align:left}
    • Quirks模式下设置图片的padding会失效,Table中的字体属性不能继承上层的设置,white-space: pre会失效,许多CSS默认样式将不同

浏览器是怎样判断元素是否和某个CSS选择器匹配?

  • 浏览器先产生一个元素集合,这个集合往往由最后一个部分的索引产生(如果没有索引就是所有元素的集合)。然后向上匹配,如果不符合上一个部分,就把元素从集合中删除,直到真个选择器都匹配完,还在集合中的元素就匹配这个选择器了
  • 比如选择器:div.ready #wrapper > .bg-red先把所有元素 class 中有 bg-red 的元素拿出来组成一个集合,然后上一层,对每一个集合中的元素,如果元素的 parent id 不为 #wrapper 则把元素从集合中删去。 再向上,从这个元素的父元素开始向上找,没有找到一个 tagName 为 div 且 class 中有 ready 的元素,就把原来的元素从集合中删去。至此这个选择器匹配结束,所有还在集合中的元素满足。大体就是这样,不过浏览器还会有一些奇怪的优化。
  • 为什么从后往前匹配因为效率和文档流的解析方向。效率不必说,找父元素和之前的兄弟比遍历所有子元素快而且方便。关于文档流的解析方向,是因为现在的CSS,一个元素只要确定了这个元素在文档流之前出现过的所有元素,就能确定他的匹配情况;应用在即使 html 没有载入完成,浏览器也能根据已经载入的这一部分信息完全确定出现过的元素的属性。基于CSS Rule 数量远远小于元素数量的假设和索引的运用,遍历每一条 CSS Rule 通过集合筛选,比遍历每一个元素再遍历每一条 Rule 匹配要快得多。

造成内存泄漏的操作有哪些

  • JS的回收机制:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收系统(GC)会按照固定的时间间隔,周期性的执行。垃圾收集器必须跟踪到底哪个变量没用,对于不再有用的变量打上标记,以备将来收回其内存。用于标记的无用变量的策略可能因实现而有所区别,通常情况下有两种实现方式:“标记清除”和“引用计数”。引用计数不太常用,标记清除较为常用

  • 标记清除:这是javascript中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”。垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间

    function test(){
      var a=10;//被标记,进入环境
      var b=20;//被标记,进入环境
    }
    test();//执行完毕之后a、b又被标记离开环境,被回收
  • 引用计数:另一种不太常见的垃圾回收策略是引用计数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存

    function test(){
      var a={};//a的引用次数为0
      var b=a;//a的引用次数加1,为1
      var c=a;//a的引用次数加1,为2
      var b={};//a的引用次数减1,为1
    }
  • 哪些操作会造成内存泄露

    • 意外的全局变量引起的内存泄露,一个未声明变量的引用会在全局对象中创建一个新的变量。在浏览器的环下,全局对象就是 window

      function foo(arg) {
          bar = "aaaaa";
      }
      
      // 实际上等价于
      function foo(arg) {
          window.bar = "aaaaa";
      }
      
      // 类似的
      function foo() {
          this.variable = "qqqqq";
      }
      //this 指向全局对象(window)
      foo();
    • 闭包引起的内存泄露

      function fn1(){
          var n=1;
          function fn2(){//在加一个fn2当他的子集
              alert(n);
          }
          return fn2(); 
      //return出来后 他就给 window了所以一直存在内存中。因为一直在内存中,在IE里容易造成内存泄漏
      }
      fn1();
    • dom清空或删除时,事件未清除导致的内存泄漏

      var elements={
          button: document.getElementById("button"),
          image: document.getElementById("image"),
          text: document.getElementById("text")
      };
      function doStuff(){
          image.src="http://some.url/image";
          button.click():
          console.log(text.innerHTML)
      }
      function removeButton(){
        document.body.removeChild(document.getElementById('button'))
      }
    • 循环引用

      function leakMemory() {
          var el = document.getElementById('el');
          var o = { 'el': el };
          el.o = o;
      }
    • 定时器setTimeout和setInterval:当不需要setInterval或者setTimeout时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏

      clearTimeout(***)
      clearInterval(***)
    • 死循环

      while(1){
          a++;
      }
    • 给DOM对象添加的属性是一个对象的引用

      var testObject = {};
      document.getElementById('idname').property = testObject;  //如果DOM不被消除,则testObject会一直存在,造成内存泄漏

以上是关于每日思考(2020/01/17)的主要内容,如果未能解决你的问题,请参考以下文章

一个类型思考了 8 年,依旧是最好的! | 每日趣闻

每日思考(2019/12/9)

每日思考(2019/12/29)

源哥每日一题第十五弹 poj 1190 关于深搜减枝以及对于阅读代码的思考

markdown 每日片段

每日思考记录(11)