聊聊Vue2為什么能通過this訪問各種選項中屬性_第1頁
聊聊Vue2為什么能通過this訪問各種選項中屬性_第2頁
聊聊Vue2為什么能通過this訪問各種選項中屬性_第3頁
聊聊Vue2為什么能通過this訪問各種選項中屬性_第4頁
聊聊Vue2為什么能通過this訪問各種選項中屬性_第5頁
已閱讀5頁,還剩7頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第聊聊Vue2為什么能通過this訪問各種選項中屬性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了。

不是很好理解,那我們來自己就用這些代碼實現(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._);

上面的代碼只是為了方便理解,所以會忽略一些細節(jié),比如props的驗證等等,真實掛載在_props上的props是通過defineReactive實現(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)

}

跟著之前的思路,我們忽略無關代碼,簡化后的代碼如下:

functioninitMethods(vm,methods){

for(constkeyinmethods){

vm[key]=typeofmethods[key]!==functionnoop:bind(methods[key],vm)

}

這里的noop和bind在之前的文章中有出現(xiàn)過,可以去看一下:【源碼共讀】Vue2源碼shared模塊中的36個實用工具函數分析

這里的vm[key]就是methods的方法,這樣就可以通過this訪問到methods中定義的方法了。

bind的作用是把methods中定義的函數的this指向vm,這樣就可以在methods中使用this就是vm了。

簡單的實現(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++

}

簡化之后的代碼如下:

functioninitData(vm){

letdata=vm.$options.data

//proxydataoninstance

constkeys=Object.keys(data)

leti=keys.length

while(i--){

constkey=keys[i]

proxy(vm,`_data`,key)

}

這里的實現(xiàn)方式和initProps是一樣的,都是通過proxy把data中的屬性代理到vm上。

注意:initData的獲取值的地方是其他的不相同,這里只做提醒,不做詳細分析。

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.`,

}

簡化之后的代碼如下:

functioninitComputed(vm,computed){

for(constkeyincomputed){

constuserDef=computed[key]

constgetter=userDef

defineComputed(vm,key,userDef)

}

這里的實現(xiàn)主要是通過defineComputed來定義computed屬性,進去瞅瞅:

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)

}

仔細看下來,其實實現(xiàn)方式還是和initProps和initData一樣,都是通過Object.defineProperty來定義屬性;

不過里面的getter和setter是通過createComputedGetter和createGetterInvoker來創(chuàng)建的,這里不做過多分析。

上面我們已經分析了props、methods、data、computed的屬性為什么可以直接通過this來訪問,那么我們現(xiàn)在就來實現(xiàn)一下這個功能。

上面已經簡單了實現(xiàn)了initProps、initMethods,而initData和initComputed的實現(xiàn)方式和initProps的方式一樣,所以我們直接復用就好了:

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等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論