在我没接触vue之前我不着调this是啥压根就没有接触过,在我学过了vue之后我知道了this,那时候理解的this就是你要使用data中的属性或调用methods中的方法等其他东西都要用this去调用,那时候其实我还是不知道this是啥,后面慢慢的才知道,当然我知道应该就是八股文背出来的,通过今天读这个源码,让我理解的更加深刻了,原来还可以这么用。

一、vue的使用

看这一段代码我们能知道有个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());

二、Vue的构造函数

接收一个options参数

  • 使用 instanceof 判断 this对象上是否出现了Vue的prototype,我们都知道this的指向是取决于谁调用
  • this._init(options) 证明在这调用要么我们创建的实例上有_init方法要么方法在Vue的prototype上,但是我们可以看到实例上并没有_init方法 ,那么肯定在一个地方给Vue的prototype上加上了_init方法 继续往下看
 function Vue(options) {if (!(this instanceof Vue)) {warn('Vue是一个构造函数,应使用“new”关键字调用');}this._init(options);
}
//Vue() //错误的调用方式 进入警告判断 此时this指向window 然后window的 window.__proto__的指向的Window构造函数的prototype

三 初始化initMixin(Vue)

在源码中会看到很多初始化的函数在这我们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

四 initState(vm)

这里就是对我们传入的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 */);}}

五 initMethods(vm, opts.methods)

如果有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

六 initData(vm)

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 instancevar 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 dataobserve(data, true /* asRootData */);}

七 proxy(vm, "_data", key)

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.methodsinitState(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可以直接访问的后面的都是差不多的,主要就是一个构造函数,然后创建一个实例,在实例上增加属性或者方法,这样我们就可以用实例对象直接访问了。原理就是那么简单。

总结给大家一个实用面试题库

 1、前端面试题库 (面试必备)            推荐:★★★★★

地址:前端面试题库

【面试题】Vue2为什么能通过this访问到data、methods的属性或方法相关推荐

  1. 访问母版页控件、属性、方法及母版页中调用内容页的方法

    首先,必须通过内容页中的MasterTye指令,对母版页实施强类型化,即在内容页代码头的设置中增加如下指令 <%@ MasterType VirtualPath="~/Master/M ...

  2. win7拒绝访问_win7系统提示无法访问application data如何解决

    有很多电脑用户都清楚application data是win7系统当中的应用程序数据文件夹,最近有位win7系统用户在访问application data文件夹的时候,系统却提示application ...

  3. 第60天:js常用访问CSS属性的方法

    一. js 常用访问CSS 属性的方法 我们访问得到css 属性,比较常用的有两种: 1. 利用点语法  box.style.width      box.style.top     点语法可以得到 ...

  4. 如何在Javascript中访问对象的第一个属性?

    本文翻译自:How to access the first property of an object in Javascript? Is there an elegant way to access ...

  5. 直接访问静态图片_详解nginx和tomcat访问图片和静态页面的配置方法

    概述 生产环境下,有时候需要访问图片,正常需要应用ftp.nginx等配套使用,但是有时候为了简化,可以用以下的两种简单的访问,说实话,就是为了偷懒,但是效果是能有的,这就行了,所以今天做这个简化版的 ...

  6. 线程访问 DevExpress控件异常时 解决方法

    线程访问 DevExpress控件异常时 解决方法 Control.CheckForIllegalCrossThreadCalls = false; DevExpress.Data.CurrencyD ...

  7. flash AS3.0访问加载的SWF文件中的属性、方法以及类、库中的影片剪辑

    对于FLASH,我们可以把任何的可视化元件都看成某个类文件的具体实例,包括swf文件. 我们可以把swf文件看成一个类的具体实例,而它里面拥有个个其他类的实例对象,例如: 我们新建一个loaded.f ...

  8. Android NDK学习笔记3:JNI访问Java属性、方法

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/119209444 本文出自[赵彦军的博客] 文章目录 Java 类型和JNI符号对比 ...

  9. 27、Python 面向对象(创建类、创建实例对象、访问属性、内置类属性、对象销毁、类的继承、方法重写、基础重载方法、运算符重载、类属性与方法、下划线双下划线)

    27Python面向对象(Python2) Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. ...

最新文章

  1. 前端的单页面模式和多页面模式
  2. python改变字符串类型_python – Sklearn将字符串类标签更改为int
  3. 给 ABAP ALV 报表的数据行增添颜色效果试读版
  4. 实现自己的.NET Core配置Provider之Yaml
  5. buck电路上下管_推荐 | 学好电路设计与仿真?你不能错过这两本书籍 ~
  6. 李伟山:金融撮合架构
  7. ARMLINUX学习笔记(1)
  8. springboot 妙启动_SpringBoot启动时执行指定任务
  9. Php 类似coffeescript,十个CoffeeScript一行程序——震惊你的小伙伴
  10. DSP实验报告—实验 4  编写一个汇编和 C 混合的 DSP 程序
  11. wiki搭建详细步骤
  12. 2021届西农计算机复试工作方案(学院)
  13. 加密文档的三种基本方法
  14. Python将头像照片转换为漫画,采用GAN深度学习,无噪点
  15. IBM小型机更换硬盘详细步骤
  16. “云钉一体”战略解读:阿里打通了数字化的“罗马引水桥”
  17. mysql的or能去重吗_mysql查询数据去重
  18. 数据结构-链表 JavaScript | 有图 | 有过程 | 有真相
  19. 为什么游戏玩家抗拒NFT?
  20. 人体工程学游戏椅行业调研报告 - 市场现状分析与发展前景预测(2021-2027年)

热门文章

  1. 阿里巴巴贷款信誉曝光
  2. MathType公式对齐不正确
  3. OpenCV3 C++ 写入AVI文件—读取彩色视频并转换为对数极坐标视频,包括创建新视频
  4. iOS开发 UILabel 详细介绍(属性+富文本)
  5. 重写highlighted改变按钮的按下状态、
  6. java assert函数_Java Assert 用法简介
  7. 基于图像处理的小目标计数
  8. DPDK盒子使用手册——DPDK入门zz
  9. 基本Widgets(29):【类】QMenu [官翻]
  10. 利用VBA 批量创建工作表