相信很多小伙伴,初学js的时候都会被this弄的焦头烂额。this关键字是一个非常非常重要的点,毫不夸张的说,如果不了解this,基本上所有的开发任务都不能完成。
首先:你要记住this的重点,这会帮你理解下面的内容
1、this永远指向一个对象
2、this对象,通过不同的方式调用函数,this的指向就不同
核心一句话 - 哪个对象调用函数,函数里面的this指向哪个对象。
针对第一点,无论在什么地方使用this,this必然指向某个对象;剩下的就剩一个问题,this到底指向哪,在javaScript中,万物皆对象,所有的函数都是在某个对象下运行,而this就是指向函数所运行的对象,这本来很好理解,可是this随着函数的使用场景不同,this的值就会发生变化。这也就是说,this的指向是动态的,很难事先确定好this指向哪个对象,这才上让我们感到困惑的地方。
function fn(){
console.log(this.age)
console.log(this)
}
let obj = {
age : 20,
f : fn
}
var age = 10;
fn() //调用fn()this指向window,age为10
obj.s() //通过对象调用fn(),age为20
上面,this被调用了两次,结果也是不一样的。
在全局作用域下调用fn()
,fn()
指向全局作用域对象window
;
而obj.s()
运行在对象内运行,this
指向当前对象;
而我们要清除的是this的指向为什么会发生改变,this的指向改变是怎么发生的
函数、对象、数组,都是(复合)引用数据类型,引用数据类型在栈内存中实际保存的是对象在堆内存的引用地址,通过这个引用地址可以快速找到保存在堆内存中的对象。
上方obj有两个属性,但是属性的值类型却是不一样的,所有在内存中储存方式的也不一样。
因为函数既可以当做值传递也是一个对象和构造函数。所以函数在运行的时候确定了当前的运行环境,this是函数体自带的一个对象指针,而this指向调用对象。所以,this会根据运行环境的改变而改变,同时this也只能在运行时才能确认运行环境。
事件绑定的三种方式:行内绑定、动态绑定、事件监听
行内绑定分为两种情况
<button onclick="fn(this)">发送1</button>
<button onclick="fn()">发送2</button>
function fn(obj) {
console.log(this) // 此函数的运行环境在全局window对象下,因此this指向window;
console.log(obj) //this作为实参传递,this指向当前节点对象
}
动态绑定和事件监听
因为动态绑定的事件本就是为节点对象的属性(事件名称前面加'on')重新赋值为一个匿名函数,因此函数在执行时就是在节点对象的环境下,this自然就指向了本节点对象;
下面是this在各个不同环境下的具体指向
一、this指向window
(1)this如果单独使用,this 表示全局对象。
var x = this
document.querySelector('body').innerHTML = x //[object Window]
输出结果是 [object Window];
(2)在函数中,this 表示全局对象
function fn(){
console.log(this)
}
fn() //window
(3)定时器调用函数,this指向window
setInterval(function(){
console.log(this) //这里this指向window
}, 1000)
(4)行内绑定事件(DOM0级)通过函数名+()形式调用this指向window
<button onclick="fn()">发送</button>
<script>
function fn(){
console.log(this)
}
二、this指向事件对象
(1)在事件中,this 表示事件调用的节点对象。
<button>发送</button>
<script>
let btn = document.querySelector('button')
btn.onclick = function fn(){
console.log(this)
}
</script>
this指向当前<button>发送</button>
(2)行内绑定事件时通过函数名+(this)形式,this指向调用的节点对象
<button onclick="fn(this)">发送</button>
<script>
function fn(res){
console.log(res)
}
</script>
this指向<button onclick="fn(this)">发送</button>
(3)DOM2级事件调用,this指向调用的节点对象
<button>发送</button>
<script>
let btn = document.querySelector('button')
btn.addEventListener('click',function(){
console.log(this)
},false)
</script>
三、this指向对象
let obj = {
name: '张三',
say(){
console.log(this)
}
}
obj.say() //obj
this指向对象obj
四、this指向数组
let arr = ['张三','李四','小甜甜',fn]
function fn(){
console.log(this)
}
arr[3]() //arr
五、构造函数中的this指向
function Fn(){
this.name = '张三'
this.say = function(){
console.log(this)
}
}
let res = new Fn();
res.say()
console.log(res)
构造函数中的this指向new创建的新对象
六、箭头函数=>的this指向
箭头函数本身上面是没有this,它的this可以去上一层去找,正是因为箭头函数没有this绑定,所有箭头函数不能用于构造函数。
箭头函数中this指向宿主对象
<button>发送</button>
<script>
let btn = document.querySelector('button')
btn.onclick = function fn(){
setInterval(()=> {
console.log(this)
}, 1000);
}
</script>
定时器原本this指向window,使用箭头函数this去上一层,this指向<button>发送</button>