第二十七章 数据劫持

一、现在的开发方式

1、现实中的开发,很少使用原声JS,不是因为JS不强大,主要是因为操作比较繁琐,几乎所有的公司都在使用框架,比如vue、react

2、特点:数据驱动视图。也就是数据发生变化以后,视图跟着变化

所以现在我们更加关注的是我们的数据了

二、数据劫持

1、含义:对原有数据的复刻,就是复制一份原有的数据出来,但是复刻出来的数据不允许修改,但是这个数据是从原有的数据中复刻出来的

2、语法:Object.defineProperty(给那一个对象,属性名,{配置项})

  • 在配置项中包含着属性名的值
  • 配置项中的内容:

=> value:该属性名对应的值

=> writable:该属性是否可以被重写(就是重新设置值)

        -> 默认是 false 不允许被重写 , 也就是只读

        -> 选填是 true 表示允许被重写 , 也就是可以被修改

=> enumerable: 表示该属性是否可以不枚举(遍历)

        -> 默认是 false 不可以枚举

        -> 选填是 true 表示可以遍历

=> get: 是一个函数 , 叫做getter获取器

        -> 可以用来获取该属性的值

        -> get属性的返回值就是这个属性的值

        -> 注意: 不能和 value 和 writable 一起使用 , 会报错
=> set: 是一个函数 , 叫做setter设置器

        -> 当你需要修改该属性值的时候 , 会触发该函数

// 设置
Object.defineProperty(obj,'age',{
    value:18,
    writable:true,
    enumerable:true,
    get () {
        // 该函数的返回值就是这个属性的值
        // 上面设置了value 和 writable 这里就不能返回了
        return 20
    },
    set (val) {
        console.log('你想要修改age的值,修改为:',val);
    }
})
console.log(obj); // 打印结果: {age: 18}
// 之后我们尝试修改
// 修改我们之前的普通设置
obj.name = 'Rose'
console.log(obj); // 没有问题可以修改
// 修改通过Object.defineProperty设置的值
obj.age = 30
console.log(obj); // 打印出来的结果还是18 , 这个时候是不允许被修改的
// 在没有书写 enumerable 之前是不可以遍历出age的 , 书写了enumerable:true 以后是可以的
for (let k in obj) {
    console.log(k);
}
// 测试get函数的返回值不能和 value 和 writable一起使用
console.log(obj)

3、数据劫持的简单封装

function observer (origin,fn) {
    // origin : 原始数据 , 也就的你给我的数据
    // fn : 我想要做的事情
    // 定义一个劫持目标
    const target = {}
    // 我们循环拿到传递进来的数据
    for (let k in origin) {
        // 开始劫持
        Object.defineProperty(target, k,{
            // 返回的数据
            get () {
                return origin[k];
            },
            set (val) {
                // 修改的是origin内的数据
                origin[k] = val
                // 修改完毕要执行一下我的功能函数
                fn(target)
            }
        })
    }
    // 初始的时候我们也要执行一下我们的功能函数
    fn(target)
    // 返回一个被劫持后的数据
    return target
}
// 获取元素
const box = document.querySelector('.box')
// 将来我们使用的时候
const app = observer({name:'Rose',age:30},result => {
    // 箭头函数中是我想要做的事情
    box.innerHTML =`我是${result.name},今年${result.age}岁了`
})
console.log(app);
// 获取元素
const inp = document.querySelector('input')
inp.oninput = () => {
    app.age = inp.value
}

4、数据劫持升级

语法:

Object.defineProperties(对象,{

哪一个属性:{配置项},

哪一个属性:{配置项},

....

}

缺点:(1) 就是只能劫持当前以前的数据

(2)如果劫持过后 , 后期动态插入的数据不好使(也就的不能再被劫持到)

// 数据劫持
const obj = {name:'Jack',age:30}
console.log('原始obj:',obj);
// 开始劫持 把obj劫持到obj身上
// 拿到obj中的所有的key
for (let k in obj) {
    // 开始劫持
    Object.defineProperties(obj,{
        // 这样操作会报错
        // 一旦 obj.name 被修改
        // 不停的获取不停的该 , 不停的该不停的获取
        // 就会造成栈溢出
        // name:{
        //     get () {
        //         return obj.name
        //     }
        // }
        // 步骤1: 我们需要复制一份属性出来(也就是备份一份)
        // 这里需要拼接一个变量出来
        // 假设:之前的属性是name , 我们复制出来的属性叫做:_name
        // 语法: ['_' + 属性名] : {}
        ['_' + k] : {
            value: obj[k],
            writable: true 
        },
        // 步骤2: 正式开始劫持(劫持的是我们备份的)
        [k] : {
            get () {
                return this['_' + k]
            },
            set (val) {
                this['_' + k] = val
                // 渲染页面操作
                console.log('你尝试修改 ' + k + ' 属性, 你要修改为 : ', val)
            }
        }
    })
}
console.log('劫持后obj',obj);
// 尝试修改
obj.age = 66

三、数据代理

1、这个行为也是一个劫持行为,是 ES6 提供的语法 , 是一个内置构造函数,但是在社区里大家还是都叫数据劫持

2、语法:const 变量名 = new Proxy(要代理的原始对象,{ 配置项 })

3、返回值: 一个实例对象 , 就是代理结果数据

// 定义一个对象
const obj = {name: 'Jack', age:25} 
// 开始代理
const result = new Proxy(obj, {
    // 配置get来进行代理设置
    get (target,property) {
        // target:就是你要代理的目标对象 , 我们这个案例中就是obj
        // prototype: 是该对象内的每一个属性 , 自动遍历
        return target[prototype]
    },
    // 配置set来进行修改
    set (target,property,val) {
        // target: 就是你要代理的目标对象
        // prototype: 就是对象内你要修改的那个属性
        // val: 就是你要修改的那个属性的值
        target[prototype] = val
        console.log('你尝试修改'+ prototype + '属性,想要修改为:'+ val + ',我要根据你修改的内容渲染页面');
        // 注意: 简单代理需要返回 true 让程序正常执行
        return true 
    }
})
console.log('原始数据:',obj);
console.log('代理数据:',result);
console.log('代理结果 name:',result.name);
        
// 尝试修改
result.name = 'Rose'
console.log('代理结果 name:',result.name);
        
// 动态插入数据
result.gender = '男'

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值