this的指向,组件实例对象的创建方式,构造函数和实例对象的继承关系
欢迎来到我的博客!
使用 Markdown 格式编写。
今天学到了什么
- this的指向
- 组件实例对象的创建方式
- 构造函数和实例对象的继承关系
this的指向
“谁调用,这个函数里的 this 就是谁”这句话只在一种常见写法下成立:普通函数 + 以点调用形式执行。更准确的版本是:
- 对“普通函数”(非箭头)来说,
this由“调用形式”决定,而不是由“函数写在哪”决定。
下面把最常见的几种“调用形式”列清楚,你就不会混了:
obj.fn():this === obj(这就是你说的“谁调用指向谁”最典型的情况)fn():this === undefined(严格模式)/window(非严格模式)fn.call(x, ...)/fn.apply(x, ...):this === xfn.bind(x):返回一个新函数,之后无论怎么调用,this都固定是xnew Fn():this是新创建的实例对象- 箭头函数:没有自己的
this,this永远取决于“定义时外层的this”(跟怎么调用无关)
结合你这行代码看:vue_test/10_src_组件自定义事件/App.vue
this.$refs.student.$on('atguigu', this.getStudentName)这里其实出现了 3 个不同层面的“this”:
- 在
mounted()里写的this:是 App 实例(Vue 调用生命周期钩子时把this设成当前组件) $on这个方法执行时的this:是 **this.on(…)` 这种点调用- 回调
this.getStudentName里this为什么还是 App:因为它是从methods里取出来的函数,Vue2 通常已经把它绑定到 App 上了(等价于你传了一个“已经bind(App)的函数”);所以后续触发事件时,就算内部想用call/apply改this,也改不掉
如果你把回调改成普通函数:
this.$refs.student.$on('atguigu', function () { console.log(this)})那这时就更像你说的那套:触发时 Vue 会以某种形式调用它,this 往往会指向 Student(触发 $emit 的组件实例)。
组件实例对象的创建方式
new出来的也是实例对象,那我new出来demo之后,我再写
对,是两个不同的实例对象(两个 vc),但它们来自同一个组件构造函数/组件定义。
把概念拆开就清楚了:
1)Demo 是什么?
const Demo = Vue.extend({...}) 得到的 Demo 是组件构造函数(可以理解成“类”)。
2)new Demo() 会得到什么?
const d = new Demo() 得到的是一个组件实例对象(vc)。
它只是在内存里创建了一个 Demo 实例,除非你 $mount 并插入 DOM,否则页面上未必有它。
3)<Demo /> 会得到什么?
你在模板里写 <Demo />,Vue 在渲染时也会再创建一个 Demo 的组件实例对象(vc),并负责它的挂载、更新、销毁。
所以:
d = new Demo()是你手动创建的 实例 A- 模板里的
<Demo />渲染出来的是 Vue 自动创建的 实例 B - A !== B,它们是两个不同对象,只是“同一个组件类型”的两个实例
它们会互相影响吗?
默认不会(各自有自己的 data/生命周期/DOM)。
但如果你把它们都挂到页面、并且共享同一个外部对象(比如都引用了同一个全局变量/同一个 Vuex store/同一个单例对象),那表现上可能“看起来像联动”,本质是共享了外部状态,不是同一个实例。
构造函数和实例对象的继承关系
实例对象不会继承构造函数身上的东西吗?
不会。实例对象不会“继承构造函数对象本身(静态属性)”上的东西,实例只会沿着它的原型链去找属性。
把关系画成一条链你就懂了:
- 构造函数本身是一个对象:
Vue
你写Vue.x = 123是给这个“函数对象”加属性(静态属性)。 - 实例对象是
new Vue()/ 组件实例:vm
vm的原型链是:vm → Vue.prototype → Object.prototype ...
注意:原型链里有 Vue.prototype,没有 Vue 本身。
所以:
Vue.prototype.x = 123✅vm.x能找到(从原型上继承)Vue.x = 123❌vm.x找不到(因为Vue不在vm的原型链上)
一个最小原生 JS 例子(和 Vue 一样的规则):
function Foo() {}Foo.a = 1 // 静态属性Foo.prototype.b = 2 // 原型属性
const f = new Foo()f.a // undefinedf.b // 2如果你真的想让实例能访问到构造函数的静态属性,得自己“绕一下”,比如:
- 在原型方法里用
this.constructor去拿:this.constructor.a - 或者手动把
Foo.a挂到Foo.prototype上
但在 Vue2 里,为了让组件里直接 this.$xxx 用,约定俗成就是挂 Vue.prototype.$xxx。
赞助支持
如果这篇文章对你有帮助,欢迎赞助支持!
部分内容可能已过时