学习:https://blog.csdn.net/weixin_34000916/article/details/88581297
https://blog.csdn.net/lianjiuxiao/article/details/109839865
一、什么是this
this是在运行时基于函数的执行环境绑定的,它的上下文取决于函数调用时的各种条件。
当一个函数被调用时,会创建一个活动记录(有时候也称执行上下文)。这个记录会包含函数在哪里被调用,函数的调用方法、出入的参数等信息。this就是记录其中一个属性,会在函数执行的过程中用到。
this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象。
#this的绑定与函数声明的位置没有声明的位置没有任何关系,只取决于函数的调用方式
#一般来说,谁最终调用了函数,那么它就是this的绑定对象。
那在全局下调用函数,this的绑定对象也就是全局对象。
二、this的指向哪几种
参考回答:
默认绑定:全局环境中,this默认绑定到window。
隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象。
隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。显式绑定:通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。
new绑定:如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定。
- 在全局执行上下文中,this
的值指向全局对象。(在浏览器中,this
引用 Window 对象)。
- 在函数执行上下文中,this
的值取决于该函数是如何被调用的。如果它被一个引用对象调用,那么 this
会被设置成那个对象,否则 this
的值被设置为全局对象或者 undefined
(在严格模式下)。
- 当 new 一个新对象,this指向返回的那个对象。
- 箭头函数里的 this 在函数定义时指定,默认指向定义它时所处的对象。
【1】构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。
【2】如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。
【3】如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象。
1、默认绑定到window
1 | function a(){ |
2、对象内方法调用,绑定该对象
1 | var o = { |
情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题,你想了解可以自行上网查找。
情况2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
情况3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
**
注意:
1 | var o = { |
3、构造函数调用-new
1 | function Fn(){ |
注意:
如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。
1 | 例1: |
三、箭头函数
- 首先箭头函数是没有this的 ,它的作用域是和父级的上下文绑定在一起的,内部的this就是定义时上层作用域中的this。即它的this就是上一层第一个包裹它的普通函数的this。
- this定义时绑定。也就是说,箭头函数内部的this指向是固定的,this总是指向函数定义生效时所在的对象。
- 由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向,是没有效果的。
- 正是因为它没有this,所以也就不能用作构造函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var name = 'window'
const obj1 = {
name: 'obj1',
fn() {
this.name = 'fn'
inFn = () => {
console.log(this.name)
}
inFn()
}
}
obj1.fn()//'fn'
obj1.fn.call(window)//'fn'
- 箭头函数的this指向,是父级程序的this指向
- 如果父级程序有this指向,指向向的就是父级程序的this指向
- 如果父级程序没有this指向(对象,数组是没有this),指向的是window
1
2
3
4
5
6
7
8
9var myObject = {
a:'myObject.a',
foo: ()=>{
console.log(this.a)
}
};
var a = 'window.a'
myObject.foo() // 'window.a'四、定时器对this的影响
setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致,这些代码中包含的 this 关键字在非严格模式会指向 window (或全局)对象,严格模式下为 undefined,这和所期望的this的值是不一样的。
备注:在严格模式下,setTimeout( )的回调函数里面的this仍然默认指向window对象, 并不是undefined1
2
3
4
5
6
7
8
9
10
11
12
13this.name = 'window'
function Foo() {
this.name = 'Foo'
this.fn = function () {
console.log(this.name)
}
this.timer = function () {
setTimeout(this.fn)
}
}
var obj = new Foo()
obj.timer() //'window'解决setTimeout中的this指向问题
当在vue中使用定时器来修改一个变量值的时候,发现没有效果,这是由于setTimeout函数调用的代码运行在与所在函数完全分离的执行环境上,这会使得this指向的是window对象。
要想setTimeout指向正确的值,可以使用如下方法:1、可以使用call/apply/bind调用改变this绑定对象。
1
2
3
4
5
6
7
8
9
10
11
12
13this.name = 'window'
function Foo() {
this.name = 'Foo'
this.fn = function () {
console.log(this.name)
}
this.timer = function () {
setTimeout(this.fn.call(this))
}
}
var obj = new Foo()
obj.timer() //'Foo'2、使用箭头函数
此时函数的this指向的是定义它的时候的对象,也就是this指向了data内中对应的变量。1
2
3
4
5
6
7
8
9
10
11const obj = {
name: 'obj',
fn() {
console.log(1)
setTimeout(() => {
console.log(this.name)
}, 1000)
}
}
obj.fn()// 1 'obj'1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16export default {
data () {
return {
left: -9999,
bottom: -9999
}
},
methods: {
cancelMask: function () {
setTimeout(() => {
this.bottom = 0;
this.left = 0;
}, 500);
}
}
}
3、将当前对象的this保存为一个变量
1 | export default { |
方法中将this存在一个对象中,此时执行setTimeout函数时,setTimeout函数内的that就会访问到这个变量,就会得到当前对象。