this
关键字的指向是由它的调用方式决定的. 通常有两种环境调用this
, 全局环境和函数环境. 函数环境中又有多种调用this
的方法.
this
不能在执行期间赋值. this
就是函数运行时所在的对象(环境)
全局上下文
当全局环境执行代码时, 全局上下文(函数体外部)的中的this
只有一种情况.
- 无论是否在严格模式下,在全局执行上下文中(在任何函数体外部)
this
都指代全局对象。
在浏览器中, 全局对象是window
console.log(this === window) //true
var a = 2
console.log(this.a === window.a) //true, 都为2
函数上下文
函数上下文中的情况就复杂多了.
函数常规调用中的this
非严格模式下的调用:
function fn() {
return this
}
fn() // 返回window对象
fn() === window //true
可以看到this
指向是全局对象window
.
- 即非严格模式下,
this
指向全局对象
严格模式下的调用:
function fn() {
return this
}
fn() // 返回undefined
fn() === undefined //true
即:
- 严格模式下,
this
为undefined
call, apply, bind方法中的this
this
的实际值就是call
函数的第一个参数. 也是apply
,bind
的第一个参数. 这三个函数之间略有差别.
function fn(){
return this.a;
}
var obj = {a: 1}
fn() //undefined, 应为没有为this指定值, fn()等同于fn.call(undefined)
fn.call(obj) //1
当使用call
方法绑定this
值时, this
就指向了obj
对象. 因此this.a
即obj.a
apply
方法和call
类似, 不同的是, 若fn
有参数, 则可以通过call
的第二个及其之后的参数传入. 而apply
是将fn
的参数组成一个数组, 并作为apply
的第二个参数传入.
function fn(x, y){
return this.a + x + y
}
var obj = {a: 1}
fn.call(obj, 2, 3) //1+2+3=6, 返回6
fn.apply(obj, [2,3]) //1+2+3=6, 返回6
bind
方法就和上面连个方法有点区别了.
bind
方法由于绑定this
的值, 且bind
只绑定一次.
function fn(){
return this.a
}
var obj = {a: 1}
var o = {a: 2}
var f1 = fn.bind(obj)
f1() //1
var f2 = f1.bind(o)
f2() //1, f1函数里的this永久的绑定到了obj对象上, 无法更改
作为对象的方法内的this
- 当
this
所在的函数作为对象的方法调用时,this
指向调用该函数的对象
var obj = {
a:1,
"fn": function () {
var a = 2
return this.a
}
}
obj.fn() //1
obj.fn()
并没有返回2
, 而是返回1
, 可见fn函数中的this
指向了obj
对象而不是fn
函数, 那么this.a
就是obj.a
obj.fn()
可以看成这样:
obj.fn.call(obj)
//等同于
obj.fn()
箭头函数内的this
- 箭头函数内的
this
指向箭头函数创建时的封闭的词法上下文(the enclosing lexical context
). 即, 箭头函数内部的this
值为创建箭头函数时的this
值. 换句话说, 箭头函数体内的this对象是定义箭头函数时时所在的对象.
function fn() {
//假设this.form指向<form>元素
this.form.addEventListener('submit', function() {
console.log(this) //这个this是什么?, 这个this指向外面的this.form, 即<form>元素
}, false)
}
通过addEventListener
添加的监听函数, 其内部this
指向调用该处理函数的元素. 在上例中, this.form
添加监听函数, 其处理函数内部的this
就指向调用元素form
表单
如何使处理函数内部的this
也指向this.form
中的this
呢? 我们可以使用箭头函数:
function fn() {
//假设this.form指向<form>元素
this.form.addEventListener('submit', ()=>{
console.log(this) //这个this就是this.form中的this
}, false)
}
- 全局环境下,
this
指向的就是全局对象(不管严格模式下还是非严格模式下)
var fn = ()=>{return this}
fn() //返回window对象
构造函数内的this
当一个函数使用new
操作符时, 我们可以称这个函数为构造函数, 其内部的this
指向正在构造的新对象.
- 当构造函数没有
return
语句或者return
的不是对象时, 构造函数会隐式的返回this
对象
function fn() {
this.a = 100 //没有return语句, 则会产生隐式的return this
}
var obj = new fn() //产生新对象obj
console.log(obj.a) //100
- 当构造构造函数返回新对象时,
this
指向返回的新对象
function fn() {
this.a = 100
var o = {a: 1}
return o //这里返回对象o
}
var obj = new fn() //产生新对象obj
console.log(obj.a) //1, this指向了对象o
注意, 新对象不继承构造函数内部的属性. 新对象只继承this
对象上的属性
function fn() {
var x = 2
this.a = 100
this.b = 101
}
var obj = new fn()
console.log(obj.x) //undefined
console.log(obj.a) //100
console.log(obj.b) //101
函数fn
内的属性a
并没有继承给obj
对象, 而this
上的a
,b
属性继承给了obj
对象.
DOM事件处理函数中的this
我们常在DOM
事件处理函数中使用this
, 此时处理函数中的this
指向调用这个函数的元素, 也是事件对象event
的target
对象, 即event.target
//假设有元素<button id="btn">点我</button>, 并绑定下面的监听事件
btn.addEventListener('click', function(e) {
console.log(this)
console.log(this === e.target)
}, false)
//当点击按钮时输出
<button id="btn">点我</button>
true
我们可以看到处理函数内部的this
指向id
为btn
的元素
内联事件处理函数中的this
内联事件中的this
有两种情况. 以onclick
属性为例:
- 一种是
this
指向onclick
监听的DOM
元素:
<button onclick="alert(this);">点我</button>
//this指向<button>元素
- 另一种是
this
指向全局对象window
:
<script>
function fn() {
return this
}
</script>
<button onclick="alert(fn());">点我</button>
//this在函数内部, 指向window对象
总结
this
的值取决与它的调用方式- 全局环境中的
this
指向window
对象 - 函数常规调用如
fn()
中的this
在非严格模式下指向window
, 严格模式下为undefined
this
值为call
,apply
,bind
中的第一个参数- 对象方法内的
this
指向调用该方法的对象 - 箭头函数内的
this
指向创建箭头函数时的外部this
- 构造函数内的
this
指向构造函数返回的新对象 DOM
事件处理函数中的this
指向调用处理函数的元素, 也是事件对象event
的currentTarget
属性即event.currentTarget
.- 内联事件处理函数中的
this
指向调用处理函数的元素或者window
参考文章: this-JavaScript | MDN