Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >用Proxy写几个Demo

用Proxy写几个Demo

作者头像
kifuan
发布于 2022-10-24 08:28:07
发布于 2022-10-24 08:28:07
25000
代码可运行
举报
文章被收录于专栏:随便写写-kifuan随便写写-kifuan
运行总次数:0
代码可运行

源码

点击这里前往Github获取本文源码。

背景

本文是根据上文所介绍的方法,以及阮一峰大大的文章写几个小Demo,这里的代码都是我自己看了一遍需求敲出来的,不存在直接复制黏贴的情况,请放心。

数组负数索引

众多语言都支持数组的索引为负数,就像这段Python代码一样:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
arr = [1, 2, 3]
print(arr[-1])
# 3

我们可以通过Proxy让JS也支持这一操作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function getPositiveKey(key, length) {
    const index = Number(key)
    if (index < 0) {
        key = String(index + length)
    }
    return key
}

function negativeArray(arr) {
    return new Proxy(arr, {
        get(target, key) {
            key = getPositiveKey(key, target.length)
            return Reflect.get(target, key)
        },
        set(target, key, value) {
            key = getPositiveKey(key, target.length)
            return Reflect.set(target, key, value)
        }
    })
}

const arr = negativeArray([5, 6, 7])

console.log(arr[-1])
// 7

console.log(arr[1])
// 6

注意,尽管我们用arr[-1],但是传进去的key还是会被转为字符串,所以需要一步转换。

同时,我们在getPositiveKey中,为了符合Reflect.get函数的参数类型要求,把计算出来的索引也转换成了字符串,不过这里是无所谓的,因为传给Reflect后它会自己进行一个转换。

数字链式调用

下面代码的目的是:

  • 如果获取的是value,就返回数字本身。
  • 如果获取的东西在Math中存在,就调用它,并且把结果再包装成我们的代理对象。
  • 都不存在就返回一个undefined,因为我这里是一个小Demo,就不做太多的处理了。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function proxy(n) {
    return new Proxy({ n }, {
        get(target, key) {
            if (key === 'value') {
                return target.n
            }

            if (key in Math) {
                return proxy(Math[key](target.n))
            }
            
            return undefined
        }
    })
}

console.log(proxy(64).sqrt.log2.value)
// 3

上述操作就是先把64开根,结果是8; 再取以2为底的对数,结果是3。

注意到这里把数字包了一层对象,因为Proxy是不支持代理基本类型的。

DOM生成器

此Demo的Codepen地址,可以在线体验一下。

每次都写document.createElement然后dom.appendChild实在是太煎熬了,所以有了这样一个例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const dom = new Proxy({}, {
    get(_, tag) {
        return (...children) => {
            const el = document.createElement(tag)
            children.forEach(child => {
                if (typeof child === 'string') {
                    child = document.createTextNode(child)
                }
    
                if (child instanceof Node) {
                    // 所有DOM都继承了Node
                    el.appendChild(child)
                } else {
	                // 如果child不是Node就认为它是属性对象
                    Object.entries(child).forEach(([key, value]) => {
                        el.setAttribute(key, value)
                    })
                }
            })

            return el
        }
    }
})

const root = document.getElementById('root')
const el = dom.p(
    dom.span('Hello! '),
    'This is ',
    dom.a('my website', { href: 'https://kifuan.top', target: '_blank' }),
)
root.appendChild(el)

别忘了在HTML里带上一个:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div id="root"></div>

数据双向绑定

Vue里面最香的就是这玩意,为表单数据获取验证省出了巨大时间,那么在这里通过Proxy的知识我们也可以实现一个简单的双向绑定。

外部链接

如果只是把这些链接写在开头很容易被忽略掉,所以我这里单独摘出来一个板块让下面这些更醒目

  • 视频 我录了一个视频从头开始实现这个功能,过程中有说到怎么去思考这个问题的实现方法,这里去B站看
  • Codepen 本Demo的Codepen地址,可以在线体验。

需求

只要我们这么写

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<input type="text" data-value="foo" data-update="foo">
<p data-value="foo"></p>

当上方输入的时候下方就会实时更新,也就是说:

  • data-value指的是当数据更新时被实时更新
  • data-update指的是数据会被这个元素更新

实现

Talk is cheap. Show me the code.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
'use strict'

function bindUpdates(setProp) {
    return Array.from(document.querySelectorAll('*[data-update]'))
        .reduce((pre, cur) => {
            const key = cur.dataset.update
            cur.addEventListener('keyup', () => {
                setProp(key, cur.value)
            })
            // 一个key只会被一个DOM更新
            return { ...pre, [key]: cur }
        }, {})
}

function bindValues() {
    return [...document.querySelectorAll('*[data-value]')]
        .reduce((pre, cur) => {
            const key = cur.dataset.value
            // 一个key会被多个DOM读取
            pre[key] ||= []
            pre[key].push(cur)
            return pre
        }, {})
}

function bind() {
    const values = bindValues()

    const updates = bindUpdates((key, value) => {
        data[key] = value
    })

    const data = new Proxy({}, {
        set(_, key, value) {
            values[key].forEach(el => {
                if (el.value !== undefined) {
                    el.value = value
                } else {
                    el.innerText = value
                }
            })
            // 表示设置成功
            return true
        },

        get(_, key) {
            return updates[key].value
        }
    })

    return data
}

const data = bind()

之后在HTML里这么写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<h1>双向绑定</h1>
<input type="text" data-value="account" data-update="account" placeholder="账号"><br><br>
<input type="text" data-value="password" data-update="password" placeholder="密码">
<p>账号: <span data-value="account"></span></p>
<p>密码: <span data-value="password"></span></p>

<button onclick="data.account = ''">清空账号</button>
<button onclick="data.password = ''">清空密码</button>

就可以达到预期效果了,想要预览可以到Codepen里面查看,在这里再放一个链接

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Proxy
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
小小杰啊
2022/12/21
2.5K0
ES6系列十四:Proxy
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。
用户8921923
2022/10/24
1.4K0
关于回调
爱学习的前端歌谣
2023/10/18
3800
关于回调
社招前端二面必会手写面试题总结4
题目描述: setInterval 用来实现循环定时调用 可能会存在一定的问题 能用 setTimeout 解决吗
helloworld1024
2023/01/06
8190
那些年面挂的js手写题
arr = {a:1, b:3}, {a:2, b:3, c:4}, {a:3},求和
helloworld1024
2022/11/07
7710
玩转ES6(二)-Object.defineProperty和Proxy代理
Object.defineProperty这个并不是es6的语法,这个是给一个对象,添加属性,但是目前框架很多实用这个方法,来实现数据劫持,也就是数据双向绑定
前端迷
2019/12/03
1.9K0
关于原型
爱学习的前端歌谣
2023/10/18
1530
关于原型
2023前端必会手写面试题整理1
我们说迭代器对象全凭迭代器生成函数帮我们生成。在ES6中,实现一个迭代器生成函数并不是什么难事儿,因为ES6早帮我们考虑好了全套的解决方案,内置了贴心的 生成器 (Generator)供我们使用:
helloworld1024
2023/01/03
5100
前端二面必会手写面试题
script标签不遵循同源协议,可以用来进行跨域请求,优点就是兼容性好但仅限于GET请求
helloworld1024
2022/12/20
6420
阿里前端面试问到的vue问题
虽然文档不建议在应用中直接使用 mixin,但是如果不滥用的话也是很有帮助的,比如可以全局混入封装好的 ajax 或者一些工具函数等等。
bb_xiaxia1998
2022/10/29
9460
腾讯二面vue面试题总结
对象内部通过 defineReactive 方法,使用 Object.defineProperty 来劫持各个属性的 setter、getter(只会劫持已经存在的属性),数组则是通过重写数组7个方法来实现。当页面使用对应属性时,每个属性都拥有自己的 dep 属性,存放他所依赖的 watcher(依赖收集),当属性变化后会通知自己对应的 watcher 去更新(派发更新)
bb_xiaxia1998
2022/11/18
7670
Vue.js 双向数据绑定基本实现认知
对每个人而言,真正的职责只有一个:找到自我。然后在心中坚守其一生,全心全意,永不停息。所有其它的路都是不完整的,是人的逃避方式,是对大众理想的懦弱回归,是随波逐流,是对内心的恐惧 ——赫尔曼·黑塞《德米安》
山河已无恙
2024/05/10
2680
Vue.js 双向数据绑定基本实现认知
vue 随记(2):轮子是如何造成的
为了预测恒纪元和乱纪元,故事里的冯诺依曼设计了人列计算机,不需要三千万个数学家。只需要三千万忠实的士兵,每个个体订阅相关单元的变化,忠实地反映状态即可。
一粒小麦
2020/07/16
8500
剖析Vue原理&实现双向绑定MVVM
本文能帮你做什么? 1、了解vue的双向数据绑定原理以及核心代码模块 2、缓解好奇心的同时了解如何实现双向绑定 为了便于说明原理与实现,本文相关代码主要摘自vue源码, 并进行了简化改造,相对较简陋,并未考虑到数组的处理、数据的循环依赖等,也难免存在一些问题,欢迎大家指正。不过这些并不会影响大家的阅读和理解,相信看完本文后对大家在阅读vue源码的时候会更有帮助 本文所有相关代码均在github上面可找到 https://github.com/DMQ/mvvm 相信大家对mvvm双向绑定应该都不陌生了,一言不
小时光
2018/01/29
3.2K0
从 Proxy 到 Vue3 响应式
最近想再回顾下 Proxy 这一部分的内容, 顺便也看看他的应用场景, 刚好在 Vue3 的响应式 API 中有使用, 所以就结合着一起复习下, 顺便总结记录一番. 如果只对 Vue3 的响应式感兴趣的, 可以直接跳到文章的第二部分.
BLUSE
2022/12/02
1.3K1
vue双向绑定原理
Vue双向绑定的原理 一、在讲vue双向绑定之前我们需要来了解下MVVM模式 MVVM(Model-View-ViewModel)是对 MVC(Model-View-Control)和 MVP(Model-View-Presenter)的进一步改进。
超级小可爱
2023/10/13
2490
vue双向绑定原理
牛客网js题库正解 (21-40题)
要求在Number对象的原型对象上添加"_isPrime"函数,该函数判断调用的对象是否为一个质数,是则返回true,否则返回false。
编程内马尔
2022/11/15
3110
19道高频vue面试题解答(上)
子组件不可以直接改变父组件的数据。这样做主要是为了维护父子组件的单向数据流。每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。如果这样做了,Vue 会在浏览器的控制台中发出警告。
bb_xiaxia1998
2022/10/10
1.3K0
几个非常有意思的javascript知识点总结
作为一名前端爱好者, 笔者利用空余时间研究了几个国外网站的源码,发现不管是库,还是业务代码,都会用到了一些比较有意思的API,虽然平时在工作中部分接触过,但是经过这次的研究,觉得很有必要总结一下,毕竟已经2020年了,是时候更新一下技术储备了,本文主要通过实际案例来带大家快速了解以下几个知识点:
徐小夕
2020/04/23
5960
几个非常有意思的javascript知识点总结
茶余饭后聊聊 Vue3.0 响应式数据那些事儿
"别再更新了,实在是学不动了"这句话道出了多少前端开发者的心声,"不幸"的是 Vue 的作者在国庆区间发布了 Vue3.0 的 pre-Aplha 版本,这意味着 Vue3.0 快要和我们见面了。既来之则安之,扶我起来我要开始讲了。Vue3.0 为了达到更快、更小、更易于维护、更贴近原生、对开发者更友好的目的,在很多方面进行了重构:
政采云前端团队
2019/12/20
9680
茶余饭后聊聊 Vue3.0 响应式数据那些事儿
相关推荐
Proxy
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验