在了解js中this指向之前先简单的阐述一下脚本执行过程和执行上下文的概念
当js引擎执行脚本代码之前会先进行一个预编译阶段,然后创建全局执行上下文入栈(上下文调用栈),然后执行全局代码,执行到函数调用的时候会为该函数创建一个函数执行上下文然后入栈,然后执行函数代码,以此类推。当函数代码执行完毕会将这个函数执行上下文出栈,最后全局代码执行完毕,全局执行上下文出栈,这是一个完整的脚本执行执行过程。
执行上下文是一个抽象的概念,它定义了代码被执行时的环境,其中包含this指向,执行上下文可以分为三种类型:全局执行上下文、函数执行上下文和eval 执行上下文(不做了解)。
console.log(this) // 指向window
function fn() {
console.log(this) // 函数调用的时候this指向window
}
const obj = {
name: 'obj',
fn(){
console.log(this)
}
}
function fn1(callback) {
callback() // 函数调用的时候this指向window
}
fn1(fn)
fn1(obj.fn)
函数调用指向window
function fn() {
console.log(this)
}
const obj = {
_fn() {
console.log(this)
fn() // 函数中的this指向window
},
_fn1() {
function _fn2() {
console.log(this)
}
_fn2() // 函数中的this指向window
},
_fn3: fn
}
fn() // 函数中的this指向window
obj._fn() // obj调用_fn方法,函数中的this指向obj
obj._fn1()
obj._fn3() // obj调用_f3方法,函数中的this指向obj
const fn3 = obj._fn
fn3() // 非对象调用,函数中的this指向window
function Animal(name) {
this.name = name
}
Animal.prototype.getName = function() {
console.log(this)
}
const cat = new Animal('cat')
cat.getName() // 构造函数中原型对象中的this指向cat对象
函数被对象调用,this指向调用它的对象, 构造函数中的this指向实例对象
(Js es6以前类的创建以及原型链-CSDN博客中有new 构造函数的执行过程)
const obj = {
fn() {
const fn1 = () => {
console.log(this) // 指向window
}
fn1() // 函数中的this指向obj
},
fn2: () => {
console.log(this)
}
}
obj.fn()
obj.fn2() // 函数中的this指向window
会发现,在obj的fn方法里声明fn1箭头函数并执行,this指向obj,将fn2方法改为箭头函数,this指向window,这是因为箭头函数并没有自己的this,它会捕获外部上下文中的this值。
代码解释
const obj = {
_fn(){
console.log(this)
},
_fn1(){
console.log(this)
}
}
const obj1= {
name: 'obj1'
}
const fn3 = obj._fn
fn3.call(obj1) // 改变函数中的this将其指向obj1,并执行函数
fn3.apply(obj1) // 改变函数中的this将其指向obj1,并执行函数
obj._fn1.call(obj1) // 改变函数方法中的this将其指向obj1,并执行方法
const fn4 = fn3.bind(obj1)
fn4() // 将函数中的this指向obj1, 并返回一个新的函数
call、apply、bind能够指定函数中的this指向,call和apply的区别就是传参的方式不同
function fn(param1, param2, param3, param4) {}
fn.call(obj, param1_value, param2_value, param3_value, param4_value)
fn.bind(obj, [param1_value, param2_value, param3_value, param4_value])
箭头函数无法更改this指向
const obj = {
fn() {
setTimeout(function(){
console.log(this) // window
})
setTimeout(() => {
console.log(this) // obj
})
}
}
回调(非箭头)函数中的this指向取决于执行这个回调函数的函数想让它指向谁,比如定时器就让他指向window,但是可以通过call、apply、bind改变回调函数中的this指向。
function callback_fn() {
console.log(this)
}
const obj = {
callback_fn() {
console.log(this)
}
}
function fn(callback) {
const inner_obj = {
name: 'inner_obj'
}
callback.call(inner_obj) // 回调函数中的this指向obj
}
fn(callback_fn)
fn(obj.callback_fn)