目录
提问:什么是this?
回答:this是Javascript语言中的一个关键字,它代表函数运行时自动生成的一个内部对象,指当前对象,因此this只能在函数内部使用。随着函数执行环境的改变,this所指代的对象也会发生改变,但this始终指向的是调用函数的对象。简单来说就是谁调用了这个函数,this就指向谁(对象)。
一、this的指向
1、全局环境中的this
所谓全局环境是指在script标签的内部,而全局环境下的作用域就是全局作用域。全局作用域下的this始终指向的是全局对象window。(window是浏览器对象中最顶层的节点)
1.1、全局环境中直接打印this
<script>
console.log(this) //该this指向window
</script>
1.2、全局环境中调用普通函数
<script>
function fn() {
console.log(this) //该this指向window
}
fn()
</script>
1.3、全局环境中调用定时器和延时器函数
<script>
setTimeout(function () {
console.log(this) //该this指向window
}, 1000)
setInterval(function () {
console.log(this) //该this指向window
}, 10000)
</script>
2、 对象中的this
对象内部方法的this指向调用这些方法的对象,即由哪个对象调用就指向哪个对象,如果是多层嵌套的情况,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象,而不是window)。
<script>
let obj-1 = {
fn-1: function () {
console.log(this)
},
obj-2: {
fn-2: function () {
console.log(this)
},
},
}
obj-1.fn-1() //fn-1由obj-1调用,故this指向obj-1
obj-1.obj-2.fn-2() //obj-2离的更近,fn-2由obj-2调用,故this指向obj-2
</script>
3、构造函数中的this
构造函数中的this与被构造函数实例出来的新对象绑定,即指向该新对象。
<script>
let Person = function (name, age) {
this.name = name
this.age = age
console.log(this) //该this指向由构造函数 Person实例出来的对象 kun
}
let kun = new Person('小黑子', 666)
</script>
4、事件中的this
在HTML事件句柄中,this指向的是触发该事件的HTML元素对象,即指向事件源。
<button id="btn" onclick = "this.style.display='none'">点击删除</button>
<script>
const btn = document.getElementById("btn")
btn.onclick = function () {
this.value = "按钮"
console.log(this) //给btn注册了on事件,因此该this指向btn
}
</script>
5、 箭头函数中的this
普通函数内部的this指向函数运行时所在的对象,但ES6中新增的箭头函数并没有自己的this对象,所以只能指向上一层作用域(父级作用域)中的this。也就是说,箭头函数内部的this指向是固定的。
<script>
var c = 21 //声明同一个全局变量 c 为21
const obj = {
c: 42,
x: () => console.log(this.c),
k: function () {
console.log(this.c)
},
}
obj.x() //箭头函数中的 this指向父级作用域中声明的变量 c,即为21
obj.k() //obj调用函数 k,函数 k中的 this指向 obj中声明的变量 c,即为 42
</script>
6、 严格模式下的this
JavaScript除了提供正常模式外,还提供了严格模式(strict mode)。ES5 的严格模式是采用具有限制性JavaScript变体的一种方式,即在严格的条件下运行 JS 代码,可消除Javascript语法中的不合理、不严谨之处,减少一些怪异行为,保证代码运行的安全并且可以提高编译器的效率。
严格模式下全局调用普通函数,其this指向为undefined,其他情况与正常模式相同。
<script>
"use strict"
function fn() {
console.log(this) //该this指向undefined
}
fn()
</script>
二、改变this的指向
1、call 方法
function.call( thisArg,arg1, arg2,arg3······ )//立即执行函数
function: 需要改变this指向的原函数
thisArg: 改变后的this所指向的新目标对象arg:需要修改的参数
<script>
function fn(name, age) {
this.name = name
this.age = age
console.log(this)
}
const obj = {}
fn.call(obj, "小黑子", 666) //函数fn中的this指向空对象obj并具备name和age属性
</script>
2、apply 方法
function.apply( thisArg,[arg1, arg2,arg3······] )//立即执行函数
function: 需要改变this指向的原函数
thisArg: 改变后的this所指向的新目标对象[arg]:一个数组,包含需要修改的参数
<script>
function fn(name, age) {
this.name = name
this.age = age
console.log(this)
}
const obj = {}
fn.apply(obj, ["小黑子",666]) //函数fn中的this指向空对象obj并具备name和age属性
</script>
3、bind 方法
function.bind( thisArg,arg1, arg2,arg3······ )//不会立即执行函数
function: 需要改变this指向的原函数
thisArg: 改变后的this所指向的新目标对象arg:需要修改的参数
该方法并不会调用函数,仅仅是改变this指向,相当于返回一份修改了this的函数的拷贝
<script>
function fn(name, age) {
this.name = name
this.age = age
console.log(this)
}
const obj = {}
//函数被借用时,不会立即执行,而是返回一个新的函数
//所以需要自己手动调用新的函数来改变this指向
const newFn = fn.bind(obj, '小黑子', 666) //this指向空对象obj并具备name和age属性
newFn()
</script>
4、总结
方法 | 区别 |
---|---|
call | 既可以调用函数又可以传参数,参数只需用逗号隔开 |
apply | 既可以调用函数又可以传参数,参数需要用一个数组进行包裹 |
bind | 不可以调用函数,可以传参数,参数只需用逗号隔开,返回得到一个新的函数,执行需要再次调用 |