实现的样例
let app1 = new Observer({
name: 'youngwind',
age: 25
});
let app2 = new Observer({
university: 'bupt',
major: 'computer'
});
// 要实现的结果如下:
app1.data.name // 你访问了 name
app.data.age = 100; // 你设置了 age,新的值为100
app2.data.university // 你访问了 university
app2.data.major = 'science' // 你设置了 major,新的值为 science
实现要求
- 传入参数只考虑对象,不考虑数组。
- new Observer返回一个对象,其 data 属性要能够访问到传递进去的对象。
- 通过 data 访问属性和设置属性的时候,均能打印出右侧对应的信息。
参考文章
思路
我是完全没有思路的,直到看了参考 ToT
Object.defineProperty(obj, prop, descriptor)阅读
- obj 要在其上定义属性的对象
- configurable属性:默认false 属性描述符的类型可能被改变,并且可以从当前对象中删除
- enumberable属性:默认false 属性可以用for…in枚举
- writable属性:默认false 该属性可以用赋值运算符修改其值
- value属性:默认undefined
get,set:访问器描述符,默认undefined
划重点 :一个数据描述符是具有价值,这可能会或可能是不可写的属性。一个访问描述符是一个getter,setter方法对函数描述的属性。描述符必须是这两种类型之一; 它不能两者都。
也就是说:出现了value,writable就不可以在出现getter,setter 因为具有value是否可以修改是用writable来控制,访问器控制符所做的也是这个工作。具体的可以阅读MDN,而我们完成监听改变需要的就是自定义setter和getter
// MDN示例代码
function Archiver() {
var temperature = null;
Object.defineProperty(this, 'temperature', {
get: function() {
console.log('get!');
return temperature;
},
set: function(value) {
console.log('set!');
temperature = value;
}
});
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
初级实现,直接传入一个对象
function Observe(data) {
this.data = data;
this.map(data)// 遍历这个对象的键值
}
Observe.prototype = {
constructor : Observe,
map : function(data) {
for(key in data){
this.convert(key,data[key]);
}
},
// 给每一个键,也说是每一个属性都绑定上属于自己的get和set。不知道这样理解对不对
convert : function(key,value) {
Object.defineProperty(this.data,key,{
get : function(){
console.log('you visited me!');
return name;
},
set : function(value) {
console.log('you change me!');
name = value;
}
})
}
}
var app1 = new Observe({// 直接传入一个对象
name: 'youngwind',
age: 25
});
app1.data.name; // 实现访问
app1.data.age = 100; // 实现改变
中级绑定,如果传入的是对象内含有对象呢?
首先遍历到最底层的属性值,然后递归调用观察器,这里基本就是照搬参考上的代码了。
function Observe(data) {
this.data = data;
this.map(data)
}
Observe.prototype = {
constructor : Observe,
map: function(obj) {
var val;
for (var key in obj) {
// for...in 循环会把对象原型链上的所有可枚举属性都循环出来
// 而我们想要监听的仅仅是这个对象本身拥有的属性,所以要这么做。
if (obj.hasOwnProperty(key)) {
val = obj[key];
// 这里进行判断,如果还没有遍历到最底层,继续new Observer
if (typeof val === 'object') {
new Observe(val);
}
// 除了要遍历到最底层,监听最底层的变化,也要监听自己的的变化
this.convert(key, val);
}
}
},
convert: function(key,value) {
// 监听对象变成了this.data
Object.defineProperty(this.data, key, {
enumerable: true,// 可以被枚举
configurable: true,
get: function() {
console.log('you visited ' + key);
return value;
},
set: function(newValue) {
console.log('you change ' + key + ' to ' + newValue);
if(value == newValue) { return ;}
value = newValue;
}
})
}
}
var data = {// 传入一个复杂的data,要遍历到他的每一个键值对
user: {
name: "hehe",
age: "24"
},
address: {
city: "beijing"
}
};
var app1 = new Observe(data);
app1.data.user;
app1.data.user.name; // 实现访问
app1.data.user.age = '100'; // 实现改变
问题
- 只监听的对象的变化,没有处理数组的变化。
- 当你重新set的属性是对象的话,那么新set的对象里面的属性不能调用getter和setter。比如像下图所示,重新设置的job属性就不在带有自定义的getter和setter了,不再提示“你访问了job”这些字样。
我不是特别懂,所以,需要继续学习才能明白这个问题到底是什么意思,哈哈,这是仅仅是作为一个学习笔记咯,大家还是要去看原文