何为this
一般而言,在JavaScript中,this指向函数执行时的当前对象。换句话说,这个关键字与函数的执行环境有关,与声明环境无关。所以this的指向要看如何去调用这个函数而不是声明。
不同调用方式中的this
作为对象的方法调用
把函数赋值给对象的一个属性,然后通过该对象调用该方法,此时函数的执行环境就是这个对象,所以this指向该对象
1 | var name = 'lala'; |
换个更清晰的写法,我们把声明和调用放在两个对象里面
1 | var obj = { |
可以看到show虽然是在obj中声明的,但是通过t_obj调用了这个方法,所以此时this指向t_obj。
作为函数调用
我们将上面的代码改一下,将obj.show赋值给全局变量show再调用他,此时this绑定到全局对象
1 | var name = 'lala'; |
在函数内部的函数调用
在函数内部调用一个函数,比如在一个对象的方法里面调用一个函数时,this会指向全局对象(讲道理的话应该指向对象)。这是JavaScript设计比较坑的一个地方,平时经常使用命名一个新变量ctx(context,即上下文环境)替代this。
1 | var name = 'lala'; |
修正版:
1 | var name = 'lala'; |
作为构造函数调用
我们常使用new 构造函数名()来创建一个对象,此时函数中的this指向新创建的对象。如果不使用new,则和普通函数一样绑定到全局对象
1 | function Foo(){ |
在setTimeout
、setInterval
和匿名函数中
在setTimeout
,setInterval
和匿名函数执行时的对象为全局对象,所以this也指向全局对象。
1 | var name = 'lala'; |
函数调用call
和apply
方法时
两者的本质的就是改变函数当前的上下文环境即this,两者的区别是call
接受一个个参数,而apply
接受一个参数数组。这两种方法会调用函数。
PS:使用call
和apply
函数的时候要注意,如果传递的 this 值不是一个对象,JavaScript 将会尝试使用内部ToObject
操作将其转换为对象。因此,如果传递的值是一个原始值比如 7 或 ‘foo’ ,那么就会使用相关构造函数将它转换为对象,所以原始值 7 通过new Number(7)
被转换为对象,而字符串’foo’使用new String('foo')
转化为对象
函数调用bind
方法时
函数调用bind方法时会创建一个有相同函数体和作用域的函数,新函数的this指向bind的第一个参数。该方法不会调用函数,而是返回新函数。