




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第聊聊Vue2為什么能通過this訪問各種選項(xiàng)中屬性exportfunctionproxy(target,sourceKey,key){
sharedPropertyDefinition.get=functionproxyGetter(){
returnthis[sourceKey][key]
sharedPropertyDefinition.set=functionproxySetter(val){
this[sourceKey][key]=val
Object.defineProperty(target,key,sharedPropertyDefinition)
}
這里的target就是vm,sourceKey就是_props,key就是props的屬性名;
這里通過Object.defineProperty把vm的屬性代理到_props上,這樣就可以通過this訪問到props了。
不是很好理解,那我們來自己就用這些代碼實(shí)現(xiàn)一下:
varoptions={
props:{
name:{
type:String,
default:defaultname
functionVue(options){
constvm=this
initProps(vm,ps)
functioninitProps(vm,propsOptions){
vm._props={}
for(constkeyinpropsOptions){
proxy(vm,`_props`,key)
functionproxy(target,sourceKey,key){
Object.defineProperty(target,key,{
get(){
returnthis[sourceKey][key]
set(val){
this[sourceKey][key]=val
constvm=newVue(options)
console.log();
console.log(vm._);
=name
console.log();
console.log(vm._);
上面的代碼只是為了方便理解,所以會(huì)忽略一些細(xì)節(jié),比如props的驗(yàn)證等等,真實(shí)掛載在_props上的props是通過defineReactive實(shí)現(xiàn)的,我這里直接是空的,這些超出了本文的范圍。
initMethods
initMethods的代碼如下:
functioninitMethods(vm,methods){
constprops=vm.$ps
for(constkeyinmethods){
if(__DEV__){
if(typeofmethods[key]!==function){
warn(
`Method${key}hastype${typeofmethods[
]}inthecomponentdefinition.`+
`Didyoureferencethefunctioncorrectly`,
if(propshasOwn(props,key)){
warn(`Method${key}hasalreadybeendefinedasaprop.`,vm)
if(keyinvmisReserved(key)){
warn(
`Method${key}conflictswithanexistingVueinstancemethod.`+
`Avoiddefiningcomponentmethodsthatstartwith_or$.`
vm[key]=typeofmethods[key]!==functionnoop:bind(methods[key],vm)
}
跟著之前的思路,我們忽略無關(guān)代碼,簡(jiǎn)化后的代碼如下:
functioninitMethods(vm,methods){
for(constkeyinmethods){
vm[key]=typeofmethods[key]!==functionnoop:bind(methods[key],vm)
}
這里的noop和bind在之前的文章中有出現(xiàn)過,可以去看一下:【源碼共讀】Vue2源碼shared模塊中的36個(gè)實(shí)用工具函數(shù)分析
這里的vm[key]就是methods的方法,這樣就可以通過this訪問到methods中定義的方法了。
bind的作用是把methods中定義的函數(shù)的this指向vm,這樣就可以在methods中使用this就是vm了。
簡(jiǎn)單的實(shí)現(xiàn)一下:
varoptions={
methods:{
say(){
console.log(say
functionVue(options){
constvm=this
initMethods(vm,options.methods)
functioninitMethods(vm,methods){
for(constkeyinmethods){
vm[key]=typeofmethods[key]!==functionnoop:bind(methods[key],vm)
functionnoop(){}
functionpolyfillBind(fn,ctx){
functionboundFn(a){
constl=arguments.length
returnl
l1
fn.apply(ctx,arguments)
:fn.call(ctx,a)
:fn.call(ctx)
boundFn._length=fn.length
returnboundFn
functionnativeBind(fn,ctx){
returnfn.bind(ctx)
constbind=Ftotype.bindnativeBind:polyfillBind
constvm=newVue(options)
vm.say()
initData
initData的代碼如下:
functioninitData(vm){
letdata=vm.$options.data
data=vm._data=isFunction(data)getData(data,vm):data||{}
if(!isPlainObject(data)){
data={}
__DEV__
warn(
datafunctionsshouldreturnanobject:\n+
/v2/guide/components.html#data-Must-Be-a-Function,
//proxydataoninstance
constkeys=Object.keys(data)
constprops=vm.$ps
constmethods=vm.$options.methods
leti=keys.length
while(i--){
constkey=keys[i]
if(__DEV__){
if(methodshasOwn(methods,key)){
warn(`Method${key}hasalreadybeendefinedasadataproperty.`,vm)
if(propshasOwn(props,key)){
__DEV__
warn(
`Thedataproperty${key}isalreadydeclaredasaprop.`+
`Usepropdefaultvalueinstead.`,
}elseif(!isReserved(key)){
proxy(vm,`_data`,key)
//observedata
constob=observe(data)
obob.vmCount++
}
簡(jiǎn)化之后的代碼如下:
functioninitData(vm){
letdata=vm.$options.data
//proxydataoninstance
constkeys=Object.keys(data)
leti=keys.length
while(i--){
constkey=keys[i]
proxy(vm,`_data`,key)
}
這里的實(shí)現(xiàn)方式和initProps是一樣的,都是通過proxy把data中的屬性代理到vm上。
注意:initData的獲取值的地方是其他的不相同,這里只做提醒,不做詳細(xì)分析。
initComputed
initComputed的代碼如下:
functioninitComputed(vm,computed){
//$flow-disable-line
constwatchers=(vm._computedWatchers=Object.create(null))
//computedpropertiesarejustgettersduringSSR
constisSSR=isServerRendering()
for(constkeyincomputed){
constuserDef=computed[key]
constgetter=isFunction(userDef)userDef:userDef.get
if(__DEV__getter==null){
warn(`Getterismissingforcomputedproperty${key}.`,vm)
if(!isSSR){
//createinternalwatcherforthecomputedproperty.
watchers[key]=newWatcher(
getter||noop,
noop,
computedWatcherOptions
//component-definedcomputedpropertiesarealreadydefinedonthe
//componentprototype.Weonlyneedtodefinecomputedpropertiesdefined
//atinstantiationhere.
if(!(keyinvm)){
defineComputed(vm,key,userDef)
}elseif(__DEV__){
if(keyinvm.$data){
warn(`Thecomputedproperty${key}isalreadydefinedindata.`,vm)
}elseif(vm.$pskeyinvm.$ps){
warn(`Thecomputedproperty${key}isalreadydefinedasaprop.`,vm)
}elseif(vm.$options.methodskeyinvm.$options.methods){
warn(
`Thecomputedproperty${key}isalreadydefinedasamethod.`,
}
簡(jiǎn)化之后的代碼如下:
functioninitComputed(vm,computed){
for(constkeyincomputed){
constuserDef=computed[key]
constgetter=userDef
defineComputed(vm,key,userDef)
}
這里的實(shí)現(xiàn)主要是通過defineComputed來定義computed屬性,進(jìn)去瞅瞅:
exportfunctiondefineComputed(target,key,userDef){
constshouldCache=!isServerRendering()
if(isFunction(userDef)){
sharedPropertyDefinition.get=shouldCache
createComputedGetter(key)
:createGetterInvoker(userDef)
sharedPropertyDefinition.set=noop
}else{
sharedPropertyDefinition.get=userDef.get
shouldCacheuserDef.cache!==false
createComputedGetter(key)
:createGetterInvoker(userDef.get)
:noop
sharedPropertyDefinition.set=userDef.set||noop
if(__DEV__sharedPropertyDefinition.set===noop){
sharedPropertyDefinition.set=function(){
warn(
`Computedproperty${key}wasassignedtobutithasnosetter.`,
this
Object.defineProperty(target,key,sharedPropertyDefinition)
}
仔細(xì)看下來,其實(shí)實(shí)現(xiàn)方式還是和initProps和initData一樣,都是通過Object.defineProperty來定義屬性;
不過里面的getter和setter是通過createComputedGetter和createGetterInvoker來創(chuàng)建的,這里不做過多分析。
上面我們已經(jīng)分析了props、methods、data、computed的屬性為什么可以直接通過this來訪問,那么我們現(xiàn)在就來實(shí)現(xiàn)一下這個(gè)功能。
上面已經(jīng)簡(jiǎn)單了實(shí)現(xiàn)了initProps、initMethods,而initData和initComputed的實(shí)現(xiàn)方式和initProps的方式一樣,所以我們直接復(fù)用就好了:
functionVue(options){
this._init(options)
Vtotype._init=function(options){
constvm=this
vm.$options=options
initState(vm)
functioninitState(vm){
constopts=vm.$options
if(ps)initProps(vm,ps)
if(opts.methods)initMethods(vm,opts.methods)
if(opts.data)initData(vm)
if(puted)initComputed(vm,puted)
functioninitProps(vm,propsOptions){
vm._props={}
for(constkeyinpropsOptions){
vm._props[key]=propsOptions[key].default
proxy(vm,`_props`,key)
functionproxy(target,sourceKey,key){
Object.defineProperty(target,key,{
get(){
returnthis[sourceKey][key]
set(val){
this[sourceKey][key]=val
functioninitMethods(vm,methods){
for(constkeyinmethods){
vm[key]=typeofmethods[key]!==functionnoop:bind(methods[key],vm)
functionnoop(){}
functionpolyfillBind(fn,ctx){
functionboundFn(a){
constl=arguments.length
returnl
l1
fn.apply(ctx,arguments)
:fn.call(ctx,a)
:fn.call(ctx)
boundFn._length=fn.length
returnboundFn
functionnativeBind(fn,ctx){
returnfn.bind(ctx)
constbind=Ftotype.bindnativeBi
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 消防演練費(fèi)用協(xié)議書
- 支援學(xué)校幫扶協(xié)議書
- 民航信息分包協(xié)議書
- 手機(jī)話費(fèi)報(bào)銷協(xié)議書
- 景區(qū)安全經(jīng)營協(xié)議書
- 扣押船舶看管協(xié)議書
- 毀壞財(cái)物和解協(xié)議書
- 救援車輛轉(zhuǎn)讓協(xié)議書
- 房頂屋頂修繕協(xié)議書
- 比賽冠名捐贈(zèng)協(xié)議書
- 《大模型原理與技術(shù)》全套教學(xué)課件
- GB/T 44770-2024智能火電廠技術(shù)要求
- 《塑料材質(zhì)食品相關(guān)產(chǎn)品質(zhì)量安全風(fēng)險(xiǎn)管控清單》
- 陌生拜訪情景演練
- 【經(jīng)典文獻(xiàn)】《矛盾論》全文
- 存款保險(xiǎn)條例培訓(xùn)
- 八年級(jí)數(shù)學(xué)家長(zhǎng)會(huì)課件
- 惠州市2025屆高三第二次調(diào)研考試(二調(diào))試題 政治試卷(含答案解析)
- 光伏發(fā)電項(xiàng)目試驗(yàn)檢測(cè)計(jì)劃
- 幼兒園營養(yǎng)膳食蔬菜水果認(rèn)知主題課件
- 國開(陜西)2024年秋《社會(huì)調(diào)查》形考作業(yè)1-4答案
評(píng)論
0/150
提交評(píng)論