vue?Proxy數(shù)據(jù)代理進(jìn)行校驗部分源碼實例解析
initProxy
數(shù)據(jù)攔截的思想除了為構(gòu)建響應(yīng)式系統(tǒng)準(zhǔn)備,它也可以為數(shù)據(jù)進(jìn)行篩選過濾,我們接著往下看初始化的代碼,在合并選項后,vue接下來會為vm實例設(shè)置一層代理,這層代理可以為vue在模板渲染時進(jìn)行一層數(shù)據(jù)篩選
Vue.prototype._init = function(options) { // 選項合并 ... { // 對vm實例進(jìn)行一層代理 initProxy(vm); } ... }
initProxy
// 代理函數(shù) var initProxy = function initProxy (vm) { //是否支持Proxy if (hasProxy) { var options = vm.$options; //當(dāng)使用類似webpack這樣的打包工具時,通常會使用vue-loader插件進(jìn)行模板的編譯,這個時候options.render是存在的,并且_withStripped的屬性也會設(shè)置為true(關(guān)于編譯版本和運(yùn)行時版本的區(qū)別可以參考后面章節(jié)),所以此時代理的選項是hasHandler //在其他場景下,代理的選項是getHandler var handlers = options.render && options.render._withStripped ? getHandler : hasHandler; // 代理vm實例到vm屬性_renderProxy vm._renderProxy = new Proxy(vm, handlers); } else { vm._renderProxy = vm; } };
hasProxy
var hasProxy = typeof Proxy !== 'undefined' && isNative(Proxy);
hasHandler
var hasHandler = { // key in obj或者with作用域時,會觸發(fā)has的鉤子 has: function has (target, key) { ··· } };
觸發(fā)代理
源碼中vm._renderProxy的使用出現(xiàn)在Vue實例的_render方法中,Vue.prototype._render是將渲染函數(shù)轉(zhuǎn)換成Virtual DOM的方法,這部分是關(guān)于實例的掛載和模板引擎的解析
當(dāng)我們調(diào)用render函數(shù)時,代理的vm._renderProxy對象便會訪問到
而這個render函數(shù)就是包裝成with的執(zhí)行語句,在執(zhí)行with語句的過程中,該作用域下變量的訪問都會觸發(fā)has鉤子,這也是模板渲染時之所有會觸發(fā)代理攔截的原因
之所以會觸發(fā)數(shù)據(jù)代理攔截是因為模板中使用了變量,例如<div>{{message}}}
Vue.prototype._render = function () { ··· // 調(diào)用vm._renderProxy vnode = render.call(vm._renderProxy, vm.$createElement); } ========================================= var vm = new Vue({ el: '#app' }) console.log(vm.$options.render) ???????//輸出, 模板渲染使用with語句 ? anonymous() { with(this){return _c('div',{attrs:{"id":"app"}},[_v(_s(message)+_s(_test))])} }
數(shù)據(jù)過濾
通過data選項去設(shè)置實例數(shù)據(jù),那么這些數(shù)據(jù)可以隨著個人的習(xí)慣任意命名嗎?顯然不是的,如果你使用js的關(guān)鍵字(像Object,Array,NaN)去命名,這是不被允許的。另一方面,Vue源碼內(nèi)部使用了以$,_作為開頭的內(nèi)部變量,所以以$,_開頭的變量名也是不被允許的,這就構(gòu)成了數(shù)據(jù)過濾監(jiān)測的前提。
var hasHandler = { has: function has (target, key) { var has = key in target; // isAllowed用來判斷模板上出現(xiàn)的變量是否合法。 var isAllowed = allowedGlobals(key) || (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)); // _和$開頭的變量不允許出現(xiàn)在定義的數(shù)據(jù)中,因為他是vue內(nèi)部保留屬性的開頭。 // 1. warnReservedPrefix: 警告不能以$ _開頭的變量 // 2. warnNonPresent: 警告模板出現(xiàn)的變量在vue實例中未定義 //has判斷是否是target對象中的變量 if (!has && !isAllowed) { if (key in target.$data) { warnReservedPrefix(target, key); } else { warnNonPresent(target, key); } } return has || !isAllowed } }; // 模板中允許出現(xiàn)的非vue實例定義的變量 var allowedGlobals = makeMap( 'Infinity,undefined,NaN,isFinite,isNaN,' + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + 'require' // for Webpack/Browserify );
在瀏覽器不支持proxy的情況下的數(shù)據(jù)過濾
在沒有經(jīng)過代理的情況下,使用_開頭的變量依舊會 報錯,但是它變成了js語言層面的錯誤。但是這個報錯無法在Vue這一層知道錯誤的詳細(xì)信息,而這就是能使用Proxy的好處。
在初始化數(shù)據(jù)階段,Vue已經(jīng)為數(shù)據(jù)進(jìn)行了一層篩選的代理。具體看initData對數(shù)據(jù)的代理
有了isReserved的篩選,即使this._data._test存在,我們依舊無法在訪問this._test時拿到_test變量
function initData(vm) { vm._data = typeof data === 'function' ? getData(data, vm) : data || {} if (!isReserved(key)) { // 數(shù)據(jù)代理,用戶可直接通過vm實例獲取返回data數(shù)據(jù) proxy(vm, "_data", key); } } function isReserved (str) { var c = (str + '').charCodeAt(0); // 首字符是$, _的字符串 return c === 0x24 || c === 0x5F }
proxy
function proxy (target, sourceKey, key) { sharedPropertyDefinition.get = function proxyGetter () { // 當(dāng)訪問this[key]時,會代理訪問this._data[key]的值 return this[sourceKey][key] }; sharedPropertyDefinition.set = function proxySetter (val) { this[sourceKey][key] = val; }; Object.defineProperty(target, key, sharedPropertyDefinition); }
總結(jié)
到此這篇關(guān)于vue Proxy數(shù)據(jù)代理進(jìn)行校驗部分源碼解析的文章就介紹到這了,更多相關(guān)vue Proxy數(shù)據(jù)代理校驗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue+Video.js實現(xiàn)視頻抽幀并返回抽幀圖片Base64
這篇文章主要為大家詳細(xì)介紹了Vue如何利用Video.js實現(xiàn)視頻抽幀并返回抽幀圖片Base64,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-01-01Vue的hover/click事件如何動態(tài)改變顏色和背景色
這篇文章主要介紹了Vue的hover/click事件如何動態(tài)改變顏色和背景色問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11