前往小程序,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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C++】算法集锦(5):BFS算法
BFS算法和DFS算法属于图论算法的范畴,DFS在前面回溯中,可以去看一下。 BFS算法用于寻找两点之间的最短路径。
看、未来
2021/09/18
6710
BFS 算法框架套路详解
首先,你要说 labuladong 没写过 BFS 框架,这话没错,今天写个框架你背住就完事儿了。但要是说没写过 DFS 框架,那你还真是说错了,其实 DFS 算法就是回溯算法,我们前文 回溯算法框架套路详解 就写过了,而且写得不是一般得好,建议好好复习。
labuladong
2021/09/23
7440
【python刷题】广度优先搜索(BFS)
一般来说,BFS使用的数据结构是队列。 BFS模板 from collections import deque def BFS(start, target): q = deque() # 核心数据结构 visited = set() # 避免走回头路 q.append(start) # 将起点加入到队列 visited.add(start) step = 0 # 记录扩散的步数 while q is not None: s = len(q)
西西嘛呦
2021/02/05
1.1K0
算法学习记录
一、介绍 1、常见的数据结构 「队列」、「栈」这两种数据结构既可以使⽤链表也可以使⽤数组实现。⽤数组实现,就要处理扩容缩容的问题;⽤链表实现,没有这个问题,但需要更多的内存空间存储节点指针。 「图」的两种表⽰⽅法,邻接表就是链表,邻接矩阵就是⼆维数组。邻接矩阵判断连通性迅速,并可以进⾏矩阵运算解决⼀些问题,但是如果图⽐较稀疏的话很耗费空间。邻接表⽐较节省空间,但是很多操作的效率上肯定⽐不过邻接矩阵。 「散列表」就是通过散列函数把键映射到⼀个⼤数组⾥。⽽且对于解决散列冲突的⽅法,拉链法需要链表特性,操作
MiChong
2020/11/17
4600
BFS算法总结
要解决的问题,大体是在一副“图”中,找到从起点start 到 终点target 的最近距离。
艳龙
2021/12/16
3020
我写了一个模板,把 Dijkstra 算法变成了默写题
其实,很多算法的底层原理异常简单,无非就是一步一步延伸,变得看起来好像特别复杂,特别牛逼。
labuladong
2021/09/23
1.6K0
leetcode刷题(110)——752. 打开转盘锁
你有一个带有四个圆形拨轮的转盘锁。每个拨轮都有10个数字: ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’ 。每个拨轮可以自由旋转:例如把 ‘9’ 变为 ‘0’,‘0’ 变为 ‘9’ 。每次旋转都只能旋转一个拨轮的一位数字。
老马的编程之旅
2022/06/22
2560
初识广度优先搜索与解题套路
先来看看其中比较简单的数据结构 - 链表,它和数组类似,也是一个线性的结构,简单来说就是一条路径,你从头开始遍历,最终会将链表上面的节点都访问到,到达终点。
五分钟学算法
2019/10/09
6070
二、进阶数据结构
二叉树题目的递归解法可以分两类思路,第一类是遍历一遍二叉树得出答案,第二类是通过分解问题计算出答案,这两类思路分别对应着 回溯算法核心框架 和 动态规划核心框架。
阿东知识库
2024/09/03
1840
二、进阶数据结构
Python 算法基础篇:深度优先搜索( DFS )和广度优先搜索( BFS )
深度优先搜索( DFS )和广度优先搜索( BFS )是两种常用的图遍历算法,用于在图中搜索目标节点或遍历图的所有节点。本篇博客将介绍 DFS 和 BFS 算法的基本概念,并通过实例代码演示它们的应用。
小蓝枣
2023/07/22
3.1K0
搞定大厂算法面试之leetcode精讲21.树
树这种数据结构包括根节点root,左右节点,子树中又有父节点,子节点,兄弟节点,没有子节点的成为叶子节点,树分为二叉树和多叉树
全栈潇晨
2021/12/06
5680
队列+宽搜
给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
用户11369558
2024/12/24
1250
队列+宽搜
​LeetCode刷题实战102:二叉树的层序遍历
算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !
程序员小猿
2021/01/20
2990
​LeetCode刷题实战102:二叉树的层序遍历
我的刷题经验总结
两年前刚开这个公众号的时候,我写了一篇 学习数据结构和算法的框架思维,现在已经 5w 多阅读了,这对于一篇纯技术文来说是很牛逼的数据。
labuladong
2021/10/14
8030
java算法刷题02——深度优先搜索与广度优先搜索
给一个01矩阵,1代表是陆地,0代表海洋, 如果两个1相邻,那么这两个1属于同一个岛。我们只考虑上下左右为相邻。 岛屿: 相邻陆地可以组成一个岛屿(相邻:上下左右) 判断岛屿个数。 例如: 输入 [ [1,1,0,0,0], [0,1,0,1,1], [0,0,0,1,1], [0,0,0,0,0], [0,0,1,1,1] ] 对应的输出为3 示例1 输入:
半旧518
2022/10/26
6660
java算法刷题02——深度优先搜索与广度优先搜索
算法:树
在之前的内容中我们学习了链表的这一基础数据结构,单链表是其中的一种,结构形式如下所示:
用户3578099
2022/03/15
7530
算法:树
数据结构与算法——BFS(广度优先搜索)
广度优先搜索(Breadth-First Search,简称BFS)是一种遍历或搜索树和图的算法,也称为宽度优先搜索,BFS算法从图的某个节点开始,依次对其所有相邻节点进行探索和遍历,然后再对这些相邻节点的相邻节点进行探索,直到遍历完所有的节点。BFS算法使用队列来辅助实现,将起始节点放入队列中,然后依次取出队列中的节点,访问其相邻节点,并将其加入队列。这样可以保证从起始节点出发,依次按照距离顺序遍历节点。BFS常用于寻找最短路径,因为它按照从起点到每个节点的距离来探索节点。
摆烂小白敲代码
2024/09/23
3380
数据结构与算法——BFS(广度优先搜索)
开发成长之路(16)-- 算法小抄:思维跃迁
复杂度分析: 在一般情况下,每一个数都要与之后的数进行匹配,所以匹配次数将与数据量n挂钩,又由于每轮匹配都要进行(n-1)次比较,所以平均时间复杂度为O(n^2)。
看、未来
2021/09/18
3580
几道和「广度优先搜索」有关的算法面试题
2、从 V0 出发,访问 V0 的各个 未被访问 的邻接点 W1, W2,…, Wk ;然后依次从 W1, W2,…, Wk 出发访问各自未被访问的邻接点;
五分钟学算法
2019/05/06
6980
几道和「广度优先搜索」有关的算法面试题
几乎刷完了力扣所有的树题,我发现了这些东西。。。
先上下本文的提纲,这个是我用 mindmap 画的一个脑图,之后我会继续完善,将其他专题逐步完善起来。
Nealyang
2020/12/03
3.3K0
几乎刷完了力扣所有的树题,我发现了这些东西。。。
推荐阅读
相关推荐
【C++】算法集锦(5):BFS算法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验