普通函数中this
普通函数内部的this
对象指向的是在函数执行时绑定的对象,也就是说函数创建的时候是没办法确定这个this
到底指向的是谁的
function fn() {
console.log(this) // 创建时this没有指向性
}
fn() // 执行时才确定this指向,因为是在window环境下执行的所以指向window对象
var obj = {}
obj.f = fn
obj.f() // 执行时确定this对象,指向绑定的obj对象
document.onclick = fn // 绑定时确定this对象,指向触发该事件的document对象
document.onclick = function() {
let fn = function() {
console.log(this)
}
fn() // window
}
箭头函数中this
箭头函数的this
在函数创建期间就绑定好了,它的this
指向创建该函数所在的作用域对象
let fn = () => {
console.log(this) // 确定this,指向fn所在的作用域,也就是window
}
fn() // this指向window
document.onclick = fn // this依旧指向fn声明时候所在的作用域window
document.onclick = function() {
let fn = () => {
console.log(this)
}
fn() // document
}
总结:不能通过call
apply
bind
去改变箭头函数其内部的 this 指向
class(类)中的this
类中的方法内部如果含有this
,它默认指向类的实例,但是一旦单独使用,很可能报错
class Logger {
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined
因为 printName
方法中的 this
, 默认指向 Logger
类的实例,但是如果将这个方法提取出来单独使用,this
就会指向该方法运行时所在的环境,从而导致找不到 print
方法而报错
应用对比
let lis = document.querySelectorAll('li')
for(let i = 0; i < lis.length; i++) {
lis[i].onclick = function() {
let fn = function() {
this.style.background = 'red'
}
setTimeout(fn, 1000)
}
}
此时会报错Cannot set property 'background' of undefined
因为setTimeout
是window
的方法,所以这里其实是简写window.setTimeout
的写法,也就是说此时setTimeout
里面的函数fn
中的this
指向的其实是window
这个对象,我们没办法对window
对象设置背景色,所有才会报错,其实我们想要的是希望这里的this
指向我们的绑定元素li
,那我们可以使用箭头函数这样写
let lis = document.querySelectorAll('li')
for(let i = 0; i < lis.length; i++) {
lis[i].onclick = function() { // function是普通函数,调用时候就是li click的时候所以this就是li
let fn = () => { // 定义箭头函数时这个作用域中的this就是li
this.style.background = 'red'
}
setTimeout(fn, 1000)
}
}
此时fn
中的this
指向的就是其创建时的作用域,也就是lis[i]
这个元素对象
这里onclick
绑定的函数就不能用箭头函数了,否则就没办法将其this
保留住了,所以一般事件函数我们都不要用箭头函数,否则函数中的this
就没办法绑定这个事件元素对象了
如果我们将事件绑定定义的函数也用箭头函数,此时的 this
又会发生变化
let lis = document.querySelectorAll('li')
for(let i = 0; i < lis.length; i++) {
lis[i].onclick = () => { // 箭头函数定义是在window环境下,所以this就是window
let fn = () => { // 定义箭头函数时这个作用域中的this就是window
this.style.background = 'red'
}
setTimeout(fn, 1000)
}
}
原文链接:https://www.csdn.net/tags/Mtjacg0sMDQ5OTktYmxvZwO0O0OO0O0O.html#this_3