当前位置:网站首页>What is a responsive object? How to create a responsive object?
What is a responsive object? How to create a responsive object?
2022-07-06 23:56:00 【Feather_ seventy-four】
The theme : What is a responsive object ? The creation process of responsive objects ?
What is a responsive object ?
Vue.js The core of implementing responsive is to take advantage of ES5 Of Object.defineProperty
. because IE8 And the following browsers do not Object.defineProperty
Method , That's why Vue.js Incompatible IE8 And the following browser reasons .
Object.defineProperty
Object.defineProperty(obj, prop, descriptor)
var o = {
};
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true
});
// o With attributes a,a The value of is 37
var bValue = 38;
Object.defineProperty(o, "b", {
get() {
return bValue; },
set(newValue) {
bValue = newValue; },
enumerable : true,
configurable : true
});
// o With attributes b,b The value of is bValue. Now? , Unless we redefine o.b,o.b The value of is always with bValue identical
Object.defineProperty(o, 'c', {
value: 39,
writable: true,
enumerable: false,
configurable: true
})
// When enumerable by false when ,Object.keys(ob) Will not show 'c'
obj
Is the object on which the attribute is to be defined .prop
Is the name of the attribute to be defined or modified .descriptor
Is the attribute descriptor to be defined or modified . Once the object has getter
and setter
attribute , We can simply call this object Responsive object .get
It's a... For properties getter
Method , When we access this property, it will trigger getter
Method ;set
It's a... For properties setter
Method , When we modify this attribute, it will trigger setter
Method .
that Vue.js Which objects have become responsive objects , It can be analyzed from the source code level .
The creation process of responsive objects
First, let's talk about the mapping of raw data to DOM in , props and data When initializing, you can define responsive objects . props By calling defineReactive()
How to put each props
Of key
Become responsive . data It's through observe()
Changes in monitoring data ,Observer
Add... To the properties of an object getter
and setter
.
src/core/instance/init.js
initialization Vue Called when _init
Method ,init
Methods include initState()
Method .
src/core/instance/state.js
(1)initState
This method mainly initializes props
、methods
、data
、computed
and wathcer
Wait for the property to be initialized .
export function initState (vm: Component) {
vm._watchers = []
const opts = vm.$options
if (opts.props) initProps(vm, opts.props)
if (opts.methods) initMethods(vm, opts.methods)
if (opts.data) {
initData(vm)
} else {
observe(vm._data = {
}, true /* asRootData */)
}
if (opts.computed) initComputed(vm, opts.computed)
if (opts.watch && opts.watch !== nativeWatch) {
initWatch(vm, opts.watch)
}
}
The key analysis initProps()
and initData()
(2)initProps
call defineReactive()
How to put each props
Of key
Become responsive
function initProps (vm: Component, propsOptions: Object) {
const propsData = vm.$options.propsData || {
}
const props = vm._props = {
}
// cache prop keys so that future props updates can iterate using Array
// instead of dynamic object key enumeration.
const keys = vm.$options._propKeys = []
const isRoot = !vm.$parent
// root instance props should be converted
if (!isRoot) {
toggleObserving(false)
}
for (const key in propsOptions) {
keys.push(key)
const value = validateProp(key, propsOptions, propsData, vm)
/* istanbul ignore else */
if (process.env.NODE_ENV !== 'production') {
const hyphenatedKey = hyphenate(key)
if (isReservedAttribute(hyphenatedKey) ||
config.isReservedAttr(hyphenatedKey)) {
warn(
`"${
hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,
vm
)
}
defineReactive(props, key, value, () => {
if (!isRoot && !isUpdatingChildComponent) {
warn(
`Avoid mutating a prop directly since the value will be ` +
`overwritten whenever the parent component re-renders. ` +
`Instead, use a data or computed property based on the prop's ` +
`value. Prop being mutated: "${
key}"`,
vm
)
}
})
} else {
defineReactive(props, key, value)
}
// static props are already proxied on the component's prototype
// during Vue.extend(). We only need to proxy props defined at
// instantiation here.
if (!(key in vm)) {
proxy(vm, `_props`, key)
}
}
toggleObserving(true)
}
(3)initData
Traverse all Object.keys(data)
, stay methods
or props
If it is defined in, it will alarm . hold _data
Agent to vm
For instance .observe()
The way is to observe data
.( The code that goes deep into the principle of responsiveness is basically src/core/observer
On )
function initData (vm: Component) {
let data = vm.$options.data
data = vm._data = typeof data === 'function'
? getData(data, vm)
: data || {
}
if (!isPlainObject(data)) {
data = {
}
process.env.NODE_ENV !== 'production' && warn(
'data functions should return an object:\n' +
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
vm
)
}
// proxy data on instance
const keys = Object.keys(data)
const props = vm.$options.props
const methods = vm.$options.methods
let i = keys.length
while (i--) {
const key = keys[i]
if (process.env.NODE_ENV !== 'production') {
if (methods && hasOwn(methods, key)) {
warn(
`Method "${
key}" has already been defined as a data property.`,
vm
)
}
}
if (props && hasOwn(props, key)) {
process.env.NODE_ENV !== 'production' && warn(
`The data property "${
key}" is already declared as a prop. ` +
`Use prop default value instead.`,
vm
)
} else if (!isReserved(key)) {
proxy(vm, `_data`, key)
}
}
// observe data
observe(data, true /* asRootData */)
}
1)observe
function :observe
Is used to monitor data changes .
observe
The function of the method is to give and give VNode Object type data to add a Observer
, If it has been added, it will return to , Otherwise, instantiate a Observer
Object instances .
Code parsing :observe
Method accepts two parameters ,value
It's any type , What's coming in is data
,asRootData
What's coming in is true
.
Judge value
Whether it is Object
type ,value
Whether it is VNode
example .
instanceof
The role of :Ainstanceof
B , Judge A Whether it is B Example
And then determine value
Is there any __ob__
Attributes and value.__ob__
Whether it is Observer
example . Meet the conditions and get it directly ob
and return
. Otherwise, make the next judgment . Judge shouldObserve
.
shouldObserve
It is a sign of global definition , Used to decide when to execute new Observer
.toggleObserving
Methods shouldObserve
Value change , The method in initProps
Method by judgment isRoot
Yes shouldObserve
Make changes . once shouldObserve
yes false
, There is no way to value
become Observer
Object instances .
export let shouldObserve: boolean = true
export function toggleObserving (value: boolean) {
shouldObserve = value
}
At the same time, judge value
No ServerRendering
, Are arrays and objects, and objects have extensible properties , We have to judge again value
No Vue. That's what makes value
become Observer
Object instances .
export function observe (value: any, asRootData: ?boolean): Observer | void {
if (!isObject(value) || value instanceof VNode) {
return
}
let ob: Observer | void
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value)
}
if (asRootData && ob) {
ob.vmCount++
}
return ob
}
2)Observer
function :Observer
Is a class , Its function is to add... To the properties of an object getter
and setter
, Used to rely on collection and distribution of updates
Code parsing :Observer
It's a class , It can be understood as an observer . Attributes are value
、dep
、vmCount
, Constructor will retain value
, Instantiation dep
.
def
Method pair Object.defineProperty
encapsulate , It's for value
add to __ob__
attribute , The value of this attribute points to the current instance . To execute observe()
When , After the first definition, the next time it will be directly for the same object return ob
.
enumerable?: boolean
: As Typescript Definition method when the number of interface attributes is uncertain . Either the parameter does not exist , Either it must conform to the type definition of the parameter .
export function def (obj: Object, key: string, val: any, enumerable?: boolean) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
})
}
Judge value
Is it an array ,observeArray()
The way is to traverse value
, Then recursively observe . If it is not an array but an object, call walk()
.walk()
Traverse all properties on the object , perform defineReactive()
Method . If you just take __ob__
Assign a value to value
,__ob__
Will perform defineReactive
, It's totally unnecessary , Because I won't modify __ob__
. Why? __ob__
Not execute defineReactive
? because def
Only three parameters were passed ,enumerable
yes undefined , therefore !!enumerable
yes false
, So the traversal will not be executed to ( Prototypes are also not enumerable ).
export class Observer {
value: any;
dep: Dep;
vmCount: number; // number of vms that have this object as root $data
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__', this)
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods)
} else {
copyAugment(value, arrayMethods, arrayKeys)
}
this.observeArray(value)
} else {
this.walk(value)
}
}
/** * Walk through all properties and convert them into * getter/setters. This method should only be called when * value type is Object. */
walk (obj: Object) {
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
defineReactive(obj, keys[i])
}
}
/** * Observe a list of Array items. */
observeArray (items: Array<any>) {
for (let i = 0, l = items.length; i < l; i++) {
observe(items[i])
}
}
}
3)defineReactive
function :defineReactive
The function of is to define a responsive object , Add... To the object dynamically getter
and setter
.
Code parsing :
Accept five parameters : object 、 Object property value 、 Initial value 、 Two optional . Get the object attribute definition property
, Get the original property getter
and setter
, When a property value is also an object , Recursively observe
. This ensures that no matter obj
How complex is the structure of , All its sub properties can also become responsive objects , So we visit or modify obj
A deeply nested property in , Can also trigger getter
and setter
.
export function defineReactive (
obj: Object, key: string, val: any, customSetter?: ?Function, shallow?: boolean
) {
const dep = new Dep()
const property = Object.getOwnPropertyDescriptor(obj, key)
if (property && property.configurable === false) {
return
}
// cater for pre-defined getter/setters
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
// #7981: for accessor properties without setter
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
}
})
}
边栏推荐
- 在Docker中分分钟拥有Oracle EMCC 13.5环境
- Use package FY in Oracle_ Recover_ Data. PCK to recover the table of truncate misoperation
- app通用功能测试用例
- Can online reload system software be used safely? Test use experience to share with you
- pinia 模块划分
- Cas d'essai fonctionnel universel de l'application
- Experiment 6: installing eve-ng
- MVC and MVVM
- Newsletter L Huobi ventures is in-depth contact with genesis public chain
- PostgreSQL highly available repmgr (1 master 2 slave +1witness) + pgpool II realizes master-slave switching + read-write separation
猜你喜欢
【通信】两层无线 Femtocell 网络上行链路中的最优功率分配附matlab代码
The intranet penetrates the zerotier extranet (mobile phone, computer, etc.) to access intranet devices (raspberry pie, NAS, computer, etc.)
MVC and MVVM
After 3 years of testing bytecan software, I was ruthlessly dismissed in February, trying to wake up my brother who was paddling
MATLIB从excel表中读取数据并画出函数图像
Pytest multi process / multi thread execution test case
Zero code and high return. How to use 40 sets of templates to meet 95% of the reporting needs in the work
刘永鑫报告|微生物组数据分析与科学传播(晚7点半)
Penetration test --- database security: detailed explanation of SQL injection into database principle
[communication] optimal power allocation in the uplink of two-layer wireless femtocell network with matlab code
随机推荐
After 3 years of testing bytecan software, I was ruthlessly dismissed in February, trying to wake up my brother who was paddling
DevOps可以帮助减少技术债务的十种方式
亚朵三顾 IPO
Quickly use various versions of PostgreSQL database in docker
基于SSM框架实现的房屋租赁管理系统
AVL树到底是什么?
士大夫哈哈哈
app通用功能測試用例
web渗透测试是什么_渗透实战
PostgreSQL highly available repmgr (1 master 2 slave +1witness) + pgpool II realizes master-slave switching + read-write separation
本地部署 zeppelin 0.10.1
Oracle EMCC 13.5 environment in docker every minute
leetcode:236. The nearest common ancestor of binary tree
Computer reinstallation system teaching, one click fool operation, 80% of people have learned
app通用功能测试用例
GEO数据挖掘(三)使用DAVID数据库进行GO、KEGG富集分析
谷歌百度雅虎都是中国公司开发的通用搜索引擎_百度搜索引擎url
MySQL主从之多源复制(3主1从)搭建及同步测试
量子时代计算机怎么保证数据安全?美国公布四项备选加密算法
Zero code and high return. How to use 40 sets of templates to meet 95% of the reporting needs in the work