vue?Proxy數(shù)據(jù)代理進(jìn)行校驗(yàn)部分源碼實(shí)例解析
initProxy
數(shù)據(jù)攔截的思想除了為構(gòu)建響應(yīng)式系統(tǒng)準(zhǔn)備,它也可以為數(shù)據(jù)進(jìn)行篩選過濾,我們接著往下看初始化的代碼,在合并選項(xiàng)后,vue接下來會(huì)為vm實(shí)例設(shè)置一層代理,這層代理可以為vue在模板渲染時(shí)進(jìn)行一層數(shù)據(jù)篩選
Vue.prototype._init = function(options) {
// 選項(xiàng)合并
...
{
// 對(duì)vm實(shí)例進(jìn)行一層代理
initProxy(vm);
}
...
}initProxy
// 代理函數(shù)
var initProxy = function initProxy (vm) {
//是否支持Proxy
if (hasProxy) {
var options = vm.$options;
//當(dāng)使用類似webpack這樣的打包工具時(shí),通常會(huì)使用vue-loader插件進(jìn)行模板的編譯,這個(gè)時(shí)候options.render是存在的,并且_withStripped的屬性也會(huì)設(shè)置為true(關(guān)于編譯版本和運(yùn)行時(shí)版本的區(qū)別可以參考后面章節(jié)),所以此時(shí)代理的選項(xiàng)是hasHandler
//在其他場(chǎng)景下,代理的選項(xiàng)是getHandler
var handlers = options.render && options.render._withStripped
? getHandler
: hasHandler;
// 代理vm實(shí)例到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作用域時(shí),會(huì)觸發(fā)has的鉤子
has: function has (target, key) {
···
}
};觸發(fā)代理
源碼中vm._renderProxy的使用出現(xiàn)在Vue實(shí)例的_render方法中,Vue.prototype._render是將渲染函數(shù)轉(zhuǎn)換成Virtual DOM的方法,這部分是關(guān)于實(shí)例的掛載和模板引擎的解析
當(dāng)我們調(diào)用render函數(shù)時(shí),代理的vm._renderProxy對(duì)象便會(huì)訪問到
而這個(gè)render函數(shù)就是包裝成with的執(zhí)行語句,在執(zhí)行with語句的過程中,該作用域下變量的訪問都會(huì)觸發(fā)has鉤子,這也是模板渲染時(shí)之所有會(huì)觸發(fā)代理攔截的原因
之所以會(huì)觸發(fā)數(shù)據(jù)代理攔截是因?yàn)槟0逯惺褂昧俗兞?,例?lt;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選項(xiàng)去設(shè)置實(shí)例數(shù)據(jù),那么這些數(shù)據(jù)可以隨著個(gè)人的習(xí)慣任意命名嗎?顯然不是的,如果你使用js的關(guān)鍵字(像Object,Array,NaN)去命名,這是不被允許的。另一方面,Vue源碼內(nèi)部使用了以$,_作為開頭的內(nèi)部變量,所以以$,_開頭的變量名也是不被允許的,這就構(gòu)成了數(shù)據(jù)過濾監(jiān)測(cè)的前提。
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ù)中,因?yàn)樗莢ue內(nèi)部保留屬性的開頭。
// 1. warnReservedPrefix: 警告不能以$ _開頭的變量
// 2. warnNonPresent: 警告模板出現(xiàn)的變量在vue實(shí)例中未定義
//has判斷是否是target對(duì)象中的變量
if (!has && !isAllowed) {
if (key in target.$data) { warnReservedPrefix(target, key); }
else { warnNonPresent(target, key); }
}
return has || !isAllowed
}
};
// 模板中允許出現(xiàn)的非vue實(shí)例定義的變量
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)過代理的情況下,使用_開頭的變量依舊會(huì) 報(bào)錯(cuò),但是它變成了js語言層面的錯(cuò)誤。但是這個(gè)報(bào)錯(cuò)無法在Vue這一層知道錯(cuò)誤的詳細(xì)信息,而這就是能使用Proxy的好處。
在初始化數(shù)據(jù)階段,Vue已經(jīng)為數(shù)據(jù)進(jìn)行了一層篩選的代理。具體看initData對(duì)數(shù)據(jù)的代理
有了isReserved的篩選,即使this._data._test存在,我們依舊無法在訪問this._test時(shí)拿到_test變量
function initData(vm) {
vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
if (!isReserved(key)) {
// 數(shù)據(jù)代理,用戶可直接通過vm實(shí)例獲取返回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]時(shí),會(huì)代理訪問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)行校驗(yàn)部分源碼解析的文章就介紹到這了,更多相關(guān)vue Proxy數(shù)據(jù)代理校驗(yàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue3封裝組件完整實(shí)例(帶回調(diào)事件)
Vue.js已成為現(xiàn)代Web開發(fā)中不可或缺的技術(shù)之一,雖然Vue.js的一些基礎(chǔ)概念和語法比較易學(xué),但深入挖掘Vue.js的核心概念和功能需要更多的實(shí)踐,下面這篇文章主要給大家介紹了關(guān)于Vue3封裝組件(帶回調(diào)事件)的相關(guān)資料,需要的朋友可以參考下2023-06-06
解決iView中時(shí)間控件選擇的時(shí)間總是少一天的問題
下面小編就為大家分享一篇解決iView中時(shí)間控件選擇的時(shí)間總是少一天的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-03-03
Vue+Video.js實(shí)現(xiàn)視頻抽幀并返回抽幀圖片Base64
這篇文章主要為大家詳細(xì)介紹了Vue如何利用Video.js實(shí)現(xiàn)視頻抽幀并返回抽幀圖片Base64,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-01-01
Vue項(xiàng)目中使用jquery的簡(jiǎn)單方法
這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目中使用jquery的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
Vue的hover/click事件如何動(dòng)態(tài)改變顏色和背景色
這篇文章主要介紹了Vue的hover/click事件如何動(dòng)態(tài)改變顏色和背景色問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11

