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

本文详细解析了JavaScript中this关键字的指向规则,包括全局环境、函数环境、构造函数、箭头函数等多种场景,并介绍了call、apply、bind方法对this的影响。
837

被折叠的 条评论
为什么被折叠?



