实现 MVVM (一)- Object.definePrope
动机 (写在前面)
之前在学习构建自己轮子组件库时,被反复的提到了 MVVM 核心实现方法的问题,其中包括 Vuejs 的原理。逛过一些技术社区。一些前辈和大佬给出了建议。初级水平的人并不推荐去看 Vuejs 的源码,截止到今天,Vuejs 2.5.17 版本的源码高达 10978 行。因此初级水平的人看源码性价比也许真的并不高。一些前辈和大牛给出的建议是,Vuejs 的实现原理尤雨溪已经说得很明白了。建议大家可以使用自己的方式去简单模拟一下 MVVM 的思想,也许可能实现得并不优雅。但这样做比头铁的看源码来得更有价值和意义。
本文是我通过已经知晓的 Vuejs 实现原理来简单实现 MVVM 的系列博文的第一篇,主要总结归纳了 Object.defineProperty()
的方法特性。
Object.defineProperty
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。其语法是:
Object.defineProperty(obj, prop, descriptor)
参数说明(三个参数都是必须的):
obj // 要在其上定义属性的对象。
prop // 要定义或修改的属性的名称。
descriptor // 将被定义或修改的属性描述符。
返回值为传入参数的对象,即第一个参数 obj
。
使用方法
以下三种方法都可以用来定义/修改一个对象属性,其中包含 Object.defineProperty()
方法。
var obj = {}
obj.name = 'evenyao'
obj['age'] = 27
Object.defineProperty(obj, 'intro', {
value : 'hello world'
})
console.log(obj) // {name: 'evenyao', age: 27, intro: 'hello world'}
configurable
configurable
是该方法传参中最后一项 descriptor
中的属性描述符。configurable
的值设置为 false
后(如果没设置,默认就是 false
)。以后就不能再次通过 Object.defineProperty()
方法修改属性,也无法删除该属性。如果configurable
的值设置为 true
后,能删除该属性,但也不能修改。
举例说明:
var obj = {}
Object.defineProperty(obj, 'intro', {
configurable: false,
value : 'hello world'
})
obj.intro = 'i wanna change it'
console.log(obj.intro) // "hello world"
delete obj.intro // false, 删除失败
console.log(obj.intro) // "hello world"
Object.defineProperty(obj, 'name', {
configurable: true,
value : 'i wanna change it'
})
delete obj.intro // true , 成功删除
enumerable
enumerable
也是该方法传参中最后一项 descriptor
中的属性描述符。设置 enumerable
属性为false
后,遍历对象的时候会忽略当前属性(如果未设置,默认就是 false
不可遍历)。
举例说明:
var obj = {name: 'evenyao'}
Object.defineProperty(obj, 'age', {
enumerable: false,
value: 27
})
for(var key in obj){
console.log(key) // 只输出 'name', 不输出'age'
}
value 和 writable
value
和 writable
叫 数据描述符,具有以下可选键值:
-
value: 该属性对应的值。可以是任何有效的
JavaScript
值(数值,对象,函数等)。默认为undefined
。 -
writable: 当且仅当该属性的
writable
为true
时,该属性才能被赋值运算符改变。但不能删除。该属性默认为false
。
举例说明:
var obj = {name: 'evenyao'}
Object.defineProperty(obj, 'age', {
value: 27,
writable: false
})
obj.age = 26
console.log(obj.age) // 27, writable为 false 时,修改对象的当前属性值无效
区别
configurable: true
和wriable: true
的区别是,前者是设置属性能删除,后者是设置属性能修改
get 和 set
get
和 set
叫 存取描述符,有以下可选键值:
-
get:一个给属性提供
getter
的方法,如果没有getter
则为undefined
。该方法返回值被用作属性值。默认为undefined
。 -
set:一个给属性提供
setter
的方法,如果没有setter
则为undefined
。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为undefined
。
var obj = {}
var age
Object.defineProperty(obj, 'age', {
get: function(){
console.log('get age...')
return age
},
set: function(val){
console.log('set age...')
age = val
}
})
obj.age = 100 // 'set age...'
console.log(obj.age) // 'get age...', 100
值得一提的是这个案例和之前我在 从「闭包」到 思考人生 那篇文章里面封装的那个闭包函数(中文的案例2)是很相似的。事实上在我看来,他们所达到的效果是一样的。
var Age = (function(){
var age = undefined
function set(s){
age = s
console.log('set age...')
}
function get(){
console.log('get age...')
return age
}
return {
set: set,
get: get
}
})()
Age.set(100) // 'set age...'
Age.get() // 100
数据描述符 和 存取描述符 是不能同时存在的。如果同时存在,代码就会报错。
例如下面例子,就是不被允许的。这段代码同时出现了 value
和 get
/ set
。所以会报错。
var obj = {}
var age
Object.defineProperty(obj, 'age', {
value: 27,
get: function(){
console.log('get age...')
return age
},
set: function(val){
console.log('set age...')
age = val
}
})