这是我参与8月更文挑战的第3天,活动详情查看: 8月更文挑战
前言
今天在跟小伙伴过一个中奖名单h5活动Code Review时突然想起了一道面试题:在vue2.x中Object.defineProperty()的劣势都有哪些?,其中有一条答案就是object.defineProperty()会对data中所有的属性进行劫持增加get和set方法,即使这些属性不会触发视图响应。
而Object.freeze()可以冻结一个对象,对象冻结后就可以阻止对其数据劫持,减少数据的响应提升一部分性能。
Object.freeze()
Object.freeze() 方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。
-
Object.freeze()冻结的是值,直接对对象重新赋值修改其引用还是会改变; -
如果被冻结对象的value值还是引用类型,则无法冻结,需要冻结其value值,下面例子中对
obj和obj.name冻结,修改obj.age下面的属性依旧生效,但是对被冻结的obj.name下的属性修改已经不生效了。
var obj = {
name: {
firstName: "三",
lastName: "张"
},
age: {
nowAge: 16
}
};
Object.freeze(obj);
Object.freeze(obj.name);
obj.name.firstName = '四';
obj.age.nowAge = 17;
console.log(obj.name.firstName) //三
console.log(obj.age.nowAge) //17
性能测试
以一个10000条数据的列表为例,分别获取到数据改变前以及数据开始渲染视图,视图更新完成这三个点的时间戳,取其时间差。
系统: macos 10.15.6
环境: Chrome 92.0.4515.107
Vue: 2.5.2
<template>
<div>
<button @click="initList">重新加载</button>
<table border="1" cellspacing="0" cellpadding="0">
<thead>
<tr>
<td>序号</td>
<td>昵称</td>
<td>手机号</td>
<td>礼品</td>
</tr>
</thead>
<tbody>
<tr v-for="(item,index) in list" :key="index">
<td>{{item.id+1}}</td>
<td>{{item.name}}</td>
<td>{{item.mobile}}</td>
<td>{{item.prize}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
let t = 0
let t1 = 0
export default {
name: 'list',
data() {
return {
list: []
}
},
created() {
this.initList()
},
beforeUpdate() {
t1 = new Date().getTime()
console.log(t1 - t, "beforeUpdate时间差")
},
updated() {
let time = new Date().getTime()
console.log(time - t1, "updated时间差")
},
methods: {
// 生成随机昵称
getWord() {
var _rsl = ""
var _randomUniCode = Math.floor(Math.random() * (40870 - 19968) + 19968).toString(16)
eval("_rsl=" + '"\\u' + _randomUniCode + '"')
_rsl += ["先生", "女士"][Math.round(Math.random())]
return _rsl
},
// 生成随机手机号
getMobile() {
var arr = new Array("130", "131", "132", "133", "135", "137", "138", "170", "187", "189")
var i = parseInt(10 * Math.random())
var mobile = arr[i]
for (var j = 0; j < 8; j++) {
mobile = mobile + Math.floor(Math.random() * 10)
}
return mobile
},
initList() {
let list = []
for (let i = 0; i < 10000; i++) {
list.push({
id: i,
name: this.getWord(),
mobile: this.getMobile(),
prize: "500积分"
})
}
t = new Date().getTime()
this.list = list
}
}
}
</script>
<style scoped>
table {
width: 100%;
}
</style>
多次执行得到大概如下结果:
再来修改
this.list的赋值语句,改为freeze赋值
// this.list = list
this.list = Object.freeze(list)
可以看到Object.freeze()冻结后的list执行时间短于前者。数据量越大差距越明显。
结论
综上,当在vue2中 data内的数据仅用来展示,不会对其修改时;或者只用于js内逻辑处理,不会对其进行操作时,可以使用Object.freeze()冻结这些数据,节省一部分性能。