Jun 01, 2021 Article blog
The product manager was by his side, and the change in demand could not escape. Test sister squinting, there must be more bugs tonight.
It is reported that the official version of
Vue3.0
will be released this month (August), from the release to the official into the formal project, still need a certain transition period, but we can not wait until
Vue3
formally into the project when to learn, learn ahead of time, let you quickly grasp
Vue3.0
promotion and salary increase to marry Bai Fumei on it.
Before you learn
Vue3
however, you need to understand
Proxy
which is the basis for
Vue3.0
to implement two-way data binding.
As a single steel straight male programmer, Xiao Wang recently gradually liked the front-end sister, but, he and the front-end sister is not familiar, so decided to entrust with the front-end sister more familiar
UI
sister to help build a bridge lead for themselves. X
iao Wang then asked
UI
little sister to eat a big meal, and then took out a love letter entrusted to it to the front desk sister, love letter written on
我喜欢你,我想和你睡觉
worthy of steel straight man. B
ut this writing is certainly no play,
UI
little sister can eat people's mouth short, so help changed the love letter, changed to
我喜欢你,我想和你一起在晨辉的沐浴下起床
and then handed over to the front desk sister.
Although it is not clear whether there is a matchmaking success ah, but this story tells us that Xiao Wang live a single dog.
In fact, the above is a more typical example of the agent model, Xiao Wang wants to send love letters to the front desk sister, because not familiar so
UI小姐姐
UI
small sister equivalent to agent, instead of Xiao Wang completed the love letter thing.
From the example above, let's consider
Vue
data response principles, such as the following code
const xiaowang = {
love: '我喜欢你,我想和你睡觉'
}
// 送给小姐姐情书
function sendToMyLove(obj) {
console.log(obj.love)
return '流氓,滚'
}
console.log(sendToMyLove(xiaowang))
If there is no
UI
little sister instead of a love letter, the ending is tragic, think of the two-way binding of
Vue2.0
the property
get
that is monitored through
Object.defineProperty
set
method for two-way binding, this
Object.defineProperty
is equivalent to the little sister of
UI
const xiaowang = {
loveLetter: '我喜欢你,我想和你睡觉'
}
// UI小姐姐代理
Object.defineProperty(xiaowang,'love', {
get() {
return xiaowang.loveLetter.replace('睡觉','一起在晨辉的沐浴下起床')
}
})
// 送给小姐姐情书
function sendToMyLove(obj) {
console.log(obj.love)
return '小伙子还挺有诗情画意的么,不过老娘不喜欢,滚'
}
console.log(sendToMyLove(xiaowang))
Although it is still a tragic story, because the success rate of sending Mercedes may be higher.
But as we can see,
Object.defineproperty
allows you to intercept an object's existing properties and then do something extra.
In
Vue2.0
two-way data binding is to listen for every property of an object through
Object.defineProperty
and then in
get
set
method, the data response is achieved by publishing the subscriber pattern, but there are some flaws, such as listening only to existing properties, there is nothing you can do to add deleted properties, and you can't listen for changes in the array, so replace it with a more powerful proxy in Vue
Proxy
Vue3.0
(Recommended tutorial: Vue 2 tutorial)
Proxy
is a new feature ofES6
that allows you to proxy methods that blockjs
operations.
For example, we can rewrite the love letter plot above through
Proxy
const xiaowang = {
loveLetter: '我喜欢你,我想和你睡觉'
}
const proxy = new Proxy(xiaowang, {
get(target,key) {
if(key === 'loveLetter') {
return target[key].replace('睡觉','一起在晨辉的沐浴下起床')
}
}
})
// 送给小姐姐情书
function sendToMyLove(obj) {
console.log(obj.loveLetter)
return '小伙子还挺有诗情画意的么,不过老娘不喜欢,滚'
}
console.log(sendToMyLove(proxy))
Use
Object.defineProperty
and
Proxy
to refine the following code logic, respectively.
function observe(obj, callback) {}
const obj = observe(
{
name: '子君',
sex: '男'
},
(key, value) => {
console.log(`属性[${key}]的值被修改为[${value}]`)
}
)
// 这段代码执行后,输出 属性[name]的值被修改为[妹纸]
obj.name = '妹纸'
// 这段代码执行后,输出 属性[sex]的值被修改为[女]
obj.name = '女'
Looking at the above code, I hope you can first implement the following, below we use
Object.defineProperty
and
Proxy
respectively to implement the above logic.
Object.defineProperty
/**
* 请实现这个函数,使下面的代码逻辑正常运行
* @param {*} obj 对象
* @param {*} callback 回调函数
*/
function observe(obj, callback) {
const newObj = {}
Object.keys(obj).forEach(key => {
Object.defineProperty(newObj, key, {
configurable: true,
enumerable: true,
get() {
return obj[key]
},
// 当属性的值被修改时,会调用set,这时候就可以在set里面调用回调函数
set(newVal) {
obj[key] = newVal
callback(key, newVal)
}
})
})
return newObj
}
const obj = observe(
{
name: '子君',
sex: '男'
},
(key, value) => {
console.log(`属性[${key}]的值被修改为[${value}]`)
}
)
// 这段代码执行后,输出 属性[name]的值被修改为[妹纸]
obj.name = '妹纸'
// 这段代码执行后,输出 属性[sex]的值被修改为[女]
obj.name = '女'
Proxy
function observe(obj, callback) {
return new Proxy(obj, {
get(target, key) {
return target[key]
},
set(target, key, value) {
target[key] = value
callback(key, value)
}
})
}
const obj = observe(
{
name: '子君',
sex: '男'
},
(key, value) => {
console.log(`属性[${key}]的值被修改为[${value}]`)
}
)
// 这段代码执行后,输出 属性[name]的值被修改为[妹纸]
obj.name = '妹纸'
// 这段代码执行后,输出 属性[sex]的值被修改为[女]
obj.name = '女'
From the two different implementations above, we can generally understand the use of
Object.defineProperty
and
Proxy
but when new properties are added to an object, the difference comes out, for example
// 添加编程网站
obj.gzh = 'W3Cschool编程狮'
You can't listen for new properties with
Object.defineProperty
but you can listen to them with
Proxy
Comparing the two pieces of code above, you can see the following differences
Object.defineProperty
listens to each property of an object, while
Proxy
listens to the object itself
Object.defineProperty
requires traversing every property of an object, which can have an impact on performance
Proxy
can also listen to new properties, but
Object.defineProperty
cannot.
Proxy
for the first time
In
MDN
Proxy
about
Proxy
is described as follows: Objects are used to define custom behaviors for basic operations, such as property lookups, assignments, enumerations, function calls, and so on. W
hat do you mean?
Proxy
is like an interceptor, it can read the properties of an object, modify the properties of an object, get a list of object properties, block the default behavior above the object through
for in
loops, and so on, and then customize these behaviors ourselves, such as
set
in the example above, we intercept the default
set
and then add callback function
set
to the custom set
Proxy
syntax format of Proxy is as follows
/**
* target: 要兼容的对象,可以是一个对象,数组,函数等等
* handler: 是一个对象,里面包含了可以监听这个对象的行为函数,比如上面例子里面的`get`与`set`
* 同时会返回一个新的对象proxy, 为了能够触发handler里面的函数,必须要使用返回值去进行其他操作,比如修改值
*/
const proxy = new Proxy(target, handler)
In the example above, we've used the
get
and
set
methods provided in
handler
so let's take a look at the methods inside
handler
The methods inside
handler
can have the following thirteen, each corresponding to one or more of the operations against
proxy
proxy object
handler.get
When you read the properties inside an object through
proxy
you enter the
get
hook function
handler.set
When you set a modified property for an object through
proxy
you enter the
set
hook function
handler.has
has
is
in
when you use in to determine whether a property is inside a
proxy
proxy object, for example
const obj = {
name: '子君'
}
console.log('name' in obj)
handler.deleteProperty
When you use
delete
to remove properties from an object, you enter the deleteProperty' hook function
handler.apply
When
proxy
listens to a function, when it is called, it enters the
apply
hook function
handle.ownKeys
When you get information about an object through
Object.getOwnPropertyNames
Object.getownPropertySymbols
Object.keys
Reflect.ownKeys
you enter the hook function
ownKeys
handler.construct
When using the
new
operator, the hook function of
construct
is entered
handler.defineProperty
This hook function is entered when the property modifier is modified using
Object.defineProperty
handler.getPrototypeOf
When you read the prototype of an object, you enter the hook function
handler.setPrototypeOf
When you prototype an object, you enter the hook function
handler.isExtensible
Enter this hook function when
Object.isExtensible
is used to determine whether an object can add new properties
handler.preventExtensions
Enter this hook function when you set the object through
Object.preventExtensions
that the object cannot modify the new property
handler.getOwnPropertyDescriptor
This action is triggered when you get a description of the property of a proxy object, such as entering the hook function when you execute
Object.getOwnPropertyDescriptor(proxy, "foo")
Proxy
provides 13 ways to block object operations, and this article focuses on some of the more important instructions in
Vue3
and the rest of the recommendations can be read directly by
MDN
about
Proxy
When you read the properties inside an object through
proxy
you enter theget
hook function
When we read a property from a
proxy
proxy, the
get
hook function is triggered,
get
as follows
/**
* target: 目标对象,即通过proxy代理的对象
* key: 要访问的属性名称
* receiver: receiver相当于是我们要读取的属性的this,一般情况
* 下他就是proxy对象本身,关于receiver的作用,后文将具体讲解
*/
handle.get(target,key, receiver)
We often have the need to encapsulate
axios
in our work, and during the encapsulation process, we also need to encapsulate request exceptions, such as different status codes that return different exception information, as follows:
// 状态码提示信息
const errorMessage = {
400: '错误请求',
401: '系统未授权,请重新登录',
403: '拒绝访问',
404: '请求失败,未找到该资源'
}
// 使用方式
const code = 404
const message = errorMessage[code]
console.log(message)
But there is a problem, there are a lot of status codes, we can not be every status code to enumerate out, so for some abnormal status codes, we hope to be able to carry out a unified prompt, such as prompts for
系统异常,请联系管理员
this time you can use
Proxy
to proxy error messages
// 状态码提示信息
const errorMessage = {
400: '错误请求',
401: '系统未授权,请重新登录',
403: '拒绝访问',
404: '请求失败,未找到该资源'
}
const proxy = new Proxy(errorMessage, {
get(target,key) {
const value = target[key]
return value || '系统异常,请联系管理员'
}
})
// 输出 错误请求
console.log(proxy[400])
// 输出 系统异常,请联系管理员
console.log(proxy[500])
set
is triggered when you assign a value to a property inside an object
When you assign a value to a property inside an object, the
set
triggered, and the
set
function is structured as follows
/**
* target: 目标对象,即通过proxy代理的对象
* key: 要赋值的属性名称
* value: 目标属性要赋的新值
* receiver: 与 get的receiver 基本一致
*/
handle.set(target,key,value, receiver)
A system needs to enter a series of values for data statistics, but when entering values, there may be some outliers that may be entered, and these outliers need to be processed at the time of entry, such as values greater than
100
converted to
100
values less than
0
converted to
0
at which point the
set
of
proxy
can be used to process the data at the time of assignment
const numbers = []
const proxy = new Proxy(numbers, {
set(target,key,value) {
if(value < 0) {
value = 0
}else if(value > 100) {
value = 100
}
target[key] = value
// 对于set 来说,如果操作成功必须返回true, 否则会被视为失败
return true
}
})
proxy.push(1)
proxy.push(101)
proxy.push(-10)
// 输出 [1, 100, 0]
console.log(numbers)
Vue2.0
When using
Vue2.0
you often need to call
$set
when adding new properties to an object because
Object.defineProperty
can only listen for existing properties, and new properties cannot be monitored, and
$set
is equivalent to manually adding properties to an object before triggering a data response.
But for
Vue3.0
because
Proxy
is used, new properties can be heard in his
set
hook function, so you no longer need to use
$set
const obj = {
name: '子君'
}
const proxy = new Proxy(obj, {
set(target,key,value) {
if(!target.hasOwnProperty(key)) {
console.log(`新增了属性${key},值为${value}`)
}
target[key] = value
return true
}
})
// 新增 公众号 属性
// 输出 新增了属性gzh,值为前端有的玩
proxy.gzh = '前端有的玩'
has
in
when you use in to determine whether a property is inside theproxy
proxy object
/**
* target: 目标对象,即通过proxy代理的对象
* key: 要判断的key是否在target中
*/
handle.has(target,key)
In general, when we declare private properties in
js
we
_
with the name of the properties, for which external calls are not required, so if it is best to hide them, then it is possible to return
false
when
has
to determine whether a property is in the object and false if it
_
with
const obj = {
publicMethod() {},
_privateMethod(){}
}
const proxy = new Proxy(obj, {
has(target, key) {
if(key.startsWith('_')) {
return false
}
return Reflect.get(target,key)
}
})
// 输出 false
console.log('_privateMethod' in proxy)
// 输出 true
console.log('publicMethod' in proxy)
When you use
delete
to remove properties from an object, you enter the deleteProperty' interceptor
/**
* target: 目标对象,即通过proxy代理的对象
* key: 要删除的属性
*/
handle.deleteProperty(target,key)
There is now an object of user information that is only allowed to be viewed for some user information, but cannot be deleted or modified, for which
Proxy
allows you to block properties that cannot be deleted or modified and throw exceptions, as follows
const userInfo = {
name: '子君',
gzh: '前端有的玩',
sex: '男',
age: 22
}
// 只能删除用户名和公众号
const readonlyKeys = ['name', 'gzh']
const proxy = new Proxy(userInfo, {
set(target,key,value) {
if(readonlyKeys.includes(key)) {
throw new Error(`属性${key}不能被修改`)
}
target[key] = value
return true
},
deleteProperty(target,key) {
if(readonlyKeys.includes(key)) {
throw new Error(`属性${key}不能被删除`)
return
}
delete target[key]
return true
}
})
// 报错
delete proxy.name
Vue2.0
In fact, similar to the problem solved
$set
Vue2.0
cannot listen for property deletions, so
$delete
for deleting properties, but for
Proxy
you can listen for deletions, so you no longer need to use
$delete
Above, we mentioned that
Proxy
handler
provides thirteen functions, and above we list the three most commonly used, each of which is basically the same, such as
ownKeys
when through
Object.getOwnPropertyNames
Object.getownPropertySymbols
Object.keys
Reflect.ownKeys
go to the hook function
ownKeys
when they go to get information about an object, and with this we can protect properties that we don't look like exposed, such as those that generally convention that the beginning of
_
is a private property. S
o when you use
Object.keys
to get all
key
of an object, you can mask
_
the properties that begin with .
For the remaining properties, we recommend that you take a closer look at the introduction in
MDN
Above, we get the value of the property or modify the value of the property by directly manipulating
target
but in fact
ES6
already provides us with the
API
for calling the default behavior of the object inside
Proxy
that is,
Reflect
Like the code below
const obj = {}
const proxy = new Proxy(obj, {
get(target,key,receiver) {
return Reflect.get(target,key,receiver)
}
})
You might see that the code above is no different from the way you use
target[key]
directly, but in fact
Reflect
to make the operation above
Object
more regulated, for example, we have to determine whether a
prop
is in an object, which is usually used
in
, that is
const obj = {name: '子君'}
console.log('name' in obj)
But the above operation is a commanding syntax that can be transformed into a functional syntax by
Reflect
making it more standard
Reflect.has(obj,'name')
In addition to
has
get
in fact, a total of thirteen static methods are provided above
Reflect
which corresponds to the 13 methods above
handler
of
Proxy
and by combining
Reflect
Proxy
the default operations above the object can be intercepted, which of course falls within the scope of functional metaprogramming.
(Recommended micro-class: Vue 2.x micro-class)
Some students may wonder, I won't
Proxy
and
Reflect
can't learn
Vue3.0
U
nderstanding this doesn't affect learning
Vue3.0
but it's important to understand
Vue3.0
in depth. F
or example, people often ask when using
Vue2
why hasn't the interface changed after I've modified the values through the index?
When you learn about the ways and limitations of
Object.defineProperty
are used, you'll suddenly realize that this is the case.
Source: The front end is a bit of a game
Article source link: mp.weixin.qq.com/s/JQDA6bP805xuN-tzuimtAA
Author: Front-end hitter
The above is about learning Vue 3.0, you need to understand the relevant introduction of Proxy, I hope to help you.