目录
一、一些理解
初学时觉得这个概念比较模糊,知其然而不知其所以然,后面在学习中总结了学到的相关知识。
首先,this是JS中的一个关键字,this关键字很重要,不懂得话对以后的大多数开发任务都会有影响。
面向对象语言中 this 表示当前对象的一个引用,但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。
注意:this 既不指向函数自身,也不指函数的词法作用域,而是调用函数时的对象,从而可以利用this对对象进行操作。所以目前在我看来,学习this关键字,很重要的一点就是学会它在不同场景下指向谁。
二、一些场景的简单学习
当我第一次学习这个知识点时,就听到了广为流传的一句话:谁调用我,我就指向谁——尽管并不完全准确,比如不适合es6中的箭头函数,但还是能帮助理解,学习很多情况。
因为this更多用在函数中,所以下面研究this在不同位置定义的函数中的用法:
1、全局
场景1
:控制台直接输出this:
console.log(this)
结果:
分析:显而易见,在全局中控制台输出this,窗口调用this,this指向window对象
场景2
:全局函数中调用this:
function test(){ console.log(this) } test() //也是全局调用 被窗口调用,即window.test()
结果:
分析:你会发现this还是指向Window,回忆一下口诀:谁调用我,我就指向谁。其实我们定义的全局的函数、变量等都是挂在Window上的,即上面代码中的test(),就是window.test()。所以既然是window调用,自然也就指向window对象。
2、对象
场景
:对象调用this
let obj = { name:"wohenshuai", test:function (){ console.log(this) } } obj.test()
结果:
分析:obj调用下面的方法test(),this自然指向对象obj。
我们就可以很方便的拿到name:
let obj = { name:"wohenshuai", test:function (){ console.log(this.name) //控制台输出 wohenshuai } } obj.test() //this放在对象调用,指向obj,就可以轻松拿到obj.name
3、setTimeout()
介绍
:这个场景很特殊,首先介绍一下setTimeout()定时器,它其实是window对象下的一个方法,该方法用于在指定的毫秒数后调用函数或计算表达式。
比如:
setTimeout(function(){alert("hello")},5000) //五秒后后调用函数弹出hello
场景
setTimeout(function (){ console.log(111,this) },2000) //2s后window窗口自动帮你调用
结果:
分析:function作为回调函数,其实是看不见的,并非setTimeout调用的,很显然这是window窗口的一个调用机制,2s后window窗口自动帮你调用,自然也就还是指向window。
4、事件绑定的this
场景1
dom0 事件绑定
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>this指向</title> </head> <body> <div id="box">click</div> <script> //dom0 box.onclick = function (){ console.log(this) } //指向box节点 </script> </body> </html>
结果:
分析:为box绑定了一个点击事件,当点击click,调用函数。显然,box节点调用函数,this指向box节点。从而可以利用this指向对节点进行操作,比如:
box.onclick = function (){ console.log(this.innerHTML) }
场景2
dom2事件绑定
box.addEventListener("click",function (){ console.log("1111111111",this) })
结果:
分析:这个好像就不符合谁调用我我指向谁,因为function被调用 ‘并非’ 节点box,不过this如dom0一样指向节点box。
tips:所以不管是dom0还是dom2,this就是指向节点对象,从而拿到一些值、属性等等,进而进行一系列操作。
三、改变this指向
三种方法
- call()
- apply()
- bind()
call()
代码:
let obj1 = { name:"obj1", getName:function (){ console.log("getName",this.name) } } let obj2 = { name:"obj2", etName:function (){ console.log("getName",this.name) } } //call: 执行函数,并改变this指向为函数的第一个参数 obj1.getName.call(obj2,1,2,3) //通过call方法,把函数中的this指向强行改变为obj2
结果:
分析:
obj1 调用,而this通过call()强行指向了obj2
特点:
支持n个参数。
apply()
代码:
//apply: 执行函数,并改变this指向为函数的第一个参数 obj1.getName.apply(obj2) //通过apply方法,把函数中的this指向强行改变为obj2
结果:
分析:
这个结果好像和call()方法一样,那有什么不同之处呢?
call 与 apply 两者区别在于参数: call可以传n个参数;而apply只接收两个参数,且第二个参数为数组
bind()
代码:
//bind: : 执行函数,并改变this指向为函数的第一个参数,但不会自动执行函数 let fun1 = obj1.getName.bind(obj2) console.log(fun1) fun1() //返回值是一个新函数,fun1接收,新函数中的this指向obj2 //支持多个参数
结果:
分析:
这个方法与前两种不同,它的返回值是一个新函数,我用fun1接收,而新函数中的this指向obj2。且该函数不会自动执行。
四、总结
在JavaScript中,this关键字是一个指向当前作用域内的对象引用,它的值取决于函数如何被调用。以下是this的一些常见情况:
1、 全局
在非箭头函数中,如果this在顶级作用域或者作为全局变量声明,它会指向全局对象(在浏览器里通常是window,Node.js环境中是global)。
2、 函数作为对象的方法
this通常是指该对象自身。比如,如果你有一个函数绑定了到某个对象上,如obj.function(), this就会指向obj。
3、事件绑定函数中的this
在事件监听器中,除非显式地使用bind()方法,否则this通常指向触发事件的元素。
4、 使用call(), apply(), 和bind()
这三种方法可以改变this指向,允许你在特定对象上调用函数。