The responseful principle of vue.js relies on Object.defineProperty. Vue listens for changes in data by setting setter/getter methods for Object properties, and relies on getter methods for collection. Each setter method is an observer. Notify the subscriber to update the view when the data changes.
What does Vue do with Data?
index.html:
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.6.10/vue.min.js"></script>
</body>
Copy the code
main.js:
const Vue = window.Vue
const myData = {
n:0
}
new Vue({
data: myData,
template: `
{{n}}
`
}).$mount('#app')
setTimeout(() = > {
myData.n += 10
}, 0)
console.log(myData)
Copy the code
Console:
// {__ob__: we}
// n: (...)
// __ob__: we {value: {... }, dep: ce, vmCount: 1}
// get n: f ()
// set n: f (t)
// __proto__: Object
Copy the code
As we can see, myData is tampered with when passed to Vue.
ES6 getter/setter
Here is an example of using the new ES6 syntax:
let obj = {
firstName: 'Eden'.lastName: 'Sheng'.name() {
return this.firstName + this.lastName
}
}
console.log(obj.name())
//EdenSheng
Copy the code
The console can print EdenSheng
Using computed properties
- If we use the get method:
let obj = {
firstName: 'Eden'.lastName: 'Sheng'.get name() {
return this.firstName + this.lastName
}
}
console.log(obj.name)
//EdenSheng
Copy the code
You can use the obj.name attribute directly by using get. You can also print EdenSheng.
This is called a getter, and the key word is get, and it gets a value. Is defined as a function, but is used without parentheses.
- Set the name with set:
let obj = {
firstName: 'Eden'.lastName: 'Sheng'.get name() {
return this.firstName + this.lastName
},
set name(e) {
this.firstName = e[0]
this.lastName = e.slice(1)
}
}
obj.name = 'xy'
console.log(obj.name, `${obj.firstName}.${obj.lastName}`)
//xy x,y
Copy the code
Obj.name = ‘xy’ is equivalent to firing the set function. Setters are used to rewrite data.
Look at this object
So let’s see what obj is.
.console.log(obj)
// {firstName: "x", lastName: "y"}
// name: (...)
// firstName: "x"
// lastName: "y"
// get name: f name()
// set name: f name(e)
// __proto__: Object
Copy the code
conclusion
Vue wrapped and we wrote obj, n, and name are not real attributes; The browser displays (…) , indicates that n and name can be read and written, but they do not exist. Get and name are used to simulate read and write operations on them.
How do I operate on declared objects?
How do we define a new attribute for an already declared object?
useObject.defineProperty( )
Methods.
The object.defineProperty () method directly defines a new property on an Object, or modifies an existing property of an Object, and returns the Object.
grammar
Object.defineProperty(obj, prop, descriptor)
parameter
-
Obj: Object on which attributes are to be defined.
-
Prop: The name of the property to define or modify.
-
Descriptor: Attribute descriptor to be defined or modified.
The return value
The object passed to a function.
example
Define a new property n for the declared object data.
let data = {}
Object.defineProperty(data, 'n', {
value: 0
})
console.log(data)
// Print {n: 0}
Copy the code
The problem
When we have the requirement that n cannot be less than 0. But n doesn’t really exist. How do we determine that?
Sneak in a variable in data to store n.
let data = {}
data._n = 0
Object.defineProperty(data, 'n', {
get() {
return this._n
},
set(value) {
if (value < 0) return
this._n = value
}
})
console.log(data.n)
/ / 0
data.n = -1
console.log(data.n)
/ / 0
data.n = 1
console.log(data.n)
/ / 1
Copy the code
Here’s the problem: If you access and tamper with data._n directly from the outside, your judgment logic part won’t notice and it will cause chaos.
How to solve this problem? Use proxies and listeners.
Proxy/monitor
Using the agent
Proxies are also a design pattern that uses proxies to fulfill the above requirements. Construct a proxy function.
function proxy({ data }) {
const obj = {}
Object.defineProperty(obj, 'n', {
get() {
return data.n
},
set(value) {
if (value < 0) return
data.n = value
}
})
return obj
}
let dataProxy = proxy({ data: { n: 0}})console.log(dataProxy.n)
/ / 0
dataProxy.n = -1
console.log(dataProxy.n)
/ / 0
dataProxy.n = 1
console.log(dataProxy.n)
/ / 1
Copy the code
The function first declares an empty object, obj. When you read and write to dataProxy, the actual return value is obj, which is actually the return value of Data.
Thus, between them, a layer of proxy is implemented: OBJ. We only have one object exposed to the user or outside: obj.
Used to monitor
If you declare a reference at initialization, you can bypass the proxy and read and write directly.
let myData = {n: 0}
let dataProxy = proxy({data: myData})
...
console.log(dataProxy.n)
/ / 0
myData.n = -1
console.log(dataProxy.n)
// -1
Copy the code
Add listener Add listener for an object:
function proxy({ data }) {
// Store data.n in value
let value = data.n
// If n already exists, it will be overwritten automatically
delete data.n
Object.defineProperty(data, 'n', {
get() {
return value
},
set(newValue) {
if (newValue < 0) return
value = newValue
}
})
/* add listener */
/* Proxies the new "data" */
const obj = {}
Object.defineProperty(obj, 'n', {
get() {
return data.n
},
set(value) {
if (value < 0) return
data.n = value
}
})
return obj
}
let myData = {n: 0}
let dataProxy = proxy({data: myData})
console.log(dataProxy.n)
/ / 0
myData.n = -1
console.log(dataProxy.n)
/ / 0
myData.n = 1
console.log(dataProxy.n)
/ / 1
Copy the code
Note: we are only modifying the object {n: 0}, the listener is the process of modifying the object, the proxy is created on the original object being modified. In this way, the connection will not be broken.
Multiple attributes
Closures and loops are used to do this when you have multiple variables/attributes in your data.
new Vue()
What does Vue do with Data?
When you create an instance
const vm = new Vue({data: myData})
Copy the code
- Vue makes the VM a proxy for myData.
- Vue monitors all properties of myData.
purpose
What is the purpose of this?
- You can use this to query the VM. This. N = = = myData. N.
- The reason for monitoring is to prevent vue from being able to learn about property changes in myData.
- Vue can use Render (data) to update the UI and render the page when the property changes.
Data response
- Responsivity is a form of response to changes in the outside world.
const vm = new Vue({data: {n: 0}})
Copy the code
- When changing vm.n or data.n, render(data…) N will respond to that response.
- This linkage process is the data response of vUE.
- Vue currently implements data responsiveness through Object.defineProperty.
Add attributes to data
Vue does listen and proxy for properties in data (or properties in objects), but it has no way to listen and proxy in advance.
What if you add attributes after initializing data?
General object
For general objects, all possible attributes can be written out in advance in data, so that there is no need to add attributes, only need to change it.
Attributes can also be added in other ways.
With that in mind, let’s look at an API that Vue provides:
Vue. Set (object, key, value) orthis.$set(object, key, value)
Copy the code
role
- Add new attributes to data.
- Automatically create creates agents and listeners for it if none have been created.
The sample
const Vue = window.Vue
new Vue({
data: {
obj: {
a: 0}},template: `
{{obj.b}}
`.methods: {
one() {
Vue.set(this.obj, 'b'.1)
$set(this.obj, 'b', 1);
}
}
}).$mount('#app')
Copy the code
An array of
Because arrays are inherently special: the length of an array is unpredictable (the usernames of all users, for example, are in the array), you can’t use undefined to hold space for each item, or use the vue.set () method all the time.
You can use the push method this.array.push(‘value’), but the array is already wrapped in Vue’s new push method. The idea is to declare a new class to inherit an array. For the various special case methods used in Vue instances, see array variation methods. There are seven apis. These methods (apis) automatically handle listening and proxying on array items and trigger view updates.