javascrip中的数据劫持与数据代理

简介: javascrip中的数据劫持与数据代理

一、用Object.defineProperty实现数据劫持

1.VUE2中的响应式原理

当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用

Object.defineProperty 把这些 property 全部转为

getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是 Vue 不支持

IE8 以及更低版本浏览器的原因。

这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property

被访问和修改时通知变更。这里需要注意的是不同浏览器在控制台打印数据对象时对 getter/setter 的格式化并不同,所以建议安装

vue-devtools 来获取对检查数据更加友好的用户界面。

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的

setter 触发时,会通知 watcher,从而使它关联的组件重新渲染

也就是说vue对data选项的所有property加了监听,当数据变化时,vue2中每一个实例都有一个watcher进行依赖收集,也就是这个实例所关联的property。property变化时候被setter监听到,然后通知watcher再进行后续处理。

2.用一个Object.defineProperty实现一个简单的数据劫持

    let a = {
        name: "小红",
        age: 12,
        oinfo: {
            school: "狗屁大学",
            hobby: ["football", "pingpang"]
        },
    }

    const observer = function (data) {

        if (!data || typeof data !== 'object') {
            return
        }
        for (const key in data) {
            if (Object.hasOwnProperty.call(data, key)) {
                let currentData = data[key]
                observer(currentData)
                Object.defineProperty(data, key, {
                    enumerable: true,
                    configurable: false,
                    get() {
                        console.log(`调用数据时候:${key}数据被劫持劫持`);
                        return currentData
                    },
                    set(value) {
                        console.log(`设置数据时候:${key}数据被劫持劫持`);
                        currentData = value
                    }
                })
            }
        }
    }
    observer(a)
    a.oinfo.hobby = ["1", "2"]
    console.log(a.oinfo.hobby);

通过observer这个方法,我们把对象a里面的所有property进行了劫持,在对property进行get和set的时候我们就可以做自己想做的事情了,比如说进行标记的添加之类的,当然这里只是简单的实现,在vue中为了能够更深度的监听数组的变化vue重写了数组的方法。

  const extendedArr = Object.create(Array.prototype)
    //重写这几个方法,用Object.assign把新的方法混入到Array.prototype上
    const methods = ["push", "pop", "shift", "splice", "sort", "reverse"]
    methods.forEach(method => {
        const oldm = Array.prototype[method]
        const newm = function (...args) {
            oldm.apply(this, args)
            console.log(`劫持方法,爱干嘛干嘛`)
        }
        extendedArr[method] = newm
    })

二、用Proxy实现数据劫持

1.原理

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。

一个代理类的简单例子:

  let student = {
        name: "小红",
        age: 15
    }
    student = new Proxy(student, {
        set(obj, prop, value) {
            if (prop == "age" && typeof value !== "number") {
                throw new Error("年龄必须是数字")
            }
            Reflect.set(...arguments)
        },
        get(obj, prop) {
            console.log("get操作");
            return Reflect.get(...arguments)
        }
    })

上面代码把student这个对象进行了代理,判断一下age属性,当age不是number时候就报错。

1.在VUE3中实现响应式核心变成了代理模式

当把一个普通的 JavaScript 对象作为 data 选项传给应用或组件实例的时候,Vue 会使用带有 getter 和 setter的处理程序遍历其所有 property 并将其转换为 Proxy 。这是 ES6 仅有的特性,但是我们在 Vue 3 版本也使用了 Object.defineProperty 来支持 IE 浏览器。两者具有相同的 Surface API,但是 Proxy 版本更精简,同时提升了性能。

  let a = {
        name: "小红",
        age: 12,
        oinfo: {
            school: "大学",
            hobby: ["football", "pingpang"]
        },
    }
  function observerP(data) {
        if (!data && Object.prototype.toString.call(data) !== '[object, Object]') {
            return
        }

        Object.keys(data).forEach(key => {
            let currentItem = data[key]
            if (typeof currentItem == "object") {
                observerP(currentItem)
                data[key] = new Proxy(currentItem, {
                    set(obj, prop, value) {
                        console.log("调用了set");
                        return Reflect.set(...arguments);
                    }
                })
            } else {
                Object.defineProperty(data, key, {
                    set(value) {
                        console.log("调用了set");
                        currentItem = value
                    }
                })
            }
        })
    }
    observerP(a)

当我们a.oinfo.hobby.push(“fff”)向数组中追加数据时,依然被set函数捕获,所以说Proxy支持代理数组的变化。

是不是很简单啊?喜欢的小伙伴留言点赞关注吧!

相关文章
|
8月前
|
安全 Shell PHP
渗透攻击实例-文件上传导致任意代码执行
渗透攻击实例-文件上传导致任意代码执行
|
存储 缓存 JavaScript
从JavaScript发起同步多行Rowhammer攻击
本文构建了SMASH(Synchronized MAny-Sided Hammering),这是一种在现代 DDR4 系统上从 JavaScript 成功触发 Rowhammer 位翻转的技术。 为了发起有效的攻击,SMASH 利用缓存替换策略的高级知识为基于驱逐的多行Rowhammer 生成最佳访问模式。 为了取消对大型物理连续内存区域的要求,SMASH 将n行 Rowhammer 分解为多个双行对,使用切片着色来识别它们。 最后,为了绕过 DRAM TRR 缓解措施,SMASH 仔细安排缓存命中和未命中,以成功触发同步的多行 Rowhammer 位翻转。
70 0
|
前端开发
前端学习案例2-数据劫持2proxy
前端学习案例2-数据劫持2proxy
55 0
前端学习案例2-数据劫持2proxy
|
存储 Web App开发 编解码
浏览器原理 32 # 跨站脚本攻击(XSS):为什么Cookie中有HttpOnly属性?
浏览器原理 32 # 跨站脚本攻击(XSS):为什么Cookie中有HttpOnly属性?
114 0
浏览器原理 32 # 跨站脚本攻击(XSS):为什么Cookie中有HttpOnly属性?
|
存储 JavaScript 安全
跨站脚本攻击(XSS)和跨站请求伪造(CSRF)是什么?区别是什么?底层原理是什么?
跨站脚本攻击(XSS)和跨站请求伪造(CSRF)是什么?区别是什么?底层原理是什么?
626 0
|
JavaScript 搜索推荐 应用服务中间件
怎么防止网站被别人使用iframe框架恶意调用
发生歹意网站的危害关于新站来说,是比较大的。那我们应该怎样防止别人歹意镜像我们的网站呢?首要得了解一下镜像网站的原理,镜像网站大约需求以下的几个条件:你的网站运用了独立IP.当然,独立ip对一个网站来说,是好的,可以和其他网站差异开来,成为镜像网站的条件之一,只是独立ip的一个小缺陷。
116 0
怎么防止网站被别人使用iframe框架恶意调用
|
JavaScript API
数据劫持2
Reflect和Object来说,框架封装更需要健壮性强的Reflect Proxy处理响应式数据更具优势 Object.defineProperty那些缺点在vue框架里也提供了相应的api进行解决
141 0
数据劫持2
数据劫持
对属性的读取和修改拦截简单来说就是数据的任何变化都要能监测到,这样才能根据数据变化做对应操作
310 0
数据劫持