Vue.js中this如何取到data和method里的属性详解
前端摸鱼儿 人气:0本篇文章介绍的是
Vue.js
如何取到data
和methods
里的属性?
准备工作
- 克隆源码到本地
git clone https://github.com/vuejs/vue.git
下载完毕后,用vscode
打开,目光移动到package.json
的scripts
属性,我们看到有dev
和build
,dev
会启动一个开发环境的服务,也就是说,我们在源码里做的改动,都会及时生效。build
就是打包。和我们平时开发Vue.js
项目是一个道理。
我们首先安装一下Vue.js
项目的依赖(使用pnpm
),然后运行npm run dev
。这样的好处就是我们能随时看到代码改动后的效果。
- 接下来我们在
examples
目录下创建一个html
文件,引入打包后的vue.js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <h1 @click="changeMsg">hello {{msg}}</h1> </div> <script src="../dist/vue.js"></script> <script> const vm = new Vue({ el: '#app', data: { msg: 'world' }, methods: { changeMsg() { this.msg = 'me' } } }) </script> </body> </html>
- 安装一个
serve
全局包启动, 在根目录运行一下serve
,就能看到页面展示出来了。
调试源码
我们这里使用谷歌浏览器调试,F12
找到sources
面板如下图所示的位置打上断点,接着刷新页面,就进入了调试模式。
然后,我们就通过step into
按钮进入new Vue
的函数内部。 接着进入_init
的内部,找到initState(vm)
,也就是当前文件代码的4714行,这个函数的内部就是我们要研究的部分。
进入initState
内部,我们看到
if (opts.methods) initMethods(vm, opts.methods); if (opts.data) { initData(vm); }
initMethods
function initMethods(vm, methods) { var props = vm.$options.props; for (var key in methods) { { if (typeof methods[key] !== 'function') { warn$2("Method \"".concat(key, "\" has type \"").concat(typeof methods[key], "\" in the component definition. ") + "Did you reference the function correctly?", vm); } if (props && hasOwn(props, key)) { warn$2("Method \"".concat(key, "\" has already been defined as a prop."), vm); } if (key in vm && isReserved(key)) { warn$2("Method \"".concat(key, "\" conflicts with an existing Vue instance method. ") + "Avoid defining component methods that start with _ or $."); } } vm[key] = typeof methods[key] !== 'function' ? noop : bind$1(methods[key], vm); } }
- 首先判断组件内部是否声明了函数
- 其次判断是否和
props
、保留键名的名字冲突了 - 最后是处理逻辑,如果对应值的类型是函数将传入的
vm
对应的属性赋值,否则为noop
,赋值的函数这里做了一个强绑(使用的bind
,this
指向vm
)。这个bind$
来自原生的bind
方法
var bind$1 = Function.prototype.bind ? nativeBind : polyfillBind;
initData
调试完了initMehtods
后,就开始initData
,我们使用step out
按钮就跳出了当前函数,接着进入initData
内部。
function initData(vm) { var data = vm.$options.data; data = vm._data = isFunction(data) ? getData(data, vm) : data || {}; if (!isPlainObject(data)) { data = {}; warn$2('data functions should return an object:\n' + 'https://v2.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]; { if (methods && hasOwn(methods, key)) { warn$2("Method \"".concat(key, "\" has already been defined as a data property."), vm); } } if (props && hasOwn(props, key)) { warn$2("The data property \"".concat(key, "\" is already declared as a prop. ") + "Use prop default value instead.", vm); } else if (!isReserved(key)) { proxy(vm, "_data", key); } } // observe data var ob = observe(data); ob && ob.vmCount++; }
逻辑和initMethods
类似,和props
、methods
做了比对,最后通过proxy
将data
,绑定到vm
上
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); }
最终我们知道data
的值是通过Object.defineProperty
,实现绑定的。
结束语
我们要研究一个源码,首先要准备源码、serve、和调试工具(谷歌浏览器),然后进入代码的内部,才能看的清楚明白,我们就此知道了Vue.js
的this
如何取到data
和methods
的属性。
加载全部内容