关于前端:Vue性能提升之Objectfreeze


在 Vue 的文档中介绍数据绑定和响应时,特意标注了对于通过 Object.freeze() 办法的对象无奈进行更新响应。因而,特意去查了 Object.freeze() 办法的具体含意。

含意

Object.freeze() 办法用于解冻对象,禁止对于该对象的属性进行批改(因为数组实质也是对象,因而该办法能够对数组应用)。在 Mozilla MDN 中是如下介绍的:

能够解冻一个对象。一个被解冻的对象再也不能被批改;解冻了一个对象则不能向这个对象增加新的属性,不能删除已有属性,不能批改该对象已有属性的可枚举性、可配置性、可写性,以及不能批改已有属性的值。此外,解冻一个对象后该对象的原型也不能被批改

该办法的返回值是其参数自身。

须要留神的是以下两点

  1. Object.freeze() 和 const 变量申明不同,也不承当 const 的性能。

    const和Object.freeze()齐全不同

  • const的行为像 let。它们惟一的区别是, const定义了一个无奈重新分配的变量。 通过 const申明的变量是具备块级作用域的,而不是像 var申明的变量具备函数作用域。
  • Object.freeze()承受一个对象作为参数,并返回一个雷同的不可变的对象。这就意味着咱们不能增加,删除或更改对象的任何属性。
  • const和Object.freeze()并不同,const是避免变量重新分配,而Object.freeze()是使对象具备不可变性。

以下代码是正确的:

  1. Object.freeze() 是“浅解冻”,以下代码是失效的:

实例

惯例用法

显著看到,a 的 prop 属性未被扭转,即便从新赋值了。

延长

“深解冻”

要齐全解冻具备嵌套属性的对象,您能够编写本人的库或应用已有的库来解冻对象,如Deepfreeze或immutable-js

// 深解冻函数.
function deepFreeze(obj) {

  // 取回定义在obj上的属性名
  var propNames = Object.getOwnPropertyNames(obj);

  // 在解冻本身之前解冻属性
  propNames.forEach(function(name) {
    var prop = obj[name];

    // 如果prop是个对象,解冻它
    if (typeof prop == 'object' && prop !== null)
      deepFreeze(prop);
  });

  // 解冻本身(no-op if already frozen)
  return Object.freeze(obj);
}
复制代码

其实就是个简略的递归办法。然而波及到一个很重要,然而在写业务逻辑的时候很少用的知识点 Object.getOwnPropertyNames(obj) 。咱们都晓得在 JS 的 Object 中存在原型链属性,通过这个办法能够获取所有的非原型链属性。

利用Object.freeze()晋升性能

除了组件上的优化,咱们还能够对vue的依赖革新动手。初始化时,vue会对data做getter、setter革新,在古代浏览器里,这个过程实际上挺快的,但依然有优化空间。

Object.freeze() 能够解冻一个对象,解冻之后不能向这个对象增加新的属性,不能批改其已有属性的值,不能删除已有属性,以及不能批改该对象已有属性的可枚举性、可配置性、可写性。该办法返回被解冻的对象。

当你把一个一般的 JavaScript 对象传给 Vue 实例的  data  选项,Vue 将遍历此对象所有的属性,并应用  Object.defineProperty  把这些属性全副转为 getter/setter,这些 getter/setter 对用户来说是不可见的,然而在外部它们让 Vue 追踪依赖,在属性被拜访和批改时告诉变动。

但 Vue 在遇到像 Object.freeze() 这样被设置为不可配置之后的对象属性时,不会为对象加上 setter getter 等数据劫持的办法。参考 Vue 源码

Vue observer 源码

性能晋升成果比照

在基于 Vue 的一个 big table benchmark 里,能够看到在渲染一个一个 1000 x 10 的表格的时候,开启Object.freeze() 前后从新渲染的比照。

big table benchmark

开启优化之前

开启优化之后

在这个例子里,应用了 Object.freeze()比不应用快了 4 倍

为什么Object.freeze() 的性能会更好

不应用Object.freeze() 的CPU开销

应用 Object.freeze()的CPU开销

比照能够看出,应用了 Object.freeze() 之后,缩小了 observer 的开销。

Object.freeze()利用场景

因为 Object.freeze()会把对象解冻,所以比拟适宜展现类的场景,如果你的数据属性须要扭转,能够从新替换成一个新的 Object.freeze()的对象。

Javascript对象冻结

批改 React props React生成的对象是不能批改props的, 但实际中遇到须要批改props的状况. 如果间接批改, js代码将报错, 起因是props对象被解冻了, 能够用Object.isFrozen()来检测, 其后果是true. 阐明该对象的属性是只读的.

那么, 有办法将props对象冻结, 从而进行批改吗?

事实上, 在javascript中, 对象解冻后, 没有方法再冻结, 只能通过克隆一个具备雷同属性的新对象, 通过批改新对象的属性来达到目标.

能够这样:

ES6: Object.assign({}, frozenObject);
lodash: _.assign({}, frozenObject);
复制代码

来看理论代码:

function modifyProps(component) {
  let condictioin = this.props.condictioin,
    newComponent = Object.assign({}, component),
    newProps = Object.assign({}, component.props)
  
  if (condictioin) {
    if (condictioin.add) newProps.add = true
    if (condictioin.del) newProps.del = true
  }
  newComponent.props = newProps
  
  return newComponent
}
复制代码

锁定对象的办法

  • Object.preventExtensions()

no new properties or methods can be added to the project 对象不可扩大, 即不能够新增属性或办法, 但能够批改/删除

  • Object.seal()

same as prevent extension, plus prevents existing properties and methods from being deleted 在下面的根底上,对象属性不可删除, 但能够批改

  • Object.freeze()

same as seal, plus prevent existing properties and methods from being modified 在下面的根底上,对象所有属性只读, 不可批改

以上三个办法别离可用Object.isExtensible(), Object.isSealed(), Object.isFrozen()来检测

Object.freeze( ) 阻止Vue无奈实现 响应式零碎

当一个 Vue 实例被创立时,它向 Vue 的响应式零碎中退出了其 data 对象中能找到的所有的属性。当这些属性的值产生扭转时,视图将会产生“响应”,即匹配更新为新的值。然而如果应用 Object.freeze(),这会阻止批改现有的属性,也意味着响应零碎无奈再追踪变动。

具体应用方法举例:

<template>
  <div>
     <p>freeze后会扭转吗
        {{obj.foo}}
     </p>
      <!-- 两个都不能批改??为什么?第二个实践上应该是能够批改的-->
      <button @click="change">点我确认</button>
  </div>
</template>

<script>
var obj = {
  foo: '不会变'
}
Object.freeze(obj)
export default {
  name: 'index',
  data () {
    return {
      obj: obj
    }
  },
  methods: {
    change () {
      this.obj.foo = '扭转'
    }
  }
}
</script>
复制代码

运行后:

从报错能够看出只读属性foo不能进行批改,Object.freeze()解冻的是值,你依然能够将变量的援用替换掉,将上述代码更改为:

<button @click="change">点我确认</button>

change () {
      this.obj = {
        foo: '会扭转'
      }
    }
复制代码

Object.freeze()是ES5新增的个性,能够解冻一个对象,解冻指的是不能向这个对象增加新的属性,不能批改其已有属性的值,不能删除已有属性,以及不能批改该对象已有属性的可枚举性、可配置性、可写性。避免对象被批改。 如果你有一个微小的数组或Object,并且确信数据不会批改,应用Object.freeze()能够让性能大幅晋升。

实际心得和技巧

Object.freeze()是ES5新增的个性,能够解冻一个对象,避免对象被批改。

vue 1.0.18+对其提供了反对,对于data或vuex里应用freeze解冻了的对象,vue不会做getter和setter的转换。

如果你有一个微小的数组或Object,并且确信数据不会批改,应用Object.freeze()能够让性能大幅晋升。在我的理论开发中,这种晋升大概有5~10倍,倍数随着数据量递增。

并且,Object.freeze()解冻的是值,你依然能够将变量的援用替换掉。举个例子:

<p v-for="item in list">{{ item.value }}</p>
复制代码
new Vue({
    data: {
        // vue不会对list里的object做getter、setter绑定
        list: Object.freeze([
            { value: 1 },
            { value: 2 }
        ])
    },
    created () {
        // 界面不会有响应
        this.list[0].value = 100;

        // 上面两种做法,界面都会响应
        this.list = [
            { value: 100 },
            { value: 200 }
        ];
        this.list = Object.freeze([
            { value: 100 },
            { value: 200 }
        ]);
    }

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理