proxy模拟实现vue.js的双向绑定
肾么是Proxy
proxy即事件代理,就像中间商,可以代替我们进行一些事件操作。就像我们要去买卖二手物品,但是我们害怕买卖的过程被人欺骗,这时候我们就会找中间商进行操作。而proxy正是这个中间商!
如果你要问我要使用proxy进行操作,那你是不知道proxy究竟有多香!!!
Proxy的快超乎你想象
众所周知,时间复杂度是衡量一个程序好不好极其重要的一个因素。在这个硬件内存不要钱的时代,只要你的代码够快,你就程序就够强!
你要问我Proxy有多快?我给你实战一个大数阶乘看一看吧!
// 阶乘函数
function demo(n) {
return n == 1?1:n*demo(n-1)
}
//不使用代理模式
console.time('demo');
demo(10000);
console.timeEnd('demo');
let proxy = new Proxy(demo, {
// 传入函数、环境、参数
apply(func, obj, argus) {
console.time('demo2');
// console.log(argus);
func(10000)
console.timeEnd('demo2');
}
});
//使用代理模式
proxy({},[5]);
上图中demo是不使用代理模式的定时器,demo2是使用了代理模式的定时器,可以看到速度真的是大大滴提升!
如何使用代理模式
在代理模式中会使用到大量的访问器,这里我也就顺带写一下最基本的访问器使用吧!
const user = {
data: {
name: '江河',
age:18
},
set age(value) {
console.log('访问器生效了');
if (typeof value != 'number' || value < 10 || value > 100) {
throw new Error('格式错误')
}
// 格式没问题设置值
this.data.age = value;
},
get age() {
// 返回值
return this.data.age +'岁'
}
}
user.age = 19;
console.log(user.age); // 19岁
用get/set+属性名来进行定义读写属性就是访问器了。很简单吧,上面我们最后一行获取年龄的时候,按照以往是应该获取18
的,但是结果是18岁
,这是因为我们使用了访问器,get age()重新定义了获取age
属性的方法,在获取的时候自动加上了一个岁。这就是访问器的作用。而且访问器的优先级是大于默认操作的,所以定义后进行属性操作会默认调用访问器。
好的,我们接着聊Proxy吧!
"use strict"
let user = {
name: "江河",
age:18
}
// 创建代理对象
// 传入需要代理的对象
// 创建代理方法
const proxy = new Proxy(user, {
get(obj, key) {
// console.log(obj[key])
return obj[key]
},
set(obj, key, value) {
obj[key] = value;
// 严格模式是需要设置返回为true
return true;
}
});
// 通过代理获取了属性
console.log(proxy.age) // 18
proxy.name = 'jianghe';
console.log(proxy.name); // jianghe
在上面我们创建了一个代理对象,讲user
注入进去,然后使用访问器模式,拿到我们想读写的key
,然后使用访问器的方法进行读写操作。这里有一个小细节,在严格模式中set需要返回true
,不然系统就会送你一朵小红花,哦不,是小bug。
在这我们可以看到,已经实现了使用了proxy进行数据改变。接下来我们讲Proxy的操作提升亿点点!
proxy模拟实现vue.js的双向数据绑定
才刚看了一个简单的例子就要真刀真枪干了?没错,因为真的不难(内心狂呼“江河,我要下车,这根本不是去幼儿园的车!”,我“车门已经焊死了,想跑没门”)。
在这里我们用两个简单的input框来实现数据双向绑定,改变其中输入框的值,另一个输入框跟随进行改变。
其中思路也是极其简单的,只要我们设定一个对象容器,并将容器中一个属性作为后台数据,两个输入框绑定到一个属性上。然后在输入框上加上监听事件,只要有一个输入框完成输入一个字符就将容器中的值进行更新,然后再输出到两个容器上。没听错,就是这么简单!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text" v-model="title">
<input type="text" v-model="title">
<div>实现两个输入框的数据双向绑定</div>
<script>
function View(){
// 设置代理
// 代理设置{}作为容器存储数据
let proxy = new Proxy({},{
// 设置对象,参数
get(obj,item){},
set(obj, item,value){
// console.log(value)
// 找到所有的使用模型
// 遍历并更新值
document.querySelectorAll(`[v-model="${item}"]`).forEach(e=>{
e.value = value
})
}
})
this.init = function(){
// 设置绑定事件
// 找到所有的触发事件文本框
const model = document.querySelectorAll("[v-model]");
// 给所有文本框添加监听机制
model.forEach(item=>{
// 监听键盘弹起事件,即完成一个字符的输入
item.addEventListener('keyup',function(){
// console.log(1)
// 给容器的值设置为最新的值
proxy[this.getAttribute('v-model')] = this.value;
})
})
}
}
// new 出实例并运行方法
new View().init();
</script>
</body>
</html>
成果如下:
我是江河,前端实习生一枚,正在准备春招,欢迎各位大佬滴滴,文章如有不正之处敬请斧正!
转载自:https://juejin.cn/post/6954004611594190862