一、思考:
1.为什么不能使用箭头函数来定义methods?
答:因为箭头函数没有自己的作用域,绑定的是父级作用域的上下文,
如果使用箭头函数,那么在获取data里面的数据的时候,this指向window导致访问失败
原因:这跟this的绑定规则有关,在箭头函数中不绑定this,但是如果箭头函数使用了this,会往上层作用域去找,注意:methods对象并不是作用域(所有的对象都没有作用域)
2.不使用箭头函数的情况下,this到底指向什么?
答:vue源码通过bind显式绑定指向vue实例的proxy(代理)
二、this指向:
首先,我们必须先知道,每个函数都会有自身的this,但是this并不是在函数声明完就绑定到某个对象上的,只有在函数调用时,this才会被绑定,
也就是说,this的绑定和函数定义的位置没有关系,和函数的调用方式有关系。
常见的this指向:
- 全局作用域中或者普通函数中this指向全局对象window
- 立即执行函数this必定指向window
- 定时器this指向window
- 事件中this指向事件源对象
- 方法中谁调用就指向谁
- 构造函数中this指向对象实例
三、this绑定规则:
1、默认绑定规则
1.默认绑定全局对象window
console.log(this === window); //true
复制代码
2.全局作用域下独立调用函数,this指向window
function test() {
console.log(this===window); //true
}
test();
复制代码
2、隐式绑定规则
理解:谁调用就指向谁
1.对象内调用方法
let obj = {
name: 'obj',
foo: function () {
console.log(this); //this指向obj
}
}
obj.foo()
复制代码
2.修改一下:
let obj = {
name: 'obj',
foo: function () {
console.log(this); //obj
function test() {
console.log(this); //window 为什么? 因为test独立调用
}
test()
}
}
obj.foo()
复制代码
3.隐式丢失:
let obj = {
name: 'obj',
foo: function () {
console.log(this); //window 为什么不是obj? bar拿到obj.foo的引用,然后在全局下独立调用
}
}
let bar = obj.foo
bar()
复制代码
4.函数作为参数:
function foo() {
console.log(this); //window obj.foo在bar函数内独立调用
}
function bar(fn) {
fn()
}
let obj = {
name: 'obj',
foo: foo
}
bar(obj.foo)
复制代码
4.1函数作为参数时,参数函数叫做子函数,外面的函数叫父函数,子函数也叫回调函数,像这样的函数有很多,
比如forEach 、setimeout,这些函数里的参数函数也叫内置参数
记住:父函数有能力决定子函数this的指向,例如forEach里第一个参数是一个函数,第二个参数就是this绑定的对象,不写默认绑定window
3、显式绑定
call、apply、bind bind返回一个新函数,新函数指向绑定的对象,旧函数不会
4、new绑定
this指向函数实例化之后的对象
5、绑定规则优先级:
new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
四、箭头函数this指向问题:
1.箭头函数没有自己的this指向,它的this指向上一级作用域的this
1.1之前,我们想让内部函数的this指向外部函数的this,我们只能这样:
var a = 0
function foo() {
let that = this //指向obj
console.log(this);
function test() {
console.log(that) //指向obj
}
test()
}
let obj = {
a: 1,
foo: foo
}
obj.foo()
复制代码
1.2或者使用bind/call/apply显式绑定外部函数的this:
var a = 0
function foo() {
console.log(this); //指向obj
function test() {
console.log(this);
}
test.call(obj)
}
let obj = {
a: 1,
foo: foo
}
obj.foo()
复制代码
2.箭头函数this指向不遵循上述的四种规则:
2.1独立调用对箭头函数无效:
var a = 0
function foo() {
let test = () => {
console.log(this)
}
return test
}
let obj = { a: 1, foo: foo }
obj.foo()()
// obj.foo()返回test obj.foo()()调用test 而且是独立调用 但是this还是指向obj
复制代码
隐式绑定对箭头函数无效:
let a = 0
let obj1 = {
a: 1,
foo: () => {
console.log(this);
}
}
obj1.foo() //指向window
复制代码
2.3显式绑定对箭头函数无效:
var a = 0
function foo() {
let test = () => {
console.log(this)
}
return test
}
let obj1 = {
a: 1,
foo: foo
}
let obj2 = {
a: 2,
foo: foo
}
obj1.foo().call(obj2)
//obj1.foo()返回test obj1.foo.call(obj2)把test的指向绑定到obj2上,无效,this依然指向obj1
复制代码