this在面试的时候是最常见的考点之一,也是我们必须要掌握的重要知识点,但是按照MDN上的描述:
this的值是当前执行上下文(global、function 或 eval)的一个属性,在非严格模式下,总是指向一个对象,在严格模式下可以是任意值。
那么然后我来简单的聊一下this在浏览器中的一些常见情况:
-
事件绑定
- 不论是DOM0还是DOM2级事件绑定,给元素ele的某个事件行为绑定方法,当事件触发执行,方法中的this是当前元素ele本身
document.body.onclick = function(){ console.log(this) //body } document.body.addEventListener('click',function(){ console.log(this) //body })-
特殊情况
-
IE6~8中给予attachEvent实现DOM2级事件绑定,事件触发方法执行,方法中的this不再是元素本身,大部分情况都是window,但是现在大部分企业已经不再兼容IE6~8,所以次情况可以忽略。
-
如果基于call/apply/bind强制改变函数中的this,我们都是以强制改变为主
-
-
普通函数
- 函数执行,看函数前是否有“点(.)”,如果有,那么“点”前边是什么this就表示什么,如果“点”前边什么都没有,this就表示window(非严格模式),严格模式下表示undefined
var a = 1; function fn(){ console.log(this.a) } var obj = { a:2, fn } var obj2 = { a:3, obj, fn } fn() //1 obj.fn() //2 var f = obj.fn; f() //1 obj2.obj.fn(); // 2 obj2.fn(); //3- 自执行函数,其内的this一般都是表示window(非严格模式)/undefined(严格模式),哪怕自执行函数写在对象哪依然如此
(function(){ console.log(this) //window })() var obj = { fn: (function(){ console.log(this) //window return 1 })() }- 回调函数中的this一般表示window(非严格模式)/undefined(严格模式),除非做过特殊处理
- 回调函数: 将一个函数a作为值(参数),传递给另一个函数b,当b执行的过程中,把传递进来的函数a执行...
setTimeout(function(){ console.log(this) //window },5000) var arr = [1]; var obj = {a: 1} arr.forEach(function(){ console.log(this) //window }) arr.forEach(function(){ console.log(this) //obj }, obj)- 如果基于call/apply/bind强制改变函数中的this,我们都是以强制改变为主
var a = 1; function fn(){ console.log(this.a) } var obj = { a:2, fn } var obj2 = { a:3, obj, fn } obj.fn.bind(obj2)() //3 -
new
首先来看一下new的过程中发生了什么:
- 创建一个空的简单JavaScript对象(即
{}); - 为步骤1新创建的对象添加属性 proto ,将该属性链接至构造函数的原型对象 ;
- 将步骤1新创建的对象作为
this的上下文 ; - 如果该函数没有返回对象,则返回
this。
通过上方我们可以看出,关于this最关键的是第三四点
- 如果函数
constructor里没有返回对象的话,this指向的是new之后得到的实例
function Foo(a){ this.a = a //这里this指向f return 1 } var f = new Foo(2) f.a //2- 如果函数
constructor里有返回对象的话,this指向的是返回的对象
function Foo(a){ console.log(this) this.a = a //这里this指向{a:10} return { a: 100 } } var f = new Foo(2) f.a //100 - 创建一个空的简单JavaScript对象(即
-
箭头函数
- 箭头函数本身没有this,其this完全继承上一级,上一级的this是什么,这里就会继承什么
function fn() { return { b: () => { console.log(this) } } } fn().b() // window fn().b.bind(1)() // window fn.bind(2)().b.bind(3)() // Number {2}-
总结
this取什么值是在函数执行的时候确定的,而不是在函数定义的时候确定的,在看this的取值的时候,关注相关函数的执行就好。
- 事件绑定,指向触发事件的元素(参考上方第1点)
- 当作普通函数被调用,指向window(参考上方第2点)
- 作为对象方法使用,指向对象本身(参考上方第2点)
- 使用call、bind、apply,看传入的参数(参考上方第2点)
- class中使用,大部分指向实例本身(这需要看一下上方的new相关部分上方第3点)
- 箭头函数,找其上一层作用域中的this(参考上方第4点)