zoukankan      html  css  js  c++  java
  • 一、开发过程中遇到的js知识点总结(1)

     1.Object.freeze()

      方法用于冻结一个对象,即将对象设置为不可扩展、将对象的所有自有的属性和方法(包括Symbol值的属性和方法)配置为不可配置,不可写。

      Object.freeze(obj)

      返回值是已冻结的对象。

      这个操作不会影响从原型对象继承来的属性和方法,即只影响自有的属性和方法,一旦对象被冻结,其自身的所有属性都不可能以任何方式被修改。

    2.深度选择器 >>> 与 /deep/

    .fuck >>> .weui-cells {
        // ...
    }

    有些想sass、less、scss之类的预处理器无法正确解析可以使用 /deep/ 取而代之,/deep/是 >>> 的别名

    vue组件中,在style设置为scoped的时候,里面在写样式对子组件是不生效的,如果想让某些样式对子组件都生效,可以使用/deep/深度选择器

    .wrap{
      /deep/ .class{
        font-size: 12px;// 对所有子组件生效  
        /deep/ .class2{};// 没有必要写多层deep,父类有deep,子类自动也会深度选择,在firfox里会失效  
      }  
    }

    3.在循环中使用break、continue和return语句之间的区别

      break:此语句将退出循环执行循环后面的语句。如果break语句包含在嵌套循环里,它只跳出最里面的循环。

      continue:程序运行到此语句时,不再执行循环体中continue后面的语句,而是跳到下一个循环入口执行下一个循环

      return:表示被调函数返回到主调函数继续执行,返回时可附带一个返回值,由return后面的参数指定。return之后,函数就结束了,后面的语句不再执行

    4.JS中数组函数的总结

      push():像数组的末尾添加一个或多个元素,并返回新的长度

      pop():删除数组的最后一个元素,数组的长度减1,并且返回删除元素的值(当数组为空的时候,不改变数组,并返回undefined)

      unshift():向数组的头部添加一个或多个元素,返回新的长度

      shift():删除并返回数组的第一个元素

      reverse():倒叙

      sort():对数组元素进行排序(默认按照ASCLL),可以传递一个函数,自定义排序规则

      concat():连接两个或多个数组

      split(): 把字符串转换成数组

      join():把所有的元素放进一个字符串,通过指定的分隔符进行分割

      splice(index, howmany, item1, ..., itemX):可以做 删除/插入/替换 操作(替换就是先删除再添加,响应式的)

        index 必需,规定添加删除项目的位置,使用负数可从数组结尾处规定位置

        howmany 必需,要删除的项目数量,如果设置为 0,则不会删除项目

        item, ..., itemX 可选,像数组添加的新的元素

      substr(start, length)

      substring(start, end)

      slice(start, end):截取。从某个已有的数组返回选定的元素,不包含 end 元素(没有 end 参数,就到数组的结尾)

      indexOf(x, start):返回某个指定字符串再字符串中首次出现的位置

        x 必需,规定检索的字符串

        start 可选,规定在字符串中开始检索的位置,合法值是 0 至 arr.length - 1,如果省略该值,则从字符串的首字符开始检索

      lastIndexOf(x, fromindex):指定字符串值,最后出现的位置,在一个字符串中的指定位置从后向前搜索

        x 必需,规定检索的字符串

        fromindex 可选,规定字符串开始检索的位置,合法值 0 至 arr.length -1 ,若省略,则将从字符串最后一个字符处开始检索

      toString():转换为字符串

      valueOf():返回数组的原始值,返回数组本身

      includes(x, start):判断字符串或数组中是否包含指定的字符串,返回Boolean

        x 必需,要查找的数据

        start 可选,设置从那个位置开始查找,默认0

      find(function(currentValue, index, arr), thisValue):返回通过判断的数组的第一个元素的值,不会对空数组执行

        currentValue 必需,当前元素

        index 可选,当前元素的索引值

        arr 可选,当前数组对象

       thisValue 可选,传递给函数的值一般用 this 值

      instanceof:检测是否是数组

        arr instanceof Array;// 返回Boolean

      Array.isArray(obj):判断obj是否是数组,返回Boolean

     JS中数组高阶函数的理解 some()、every()、fiflter()、map()、forEach()、reduce()

      some((item, index, arr)=>{}):返回一个Boolean,判断是否有元素符合func中的条件

          item 必选,index 可选,索引值。arr 当前数组,可选

          不会对空数组进行检测,不会改变原始数组

        const arr = [1,2,3,4,5];
        arr.some(item=>item>2);// 返回true

      every((item,index,arr)=>{}):返回一个Boolean,判断每个元素是否符合func中的条件

           item必选,index 可选,索引值。arr当前数组,可选

          不会对空数组进行检测,不会改变原始数组

        const arr = [2,3,4,5,6];
        arr.every(item=>item>2);// 返回false

      filter((item,index,arr)=>{}):返回一个符合func条件的元素数组(es6)

           item必选,index 可选,索引值。arr当前数组,可选

          filter() 不会对空数组进行检测。不会改变原始数组

        let arr = [2,3,4,5];
        arr.filter(item=>item>2);// 返回 [3,4,5]

      map((item, index, arr)=>{}):返回一个新的array,数组元素由每一次调用函数产生结果组成

          item必选,index 可选,索引值。arr当前数组,可选

          map() 不会对空数组进行检测,不会改变原始数组

        const arr = [1,2,3,4,5];
        arr.map(item=>item*2);// 返回 [2,4,6,8,10]

      forEach((item, index, arr)=>{}):调用数组的每个元素,并将元素传递给回调函数(没有返回值,将数组遍历)

          item 参数是必须的,当前元素。index 可选,当前索引值。arr 可选,当前元素所属的数组对象

          forEach() 对于空数组是不会执行回调函数的

        const a = [1, 22, 333]
        a.forEach((item, index, arr)=>{
          console.log(item);// 1 22 333
          console.log(index);// 0 1 2
          console.log(arr);// arr 为遍历的数组
        })    

      reduce():接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值

        可以作为一个高阶函数,用于函数的 compose ,对于空数组是不会执行回调函数的

        let arr = [{count: 1, price: 2},{count: 3, price: 3}, {count: 2, price: 2}];
        arr.reduce(function(total, currentValue, index, arr){}, initialValue)// initialValue 可选,传递给函数的初始值
        // 参数 total 必需,初始值,或者计算结束后的返回值。currentValue必需,当前元素。index 可选,索引。arr 可选,数组对象
        let sum = arr.reduce(function(total, item){
          return total + item.count * item.price;
        },0)// 最终返回15 

    5.jquery获取radio, checkbox, checked 的值的时候不能使用attr

      要使用prop进行获取和设置值

      获取选中的属性

        $("#id").prop('checked');
    
        $("#id").get(0).checked
    
        document.getElementById("#id").checked
    
        $("#id").is(":checked")

      设置选中

        $("#id").prop('checked', true);
    
        $("#id").get(0).checked = true;
    
        document.getElementById("#id").checked = true;

    6.多个异步请求成功后在执行后续方法

      1--jquery 中 $.when() 方法

      $.when($.ajax(), $.ajax()).done(function(a1, a2){
        // a1是第一个异步返回的数据,a2是第二个异步返回的数据
      }).file(function(){
        alert('file')
      })
    // 以上代码是先执行两个操作$.ajax,如果都成功了,就运行done(),如果有一个或都失败了就执行fail()

      $.when(deferreds)

        Deferred 类型 一个或多个延迟对象,或者普通的js对象

       2--使用promise中的all()方法实现

      Promise.all([
          new Promise(resolve => {
            setTimeout(() => {
              resolve('100')
            }, 1000)
          }),
          new Promise(resolve => {
            setTimeout(() => {
              resolve('200')
            }, 1000)
          })
        ]).then(data => {
          console.log('5555')
        })

       2、如果是三个请求 p1、p2、 p3 都返回成功再执行 fn

        

    // 失败就直接失败,不写代码了
    let n =0
    p1.then(res=>{
        n++
        if (n == 3) fn
    })
    
    p2.then(res=>{
        n++
        if (n == 3) fn
    })
    
    p3.then(res=>{
        n++
        if (n == 3) fn
    })

    7.word-wrap: break-word;

      允许长单词换行到下一行

    8.数组引用的时候,直接改变数据会影响原数据的值

       let a = [1,2,3,4,5];
    
      let b = a;
    
      b[2] = 22;// 此时a数组也是[1,2,22,4,5]
    
      要想不改变原始数据的值,
    
      let c = JSON.parse(JSON.stringify(a))
    
      c[2] = 2222;// 此时改变的只是c中的值    

    9.js浅拷贝与深拷贝的区别和实现

      区别:假设 B 复制了 A ,当修改 A 时,看 B 是否会发生改变,如果 B 变了,说明是浅拷贝,若 B 没有改变,那就是深拷贝

      1.如果是基本数据类型,名字和值都会储存在栈内存中

        let a = 1;
        let b = a;// 栈内存会开辟一个新的内存空间,此时 a 和 b 都是相互独立的
        b=2;//此时a还是1

      以上算不上深拷贝,因为深拷贝本身只针对比较复杂的 object 类型数据

      2.如果是引用类型,名字存在栈内存中,值存在堆的内存中,但是栈内存会提供一个引用的地址指向堆内存中的值

        let a  = [1,2,3]
        let b = a;// 此时进行拷贝,其实复制的是 a 的引用地址,而并非堆里面的值
        a[1] = 222;// 在修改数组时,由于 a 与 b 指向的时同一个地址,所以 b 也跟着相应的改变,这就是浅拷贝

      3.实现浅拷贝的方法

        1.for...in 只循环第一层

        // 只复制第一层的浅拷贝
        function simpleCopy(obj1) {
          var obj2 = Array.isArray(obj1) ? [] : {};
          for (let i in obj1) {
            obj2[i] = obj1[i];
          }
          return obj2;
        }
        var obj1 = {
          a: 1,
          b: 2,
          c: {
            d: 3
          }
        }
        var obj2 = simpleCopy(obj1);
        obj2.a = 3;
        obj2.c.d = 4;
        alert(obj1.a); // 1
        alert(obj2.a); // 3
        alert(obj1.c.d); // 4
        alert(obj2.c.d); // 4

        2.Object.assign方法

        var obj = {
            a: 1,
            b: 2
        }
        var obj1 = Object.assign(obj);
        obj1.a = 3;
        console.log(obj.a) // 3

        3.使用等于号 =

        let a = [0, 1, 2, 3, 4];
        let b
    = a;     console.log(a === b);     a[0] = 1;     console.log(a, b);

      4.实现深拷贝的方法

        1.使用递归去拷贝所有层级的属性

        let a = [1, 2, 3, 4, 5];
        let b = deepClone(a);
        function deepClone(obj){
          let objClone = Array.isArray(obj) ? [] : {};
          if (obj && typeof obj === "object") {
            for(key in obj) {
              // 判断对象是否包含特定的自身属性,返回Boolean
              if(obj.hasOwnProperty(key)) {
                // 判断 obj 子元素是否为对象,如果是,递归复制
                if(obj[key] && typeof obj[key] === 'object') {
                  objClone[key] = deepClone(obe[key])
                } else {
                  objClone[key] = obj[key]
                }
              }
            }
          }
          return objClone;    
        }

        2.通过 JSON 对象来实现深拷贝

          // 缺点:无法实现对对象中方法的拷贝,会显示为 undefined
          let a = [1,2,3,4,5];
          let b = JSON.parse(JSON.stringify(a));

        3.通过 jQuery 的 extend 方法实现深拷贝

          let arr = [1,2,3,4];
          let bbb = $.extend(true, [], array);// true 为深拷贝,false为浅拷贝

        4.可以通过 lodash 函数库实现深拷贝

          let res = _.clone(arr);

        5.Reflect方法

          // 代理法
          function deepClone(obj) {
            if(!isObject(obj)){// 判断是否为对象
              throw new Error('obj 不是一个对象')
            }
            let isArray = Array.isArray(obj);
            let cloneObj = isArray ? [...obj] : {...obj};
            Reflect.ownKeys(cloneObj).forEach(key => {
              cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
            })
            return cloneObj;
          }

        6.手动实现深拷贝

          let obj = {a: 1, b: 2};
          let obj2 = {a: obj.a, b: obj.b};

        7. 如果对象的 value 时基本类型的话,也可以用 Object.assign 来实现深拷贝,但是要把它赋值给一个空对象

          var obj = {a: 1, b: 2}
          var obj1 = Object.assign({}, obj);// obj赋值给一个空{}

        8.使用 slice 实现对数组的深拷贝

          // 但数组里面的值是基本数据类型,比如 String,Number,Boolean 时,属于深拷贝
          // 当数组里面的值时引用数据类型比如 Object, Array时,属于浅拷贝
          let a = [1,2,3];
          let b = a.slice(0);

        9.用 concat 实现对数组的深拷贝

        // 当数组里面的值是基本数据类型,比如String, Number, Boolean时,属于深拷贝
        let a = [1,2,3];
        let b = a.concat();
        // 当数组里面的值是引用数据类型,比如Object,Array时,属于浅拷贝
        let a = [{a: 1},{b: 2}];
        let b = a.concat;

        10.使用 let newObj = Object.create(oldObj) 可以达到深拷贝的效果

          function deepClone(initalObj, finalObj){
            var obj = finalObj || {};
            for(var i in initalObj) {
              var prop = initalObj[i];// 难免相互引用对象导致死循环,比如initalObj.a = initalObj
              if(prop === obj) {
                continue;
              }
              if (typeof prop === 'object') {
                obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
              } else {
                obj[i] = prop;
              }
            }
            return obj;
          }

        11.使用扩展运算符实现深拷贝

          // 当value是基本数据类型,比如String,Number,Boolean时,是可以使用拓展运算符进行深拷贝的
          // 当value是引用类型的值,比如Object,Array,引用类型进行深拷贝也只是拷贝了引用地址,所以属于浅拷贝
          var car = {sf: "james", pf: "davis", cf: "cf"}
          var car1 = { ...car, pf: "kobe" }
          console.log(car1); // { sf: "james", pf: "davis", cf: "cf" }
          console.log(car); // { sf: "james", pf: "kobe", cf: "cf" }

    10.用on给动态添加的元素绑定hover事件,不会生效

      在jQuery中,hover() 函数本身是对 mouseenter && mouseleave 的封装,然而在原生 event 中,并没有 hover 这一事件,所以在传递参数 hover 时,并不会有任何的效果。

      如果我想绑定类似 hover 的效果,可以绑定两个事件 mouseenter && mouseleave + function ,样式就用类名来 toggle, 也可以在map里面,一个事件对应一个function

      $('ul.course').on('mouseenter mouseleave', 'li', function(){
        $(this).toggleclass('borderClass');// 鼠标移入移出改变 class
      })

    11.JSON.stringify() 和 JSON.parse()

      JSON.stringify({'a': '1', 'b': '2'});
      // '{'a': '1', 'b': '2'}'  从一个对象中解析出字符串
      JSON.parse('{'a': '1', 'b': '2'}');   // Object{a:'1', 'b': '2'}  从一个字符串中解析出JSON对象

    12.for...in 与 for...of 的区别

       对于数组的遍历,for...in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for...of 只返回数组的下标对应的属性值

      for...of 循环的原理其实也是利用了遍历对象内部的 iterator 接口,将 for...of 循环分解成最原始的 for 循环,内部实现的机制可以这么理解

      // 1.for...of 遍历获取的是对象的键值,for...in 获取的是对象的键名
      let arr = ['one', 'two', 'three'];
      for(let i in arr){
        console.log(i);// 分别输出 0 1 2
      }
      for(let i of arr){
        console.log(i);// 分别输出 one two three
      }
    
      // 2.对于普通对象,没有部署原生的 iterator 接口,直接使用 for...of 会报错
      let obj ={name: 'zhangning187', age: '24'}
      for(let key of obj) {
        console.log(key);// obj is not iterable
      }
    
      // 可以使用 for...in 循环遍历键名
      for(let key in obj) {
        console.log(key);// name age
      }
      // 也可以使用 Object.keys(obj) 方法将对象的键名生成一个数组,然后遍历这个数组
      for(let key of Object.keys(obj)) {
        console.log(key);// name age
      }
    
      // 3.for...in 循环不仅遍历数字键名,还会遍历手动添加的其他键,甚至包括原型链上的键。for...of则不会这样
      let array = [1, 2, 3];
      arr.name = 'zhangning187';// 手动添加的键
      Array.prototype.age = '23';// 原型链上的键
      for(let i in arr) {
        console.log(i);// 1 2 3 name age
      }
      
      // 4.forEach 循环无法中途跳出,break 命令或 return 命令都不能奏效
      let arr1 = [1, 2, 3, 4]
      arr.forEach(i=>{
        if(i == 2) return;// 它会像 continue 一样,跳过当前循环继续执行下一次循环
        console.log(i);// 1 3 4
      })
      for...of 循环可以与 breakcontinuereturn 配合使用,跳出循环
    
      // 5.无论是 for...in 还是 for...of 都不能遍历出 Symbol 类型的值,遍历 Symbol 类型的值需要用Object.getOwnPropertySymbols()方法
      let a = Symbol('a')
      let b = Symbol('b')
      let obj = {
        [a]: 'zhang',
        [b]: 'ning',
        c: '23',
        d: 'web'
      }
      for(let key in obj) {
        console.log(key);// c d
      }
      let objSymbols = Object.getOwnPropertySymbols(obj)
      console.log(objSymbols);// [Symbol(a), Symbol(b)]
      objSymbols.forEach(i=>{
        console.log(obj[i]);// zhang ning
      })
      
    // Reflect.ownKeys 方法可以返回所有类型的键名,包括常规键名和 Symbol 键名   let keyArr = Reflect.ownKeys(obj)   console.log(keyArr);// ["c", "d", Symbol(a), Symbol(b)]

      for...in 循环主要是为了遍历对象,不适用于遍历数组

      for...of 适用于遍历数组、类数组对象、字符串、Set、Map、Generator 等拥有迭代器对象的集合。但是不能便利对象,因为没有迭代器对象.

        与 forEach() 不同的是,它可以正确相应 break、continue、return 语句

       for...of 循环的步骤:首先调用集合的 Sysmbol.iterator 方法,接着返回一个新的迭代器对象。迭代器对象可以是任意具有 .next() 方法的对象;

          for-of 循环将重复调用这个方法,每次循环调用一次。

    13.vue过滤器中的this值

       过滤器中的this值为undefined

     14.$nextTick()

       在下次DOM更新循环结束之后执行延迟回调,在修改数据之后立即使用这个方法,获取更新后的DOM

      在 created() 钩子函数进行的DOM操作,一定要放在this.$nextTick() 回调函数中,原因是在 create() 钩子函数执行的时候 DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以放在nextTice()回调函数中。与之对应的就是 mounted() 钩子函数,该钩子函数执行的时候,所有的 DOM 挂载已完成。

    15.改变 this 指向的方法的异同点

      call

      function f1(a, b){
          console.log(this)
          console.log(a, b);
        }
        var obj = {name: '张宁'};
        f1.call(obj, 1, 2);// f1中的this,指向就是obj,后面的参数就是f1的形参

      apply

      function f1(a, b){
          console.log(this)
          console.log(a, b);
        }
        var obj = {name: '张宁'};
        f1.apply(obj, [2,333]);// f1中的this,指向就是obj,和call不同的就是,apply的形参放在一个数组中

      bind

    function f1(a, b){
          console.log(this)
          console.log(a, b);
        }
    
        var obj = {name: '张宁'};
        let f2 = f1.bind(obj);// 不会立即调用调用f1()函数,二十会产生一个修改了this指向的新的函数,即f2中的this指向obj
        f2(2,333)

    16.单页面应用

      1.内容不需要重新加载整个页面,没有页面之间额切换,体验感较好,不会出现 白屏现象,

      2.单页面应用对服务器的压力小,

      3.良好的前后端分离,开发更愉快

      缺点

      首屏加载慢,要加载全部的js

      不利于SEO

      前进后退功能较难管理

    17. extend、assign、merge 的相同之处与区别  

      相同: 都可以用来合并对象,

          都会修改原来的对象(如果原生的对象是作为函数的第一个参数的话)

      不同: assign:函数不会处理原型链上的属性,也不会合并相同的属性,而是用后面的属性值覆盖前面的属性值

          extend:和 assign 的唯一区别就是,它会合并原型链上的属性

          merge:遇到相同属性名的时候,如果属性值是纯对象或集合的时候,会合并属性值

    19.  

      什么是 BFC

        BFC 是一块独立的布局环境,,保护其中内部元素不受外部影响,也不影响外部。

      如何触发 BFC?

        float 的值不是 none、position 的值不是 static 或 relative 、display 的值是 inline-block 或 flex 或 table-caption 或 inline-flex 、overflow 的值不是 visible

      BFC 的用途

        解决父子的外边距折叠问题(因为 BFC 模型只作用于本身的内部元素,,就是父子关系),,给父元素加入上述的 css 属性即可(无法解决父元素兄弟之间的外边距折叠问题)

        实现了块级元素独占一行的特性,并且规定了浮动元素不被静态文档流元素影响。(这是为什么块级元素独占一行的原因)

        清除浮动影响,BFC 在计算高度时,会一同计算浮动元素的高度,所以也可以清除浮动带来的影响

    20.防抖节流

      主要是针对响应跟不上触发频率这类问题的两种解决方案。在DOM绑定事件时,有些事件我们是无法控制触发频率的。如鼠标移动事件。滚动条滚动事件,窗口大小改变事件,瞬间的操作都会导致这些事件会被高频触发。如果事件的回调函数较为复杂就会导致响应跟不上触发,出现页面卡顿,假死现象。

      debounce 防抖:当事件触发时,设定一个定时器,延迟代码执行。若在这期间又一次触发了这个事件,则删除之前定时器,重新设置定时器,直到周期结束,执行代码。这是 debounce 防抖的基本思想。

      throttle 节流:在固定周期内,只执行一次动作,若有新事件触发,不执行。周期结束之后,又有新事件触发,再开始新的周期。

        节流相当于技能冷却,防抖相当于前摇

        应用:

          1.搜索的时候,用户不断输入值时,用防抖来节约请求资源

      debounce() {
          this.timeout = null;
          clearTimeout(this.timeout);
          this.timeout = setTimeout(() => {
            // 执行代码
            console.log('防抖成功');
          }, 500)
        },

          2.频繁操作点赞和取消点赞,因此需要获取最后一次操作并发送给服务器

          3.鼠标不断点击触发,mousedown(单位i时间内触发一次)

          4.window 触发 resize 的时候,不断调整浏览器窗口大小会不断触发这个事件,用防抖让其只触发一次

      throttle() {
          let canRun = true; // 通过闭包保存一个标记
          return function () {
            if (!canRun) return; // 在函数开头判断标记是否为 true,不为 true 则 return
            canRun = false; // 立即设置为 false
            setTimeout(() => { // 将外部传入的函数的执行放在 setTimeout 中
              fn.apply(this, arguments);
              // 最后在 setTimeout 执行完毕后再把标记设置为 true(关键) 表示可以执行下一次循环了。当定时器没有执行的时候标记永远是 false,在开头被 return 掉
              canRun = true;
            }, 500);
          };
        }

       

    21.回流重绘

      浏览器的渲染过程:

        1.解析HTML,生成DOM树,解析CSS,生成CSSOM树

        2.DOM树与CSSOM树结合,生成渲染树(Render Tree)

        3.(Layout)回流:根据渲染树,进行回流,得到节点的几何信息(位置,大小)

        4.(Painting)重绘:根据渲染树和回流得到的几何信息,得到节点的具体像素。

        5.将像素信息发给GPU,展示在页面上

      回流

        渲染树构造完成后还需要计算它们在设备窗口的具体位置和大小,这就是回流(重排)

      重绘

        通过构造渲染树和回流过程,我们知道什么节点是可见,以及它们的规则和相应的几何信息。这个时候需要重绘,来得到节点的具体像素值。

      何时会发生回流重绘

        当页面布局发生或节点几何信息发生改变,即需要重新计算节点的位置和几何信息,便需要进行回流(重排)

          添加或删除可见的DOM元素

          元素的位置发生变化

          元素的尺寸发生变化

          内容发生变化

          页面一开始渲染的时候

          浏览器的窗口尺寸发生变化(因为回流是根据视口的大小来计算元素的位置和大小的)

        回流必会触发重绘,重绘不一定会回流

      如何减少回流重绘

        尽量较少回流重绘的次数

        对于复杂的动画效果,用绝对定位让其脱离文档流

        CSS3硬件加速(GPU加速)

        使用 transform opacity filters 等属性会触发CSS3硬件加速,让动画不会产生回流重绘

          缺点如果使用太多元素硬件加速,会导致内存占用较大,会有性能问题。

    22.闭包

      指有权访问另一个函数作用域中的变量的函数

    var x = 1;
    function foo(y = function() { x = 2;}) {
      var x = 3;
      y();
      console.log(x); // 3
    }
    console.log(x); //2 虽然内部函数被调用,但是他还是沿定义时作用域链向上找变量,所以没有x参数,他就找到了全局变量的x,
    // 这个例子就是与 foo 函数是作用域平行的最好证明

      优点:

        1.能够读取函数内部的变量。让这些变量一致存在于内存中,不会在调用结束后,被垃圾回收机制回收

        2.用闭包解决递归调用问题

    function  factorial(num) {
       if(num<= 1) {
           return 1;
       } else {
          return num * factorial(num-1)
       }
    }
    var anotherFactorial = factorial
    factorial = null
    anotherFactorial(4)   
    // 报错 ,因为最好是return num* arguments.callee(num-1),
    // arguments.callee指向当前执行函数,但是在严格模式下不能使用该属性也会报错,所以借助闭包来实现
    // 使用闭包实现递归 function newFactorial = (function f(num){ if(num<1) {return 1} else { return num* f(num-1) } }) //这样就没有问题了,实际上起作用的是闭包函数f,而不是外面的函数newFactorial

        3.用闭包模仿块级作用域

          在 let 没有出来之前,用 var 定义变量存在变量提升问题

    for(var i=0; i<10; i++){
        console.info(i)
    }
    alert(i)  // 变量提升,弹出10
    //为了避免i的提升可以这样做
    (function () {
        for(var i=0; i<10; i++){
             console.info(i)
        }
    })()
    alert(i)   
    // underfined 因为i随着闭包函数的退出,执行环境销毁,变量回收

      缺点:

        1.由于闭包会使函数中的变量保存在内存中,内存消耗很大,所以不能滥用闭包。

          解决办法是,退出函数之前,将不适用的局部变量删除。

        2.this指向问题。

    var object = {
         name: ''object",
         getName: function() {
            return function() {
                 console.info(this.name)
            }
        }
    }
    object.getName()()    // underfined
    // 因为里面的闭包函数是在window作用域下执行的,也就是说,this指向windows

        3.内存泄漏(只在ie中),

  • 相关阅读:
    MySQL 有关权限的表都有哪几个?
    MyISAM 表格将在哪里存储,并且还提供其存储格式?
    你是怎么看Spring框架的?
    elasticsearch 的倒排索引是什么 ?
    主键和候选键有什么区别?
    MySQL 支持事务吗?
    可以使用多少列创建索引?
    LIKE 声明中的%和_是什么意思?
    什么是通用 SQL 函数?
    MySQL 中有哪些不同的表格?
  • 原文地址:https://www.cnblogs.com/zhangning187/p/kfzsdzjjsmstdd.html
Copyright © 2011-2022 走看看