this指向问题最核心的一句话:
哪个对象调用函数,函数里面的this就指向哪个对象
理解起来是有点抽象
下面是一些列子
1、普通函数调用
2、对象函数调用
3、构造函数调用
4、apply、call调用
5、箭头函数调用
一、普通函数调用
在非严格模式下,this的指向都是window
下面需要注意let、var不同写法的区别
先介绍下let、 var,let是块级作用域变量,写在函数中则只在函数内部有效。var申明的变量要不是全局的,要么就是函数级别的,不是块级的
这里用代码简单介绍下let、var
都是let的情况下
<script>
let fn = function() {
let name = 'tom'
if (true) {
let name = 'pig'
console.log(name);
}
console.log(name);
}
fn()
</script>
先使用let后使用var
<script>
let fn = function() {
let name = 'tom'
if (true) {
var name = 'pig'
console.log(name);
}
console.log(name);
}
fn()
</script>
会发现报错,因为var相当于函数级作用域,相当于一个函数作用域中有两个n的变量,var作用于整个fn,和let冲突了,let不能重复的声明,already been declared=已经被声明。
先var 后let的情况
<script>
let fn = function() {
var name = 'tom'
if (true) {
let name = 'pig'
console.log(name);
}
console.log(name);
}
fn()
</script>
这里没发现报错因为先声明var再声明let是可以的
上面可以简单的对var let有个理解,方便理解下面的知识
1、使用let
<script>
let name = "tom"
function fn() {
console.log(this.name); //undefind
}
fn();
</script>
这里打印出来的是undefined
2、使用var
<script>
var name = "tom"
function fn() {
console.log(this.name); //tom
}
fn();
</script>
这里打印出来的是tom
区别就是上面描述的
3、使用window
<script>
window.name = "tom"
function fn() {
console.log(this.name); //tom
}
fn();
</script>
打印出来的是tom
二、对象函数调用
简单的理解就是哪个函数调用,this就指向哪里
<script>
let name = "tom"
let obj = {
id: 121,
fn: function() {
console.log(this.name);
console.log(this.id);
}
}
obj.fn()
</script>
这里obj调用了函数,所以this指向指向了obj,obj中只有id没有那么
这里会出现b赋值给a然后a调用,注意this指向不要搞混
<script>
let obj1 = {
name: "tom"
}
let obj2 = {
name: "pig",
fn: function() {
console.log(this.name);
}
}
obj1.fn = obj2.fn
obj1.fn()
</script>
再次声明:哪个函数调用this就指向哪里
三、构造函数调用
<script>
let fn = function() {
this.name = "tom"
}
let fn1 = new fn()
console.log(fn1.name);
let fn2 = new fn()
fn2.name = "pig"
console.log(fn2.name);
</script>
这里可以看到this指向
这里需要注意return的出现
<script>
let fn = function() {
this.name = "tom"
return {
username: 'age'
}
}
let fn1 = new fn()
console.log(fn1);
console.log(fn1.name);
</script>
这里发现return中的this指向指向的直接指向这个对象,而不是函数
四、apply和call、bind
上面介绍了this在函数中的指向问题,在现实中我们可以改变this的指向,比如apply、call、bind
apply
用法:改变函数中的this指向。
xxx.apply(对象名,数组) 就是将xxx函数中的this指向指向对象名,数组中的元素依次与元素的参数对应
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn(1, 2)
var obj = {
name: 'tom'
}
fn.apply(obj, [3, 4])
call
用法:改变函数中的this指向问题,和apply的区别是第二个参数不为数组
xxx.call(对象名,参数1,参数2,参数3.......) 就是将xxx函数中的this指向指向对象名,参数中的元素依次与元素的参数对应
<script>
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn(1, 2)
var obj = {
name: 'tom'
}
fn.call(obj, 3, 4)
</script>
bind
用法:改变函数中的this指向问题,和call写法一样,不同的地方是bind返回的是一个函数,所以我们在调用的时候在进行传参
xxx.bind(对象)(参数1,参数2......)
<script>
function fn(a, b) {
console.log(this);
console.log(a + b);
}
fn(1, 2)
var obj = {
name: 'tom'
}
fn.bind(obj)(3, 4)
</script>
五、箭头函数调用
ES6中提供的箭头函数,箭头函数中没有this,箭头函数中的this是继承外部函数的this。
<script>
let obj = {
name: 'tom',
fn: function() {
setTimeout(function() {
console.log(this.name)
})
}
}
obj.fn()
</script>
这里的到的this.name为undefined,因为普通函数中的this指向的是window对象,这里window中并没有定义name,所以为空。
<script>
let obj = {
name: 'tom',
fn: function() {
setTimeout(() => {
console.log(this.name)
})
}
}
obj.fn()
</script>
这里使用箭头函数,在定时器中找不到this指向会向上级查找,所以是tom