vue2响应式原理之Object.defineProperty()方法的使用
作者:山海入梦
前言
最近一直在研究vue2响应式原理,去官网看一遍文档,好像懂了但又好像不懂,然后去查看别人写的响应式原理和视频,好的理解了百分六七十头皮发麻,vue2的响应式原理实现的核心就是Object.defineProperty()方法,所以自己也跟着手敲一下响应式源码记录对Object.defineProperty的理解
一、Object.defineProperty()
1.概念
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象.
这句话到底什么意思呢?
我们简单实现这个方法
var obj = {} Object.defineProperty(obj, 'name', { value:'科比' }) console.log(obj.name) //科比
可以看出Object.defineProperty()能为我们定义一个属性,又有人会想为什么我们不直接定义obj.name='科比',而使用这个方法不更加麻烦吗?
2.Object.definProperty()方法
可以设置额外隐藏的属性使用这些属性能够使对象更加自由的被定义
var obj = {} Object.defineProperty(obj, 'name', { value:'科比', //是否可写 writable: false }) Object.defineProperty(obj, 'number', { value:24, //是否可枚举 enumerable: false }) //修改属性报错 obj.name = "库里" //Cannot assign to read only property 'name' of object '#<Object>' console.log(obj.name)
通过obj对象定义writable: false 使你属性不能修改,如果修改obj.name就会报错;enumerable是否可以枚举,所以使用这些属性能够使对象更加自由的被定义
二、Object.definProperty()方法的get()和set()
代码如下(示例):
通过这个示例可知访问obj.name属性就会触发get()方法,修改obj.name属性触发set()方法
但是我们发现修改obj.name属性为"乔丹",打印为undefined这是为什么呢?
看一下get和set方法的介绍:
get
- 属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。
- 执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。
- 该函数的返回值会被用作属性的值。
- 默认为 undefined。
set
- 属性的 setter 函数,如果没有 setter,则为 undefined。
- 当属性值被修改时,会调用此函数。
- 该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。
- 默认为 undefined。
因为get的函数返回值会被当作属性的值,而我们示例中get和set没有return 任何值,就默认为undefined,修改后:
const obj = {} Object.defineProperty(obj , 'name' , { get(){ console.log('访问obj.name属性触发') return "乔丹" }, set(newValue) { console.log('修改obj.name属性触发' , newValue) } }) obj.name //访问属性 console.log(obj.name) //乔丹 obj.name = "科比" //修改属性 console.log(obj.name) //乔丹
能够访问到设置的obj属性了,但是修改了obj.name = "科比"
最后打印还是"乔丹" ,但是set方法触发的newValue是科比这又是为什么呢?
因为getter并不能返回你修改的值,只要你访问obj.name他就是返回return "乔丹"
就如同你设置的set新属性从未改变一样非常固执,那么我们应该怎么解决这个问题呢?
我们可以通过一个变量com进行周转,修改如下:
var obj = {} var com; //设置变量周转 Object.defineProperty(obj , 'name' , { get(){ console.log('访问obj.name属性触发') return com }, set(newValue) { console.log('修改obj.name属性触发' , newValue) com = newValue } }) obj.name //访问属性 console.log(obj.name) //乔丹 obj.name = "科比" //修改属性科比 console.log(obj.name) //最后控制台打印 科比
总结
vue2的响应式原理核心就是基于Object.defineProperty()方法实现的哟,不过完整的响应式源码可不止这样简单,所以下一篇博客就是手敲完整vue2响应式源码实现,加深理解.
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。