手写vue(上) defineProperty
通过Object.defineProperty函数可以对对象属性的设置和获取进行拦截
定义函数defineReactive
该函数传入对象,属性,值;对传入的对象的属性操作进行拦截。
每次获取此属性前打印get xxx,每次对此属性设置值前打印set xxx 新值
function defineReactive(obj, key, val){
// 对传入obj进行访问拦截,注意:对数组无效
Object.defineProperty(obj, key, {
// val被引用,形成闭包不被释放,保存当前状态
// 暴露在函数作用域之外,下面用obj.xxx通过get方法在全局作用域能访问到
get(){
console.log('get '+key);
return val
},
set(newVal){
if(newVal !== val){
console.log('set ' + key + ': ' + newVal);
val = newVal
}
}
})
}调用
const obj = {}
defineReactive(obj, 'foo', 'bar')
obj.foo // get foo
obj.foo = 'foobar' // set foo: foobar在对属性set时进行一些界面更新
set(newVal){
if(newVal !== val){
console.log('set ' + key + ': ' + newVal);
val = newVal
// 更新函数
update()
}
}
function update(){
document.body.innerText = obj.foo
}使用
defineReactive(obj, 'foo', 'bar')
// 页面加载显示时间
obj.foo = new Date().toLocaleTimeString()
// 每隔一秒后时间更新
setInterval(() => {
obj.foo = new Date().toLocaleTimeString()
},1000)
递归拦截,set拦截
假如对象多层嵌套,上面无法拦截
const obj = { foo: 'bar', baz: 'bar', foobar: { a: 1 } }定义observe函数,对循环循环拦截
function observe(obj){
if(typeof obj !== 'object' || obj == null) return
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}对象嵌套的情况要递归拦截,如果传入的newVal依然是obj,要对其做响应式处理
function defineReactive(obj, key, val){
// 递归
observe(val)
// 对传入obj进行访问拦截
Object.defineProperty(obj, key, {
// val被引用,形成闭包不被释放,保存当前状态
get(){
console.log('get '+key);
return val
},
set(newVal){
if(newVal !== val){
console.log('set ' + key + ': ' + newVal);
// 如果传入的newVal依然是obj,要对其做响应式处理
observe(newVal)
val = newVal
}
}
})
}当添加新属性,直接赋值无法拦截,需要经过defineProperty再拦截
function set(obj, key, val){
defineReactive(obj, key, val)
}使用
const obj = { foo: 'bar', baz: 'bar', foobar: { a: 1 } }
// 遍历响应化处理
observe(obj)
obj.foo // get foo
obj.foo = 'foobar' // set foo: foobar
obj.baz // get baz
obj.baz = 'foobarbaz' // set baz: foobarbaz
obj.foobar.a = 10 // 先get foobar 后set a: 10
// 添加新属性
// obj.dong = 'dong'
set(obj, 'dong', 'dong')
obj.dong // get dongObject.defineProperty没法拦截数组
替换数组原型中7个方法
push、pop、unshift、shift、reverse、splice、sort
// 数组响应式
// 1.替换数组原型中7个方法
const orginalProto = Array.prototype
// 备份一份,修改备份
const arrayProto = Object.create(orginalProto);
['push', 'pop', 'shift', 'unshift'].forEach(method => {
arrayProto[method] = function(){
// 原始操作
orginalProto[method].apply(this, arguments)
// 覆盖操作,通知更新
console.log('数组执行 '+ method +' 操作');
}
});
function defineReactive(obj, key, val){
// 递归
observe(val)
// 对传入obj进行访问拦截
Object.defineProperty(obj, key, {
// val被引用,形成闭包不被释放,保存当前状态
get(){
console.log('get '+key);
return val
},
set(newVal){
if(newVal !== val){
console.log('set ' + key + ': ' + newVal);
// 如果传入的newVal依然是obj,要对其做响应式处理
observe(newVal)
val = newVal
}
}
})
}
function observe(obj){
if(typeof obj !== 'object' || obj == null) return
// 判断传入obj类型
if(Array.isArray(obj)){
// 覆盖原型,替换7个变更操作
obj.__proto__ = arrayProto
// 对数组内部元素执行响应化
const keys = Object.keys(obj)
for(let i = 0; i< obj.length; i++){
observe(obj[i])
}
}else{
Object.keys(obj).forEach(key => {
defineReactive(obj, key, obj[key])
})
}
}
function set(obj, key, val){
defineReactive(obj, key, val)
}
// 响应式
const obj = { foo: 'bar', baz: 'bar', foobar: { a: 1 }, arr: [] }
// 遍历响应化处理
observe(obj)
obj.foo
obj.foo = 'foobar'
obj.baz
obj.baz = 'foobarbaz'
obj.foobar.a = 10
// 添加新属性
// obj.dong = 'dong'
set(obj, 'dong', 'dong')
obj.dong
obj.arr.push(1)
Ценники на вывоз мусора сейчас космос, любые лайфхаки по экономии в тему.
1xbet onlayn kazino platforması ilə vaxtınızı daha səmərəli və maraqlı keçirin. Saytın canlı kazino bölməsi istifadəçilərə fərqli bir dünya təklif edir. Burada canlı dilerli kazino oyunlarının hər bir növünü sınaqdan keçirə bilərsiniz. Krupyelərin peşəkarlığı oyunun dinamikasını və marağını artırır. Müntəzəm olaraq yenilənən oyun siyahısı cansıxıcılığa yol vermir. Hesabınızı artırmaq üçün onlarla fərqli və etibarlı üsul mövcuddur. Qazanılan pullar cəmi bir neçə dəqiqə ərzində şəxsi hesabınıza köçürülür. Aktiv fəaliyyətinizə görə fərdi bonuslar və hədiyyələr qazana bilərsiniz. Dəstək xidməti həm çat, həm də e-poçt vasitəsilə kömək göstərir. 1xbet ailəsinə qoşulun və böyük uduşlar üçün ilk addımı atın. onlayn kazino
我一直梦想, 看到你们相册那样的地方。真棒。
我喜欢, 这里分享真实经验。你的项目 就是 属于这里的。请继续。
我热爱这样的想法, 去那么多国家。真的很鼓舞。
能感受到热爱。继续保持 感受。
我关注这样的资源, 写得很实在。你的网站 就是 属于这里的。加油。
1
1
1