剖析vue3数据绑定原理 Proxy

//ES5
let obj = {}
Object.defineProperty(
    obj,
    'name', {
        get() {
            console.log('get');
            return 'zxs'
        },
        set() {
            console.log('set');
        }
    })



console.log(obj.name); //get zxs
obj.name = 'es'

let obj1 = {}
let newVal = ''
Object.defineProperty(obj1, 'name', {
    get() {
        console.log('读取了属性');
        return newVal;
    },
    set(val) {
        console.log("设置了属性");
        newVal = val;
    }
})

console.log(obj1.name);
obj1.name = 'es';

// ES6

let obj2 = {}
let p = new Proxy(obj2, {}) //参数1:要包装(拦截)的对象  //参数2: 拦截方法钩子函数,类似于上面的get,set
p.name = 'zxs';
console.log(obj2.name);

let arr = [7, 8, 9]
arr = new Proxy(arr, {
    get(target, prop) {
        console.log('target: ' + target + 'prop: ' + prop); //target: 7,8,9  prop: 1 //target是要包装的整个对象,prop是带的参数
        return prop in target ? target[prop] : 'error'
    }
})
console.log(arr[1]); //target: 7,8,9  prop: 1    8
console.log(arr[10]); //target: 7,8,9 prop: 10   error



let dict = {
    'hello': '你好',
    'world': '世界'
}
dict = new Proxy(dict, {
    get(target, prop) {
        return prop in target ? target[prop] : prop
    }
})

console.log(dict['world']); //世界
console.log(dict['zxs']); //zxs



let arr1 = []
arr1 = new Proxy(arr1, {
    set(target, prop, val) {
        if (typeof val === 'number') {
            console.log('target: ' + target + ' prop: ' + prop + ' val: ' + val);
            target[prop] = val
            return true
        } else {
            return false
        }
    }
})

arr1.push(5); //target:  prop: 0 val: 5
arr1.push(6) //target: 5 prop: 1 val: 6
console.log(arr1[0], arr1[1], arr1.length); //target: 5,6 prop: length val: 2  //5 6 2



// has
let range = {
    start: 1,
    end: 5
}

range = new Proxy(range, {
    has(target, prop) {
        return prop >= target.start && prop <= target.end
    }
})

console.log(2 in range); //true
console.log(6 in range); //false

let userinfo = {
    username: 'zxs',
    age: 100,
    _pwd: '1234' //不想让外界访问到_pwd
}

userinfo = new Proxy(userinfo, {
    ownKeys(target) {
        return Object.keys(target).filter(key => !key.startsWith('_'));
    }
})

for (let i in userinfo) {
    console.log(i);
    //username
    //age
}


console.log(Object.keys(userinfo)); //['username', 'age']


let user = {
    username: 'zxs',
    age: 100,
    _pwd: '12345' //不想让外界访问到_pwd,删除_pwd等等所有操作
}


user = new Proxy(user, {
    get(target, prop) {
        if (prop.startsWith('_')) {
            // throw new Error('不可访问')
        } else {
            return target[prop]
        }
    },
    set(target, prop, val) {
        if (prop.startsWith('_')) {
            throw new Error('不可访问')
        } else {
            target[prop] = val
            return true
        }
    },
    deleteProperty(target, prop) {
        if (prop.startsWith('_')) {
            throw new Error('不可删除')
        } else {
            delete target[prop]
            return true
        }
    },
    ownKeys(target) {
        return Object.keys(target).filter(key => !key.startsWith('_'))
    }
})


console.log(user); //['username', 'age']
console.log(user._pwd); //Error:不可访问
user.age = 18;
console.log(user.age = 18);

// try {
//     user._pwd = 'xxx'
// } catch (e) {
//     console.log(e.message); //不可访问
// }



// try {
//     delete user._pwd
// } catch (e) {
//     console.log(e.message); //不可删除
// }


for (let key in user) {
    console.log(key);
    //username
    //age
}



// apply

//未知参数求和
let sum = (...args) => {
    let num = 0;
    args.forEach(item => {
        num += item
    })
    return num;
}
sum = new Proxy(sum, {
    apply(target, ctx, args) {
        //ctx :目标对象的上下文对象(this)
        return target(...args) * 2 //将求和函数结果*2
    }
})
console.log(sum(1, 1, 1 ));//6
console.log(sum.call(null, 1, 1, 1)); //6
console.log(sum.apply(null,[1,1,1]));//6

// construct
let user1=class{
    constructor(name){
        this.name=name
    }
}
user1 = new Proxy(user1, {
    //拦截 new一个对象
    construct(target, args,newTarget){
        return new target(...args)
    }
})

console.log(new user1('zxs')); //user1 {name: 'zxs'}



 




 










posted @ 2022-07-05 21:48  小国际  阅读(231)  评论(0)    收藏  举报