<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在我沒接觸vue之前我不著調this是啥壓根就沒有接觸過,在我學過了vue之後我知道了this,那時候理解的this就是你要使用data中的屬性或呼叫methods中的方法等其他東西都要用this去呼叫,那時候其實我還是不知道this是啥,後面慢慢的才知道,當然我知道應該就是八股文背出來的,通過今天讀這個原始碼,讓我理解的更加深刻了,原來還可以這麼用。
看這一段程式碼我們能知道有個Vue的建構函式 ,然後我們使用new Vue建立了它的範例,並給它傳了一個物件引數,裡面有data和methods,那麼在這個Vue建構函式做了什麼才能讓我使用this可以直接存取裡面的屬性或者方法呢?
//建立vue的範例 const vm = new Vue({ data: { desc: '為什麼this能夠直接存取data中的屬性', }, methods: { sayName() { console.log(this.desc); } }, }); console.log(vm.name); console.log(vm.sayName());
接收一個options引數
function Vue(options) { if (!(this instanceof Vue) ) { warn('Vue是一個建構函式,應使用「new」關鍵字呼叫'); } this._init(options); } //Vue() //錯誤的呼叫方式 進入警告判斷 此時this指向window 然後window的 window.__proto__的指向的Window建構函式的prototype
在原始碼中會看到很多初始化的函數在這我們initMixin()
這個函數就是在Vue的原型上增加了_init方法,方法接收一個引數,然後定義了vm變數,在我看的時候就想看看這個函數的this指向誰,其實也不難函數掛在Vue建構函式的原型上,呼叫還是在建構函式裡面使用this呼叫,建構函式的this指向Vue範例,根據this的指向規則 此時的vm就指向了Vue建構函式的範例。
使用this的存取規則如果範例上沒有就去原型上找
然後執行 initState(vm)
initMixin(Vue) function initMixin(Vue) { //prototype上增加init方法 Vue.prototype._init = function (options) { var vm = this; //Vue範例 vm.age = 30 //程式碼進行了刪減 initState(vm); } } //這裡只是舉例測試 const vm = new Vue({}) console.log(vm.age) //30
這裡就是對我們傳入的data 或者methods進行不同的處理
//initState方法程式碼進行了刪減 function initState(vm) { vm._watchers = []; var opts = vm.$options; //這裡是我們在建立範例的時候傳的引數 //如果傳了methods 則去呼叫 if (opts.methods) { initMethods(vm, opts.methods); } if (opts.data) { initData(vm); } else { observe(vm._data = {}, true /* asRootData */); } }
如果有methods則取呼叫initMethods方法
前面主要是判斷 methods中的值是不是函數,key有沒有跟props衝突等
最後一段程式碼就是在vm的範例上增加方法vm[key]=methods[key],在讀的時候我有這樣一個以為為什麼還要用bind改變this指向呢不本來就是寫在vm範例上的方法嗎 只能使用vm呼叫 那麼方法的this不就指向vm嗎?
/* vm:建構函式範例 methods:我們傳的methods物件 */ function initMethods(vm, methods) { var props = vm.$options.props; //迴圈methods物件 for (var key in methods) { { //判斷是否是函數 不是的化則作出警告 if (typeof methods[key] !== 'function') { warn( "Method "" + key + "" has type "" + (typeof methods[key]) + "" in the component definition. " + "Did you reference the function correctly?", vm ); } //判斷 methods 中的每一項是不是和 props 衝突了,如果是,警告。 if (props && hasOwn(props, key)) { warn( ("Method "" + key + "" has already been defined as a prop."), vm ); } //判斷 methods 中的每一項是不是已經在 new Vue範例 vm 上存在,而且是方法名是保留的 _ $ (在JS中一般指內部變數標識)開頭,如果是警告。 if ((key in vm) && isReserved(key)) { warn( "Method "" + key + "" conflicts with an existing Vue instance method. " + "Avoid defining component methods that start with _ or $." ); } } //給範例增加methods中的方法 這樣其實我們就已經可以用vm存取 到methods中的方法了 vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm); } }
問了群裡大佬之後原來這步操作時為了防止使用者改變this指向,專門做了個例子
在這我有定義了物件a裡面有個age屬性和fn,fn我賦值vm範例上的sayHi,然後a.fn()呼叫很明顯this的指向已經被改變了,使用bind之後則不會
const vm = new Vue({ methods: { sayHi() { console.log(this.age, 'hello-this') } } }); let a = { age: 15, fn: vm.sayHi } console.log(a.fn(), 'vm') //列印15
data是如何做到的使用this可以直接存取的,其實原理都一樣,
首先在vm範例上增加了_data,裡面存的我們傳入的data引數
function initData(vm) { var data = vm.$options.data; data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}; //如果不是物件則警告 if (!isPlainObject(data)) { data = {}; 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 var keys = Object.keys(data); var props = vm.$options.props; var methods = vm.$options.methods; var i = keys.length; while (i--) { var key = keys[i]; //判斷key值有沒有跟methods中的key重名 { if (methods && hasOwn(methods, key)) { warn( ("Method "" + key + "" has already been defined as a data property."), vm ); } } //判斷key值有沒有跟props中的key重名 if (props && hasOwn(props, key)) { 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 */); }
get 和 set 方法 注意裡面的this 指向vm範例物件,上面已經在vm範例物件上增加了_data 所有在獲取或者設定屬性值的時候 都是this._data[key] 也就是vm._data[key],
然後通過Object.defineProperty往範例物件上新增屬性,所以當我們存取vm[key] 也就是 vm._data[key]
function proxy (target, sourceKey, key) { sharedPropertyDefinition.get = function proxyGetter () { return this[sourceKey][key] }; sharedPropertyDefinition.set = function proxySetter (val) { this[sourceKey][key] = val; }; Object.defineProperty(target, key, sharedPropertyDefinition); }
//建立vue建構函式 function Vue(options) { if (!(this instanceof Vue) ) { warn('Vue是一個建構函式,應使用「new」關鍵字呼叫'); } this._init(options); } //初始化 initMixin(Vue); function initMixin(Vue) { //prototype上增加init方法 Vue.prototype._init = function (options) { var vm = this; //Vue範例 let methods = options.methods initState(vm); } } //initState方法程式碼進行了刪減 function initState(vm) { vm._watchers = []; var opts = vm.$options; //這裡是我們在建立範例的時候傳的引數 //如果傳了methods 則去呼叫 if (opts.methods) { initMethods(vm, opts.methods); } if (opts.data) { initData(vm); } else { observe(vm._data = {}, true /* asRootData */); } } /* vm:建構函式範例 methods:我們傳的methods物件 */ function initMethods(vm, methods) { var props = vm.$options.props; //迴圈methods物件 for (var key in methods) { { //一些條件判斷 } //給範例增加methods中的方法 這樣其實我們就已經可以用vm存取 到methods中的方法了 vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm); } } const vm = new Vue({ methods: { sayHi() { console.log('hello-this') } } }); vm.sayHi() //hello-this
其實看明白了Methods是怎麼做到直接用this可以直接存取的後面的都是差不多的,主要就是一個建構函式,然後建立一個範例,在範例上增加屬性或者方法,這樣我們就可以用範例物件直接存取了。原理就是那麼簡單。
到此這篇關於Vue2為何能通過this存取到data與methods的屬性的文章就介紹到這了,更多相關Vue2存取data內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45