学过vue的对getter和setter听起来应该都比较熟悉,因为vue的响应式原理就是使用 Object.defineProperty 把对象的 property 全部转为 getter/setter。
通过getter我们可以获取对象中相关属性的值。我们可以理解为我们是定义了一个伪属性,我们读取这个伪属性的值时,它会按照我们定义好的规则返回对象的相关的值。
例如:
let obj = {
people: {
info: {
name: 'lis',
}
},
get getName() {
return this.people.info.name
}
}
console.log(obj.getName);
我们可以在getter中自己定义返回的格式
let obj = {
people: {
info: {
name: 'lis',
}
},
get getName() {
return this.people.info.name + '1111'
}
}
console.log(obj.getName);
let obj = {
people: {
info: {
name: 'lis',
}
},
get getName() {
console.log('name被取出了');
return this.people.info.name + '1111'
}
}
console.log(obj.getName);
通过setter我们可以修改对象中的相关属性,同样我们也可以理解为我们定义了一个伪属性,当我们修改这个伪属性的值时,它会按照我们定义好的规则修改相关属性。
let obj = {
people: {
info: {
name: 'lis',
}
},
get getName() {
return this.people.info.name
},
set setName(newName) {
this.people.info.name = newName
}
}
obj.setName = 'dwq';
console.log(obj.getName);
和getter类似,我们可以自己定义修改规则,并且监听修改情况
let obj = {
people: {
info: {
name: 'lis',
}
},
get getName() {
return this.people.info.name
},
set setName(newName) {
console.log('name被修改了');
this.people.info.name = newName + '1111'
}
}
obj.setName = 'dwq';
console.log(obj.getName);
一般有三种情况设置:对象初始化时定义get和set、通过Object.prototype.__defineGetter__()
和 Object.prototype.__defineSetter__()
定义getter和setter、通过Object.defineProperty()
和Object.defineProperties()
定义getter和setter
下面将简单介绍这三种方式
初始时定义就像上面介绍的一样,在定义对象时就定义好get和set
let user = {
info: {
name: 'lis'
},
get name() {
return this.info.name
},
set name(newName) {
this.info.name = newName
}
}
**注:**getter和setter是可以同名的,这是一个非常优秀的设定
定义一个对象:
let user = {
info: {
name: 'lis'
},
}
console.log(user);
我们可以看到当前对象的原型链有__defineGetter__()
和__defineSetter__()
两个方法
具体语法:
obj.__defineGetter__(property, func)
:
property
: 一个字符串,表示指定的属性名。
func
: 一个函数,当 prop 属性的值被读取时自动被调用。
let user = {
info: {
name: 'lis'
},
}
user.__defineGetter__('getName', function () {
return this.info.name
})
console.log(user.getName);
具体语法:
obj.__defineSetter__(property, func)
:
property
: 一个字符串,表示指定的属性名。
func
: 一个函数,当 prop 属性的值被读取时自动被调用。
let user = {
info: {
name: 'lis'
},
}
user.__defineGetter__('getName', function () {
return this.info.name
})
user.__defineSetter__('setName', function (newName) {
this.info.name = newName
})
user.setName = 'dwq'
console.log(user.getName);
静态方法Object.defineProperty(obj, property, descriptor)很强大,但我们这里只讨论设置getter和setter
具体语法:
Object.defineProperty(obj, property, descriptor)
:
参数
obj
: Object,Required,要在其上定义属性的对象。
property,
: String|Symbol,Required,要定义或修改的属性的名称。
descriptor
: Object,Required,将被定义或修改的属性描述符。
返回值: Object,返回被传递给函数的对象obj。
let user = {
info: {
name: 'lis'
},
}
Object.defineProperty(user, 'userName', {
get: function () {
return this.info.name
},
set(newName) {
this.info.name = newName
}
})
user.userName = 'dwq'
console.log(user.userName);
静态方法Object.defineProperties(obj, propertys)可以同时设置多个属性。
具体语法:
Object.defineProperties(obj, propertys
:
Object.defineProperty(obj, property, descriptor)
:
参数
obj
: Object,Required,要在其上定义属性的对象。
propertys,
: String|Symbol,Required,要定义或修改的属性名称以及的详细描述。
返回值: Object,返回被传递给函数的对象obj。
let user = {
info: {
name: 'lis',
age: '18'
},
}
Object.defineProperties(user, {
userName: {
get() {
return this.info.name
},
set(newName) {
this.info.name = newName
}
},
userAge: {
get() {
return this.info.age
},
set(newAge) {
this.info.age = newAge
}
}
})
user.userName = 'dwq'
user.userAge = '20'
console.log(user.userName);
console.log(user.userAge);
学了getter和setter之后我们可以简单模拟一下vue的响应式原理,来实现vue中对data中定义的值实现动态监听,当然这里只是简单模拟,vue的响应式原理的实现还是很复杂的。
首先定义一个对象Vue:
let Vue = {
data(){
return {
name: 'dwq',
age: '18',
message: '哈哈哈'
}
}
}
对data中的所有数据添加动态监听:
function addDynamicMonitoring(obj) {
if (obj.data) {
for (const dataKey in obj.data) {
if (!obj.data.hasOwnProperty(dataKey)) {
return ''
}
Object.defineProperty(obj, dataKey, {
get() {
console.log(dataKey + '被读取了');
return this.data[dataKey]
},
set(v) {
console.log(dataKey + '被修改了');
this.data[dataKey] = v
}
})
}
}
}
Vue就是在对应的getter和setter中进行相关的DOM操作的。
完整代码:
let Vue = {
data: {
name: 'dwq',
age: '18',
message: '哈哈哈',
info: {
address: '111'
}
}
}
let a = {
name: 11
}
function addDynamicMonitoring(obj) {
if (obj.data) {
for (const dataKey in obj.data) {
if (!obj.data.hasOwnProperty(dataKey)) {
return ''
}
Object.defineProperty(obj, dataKey, {
get() {
console.log(dataKey + '被读取了');
return this.data[dataKey]
},
set(v) {
console.log(dataKey + '被修改了');
this.data[dataKey] = v
}
})
}
}
}
addDynamicMonitoring(Vue)
console.log(Vue.name);
Vue.age = 22
console.log(Vue.age);