开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情
我们知道,this代表的是函数的指向。那么我们也同时需要明白一个问题就是,函数的this,是在什么时间确认的。
前面我们学习执行上下文的过程中,有提到关于this的信息,在执行上下文的环境记录对象中,存在一个内部属性[[ThisValue]]用于记录this指向,同时还存在一个内部方法BindThisValue用于设置[[ThisValue]]的值。这也就是说,this的指向,对于函数来说是在执行上下文的创建过程中确定的。因此,这也是为什么说,this的指向是在函数调用的时候才确定的。
const a = 20
const obj = {
a: 20
}
function fn(){
console.log(this.a)
}
fn() // 10
fn.call(obj) // 20
通过a的值的不同体现,我们知道this分别指向window对象和obj对象。
全局上下文中的this
在全局上下文中,this对象指向全局对象本身
this.a = 20
var b = 10
c = 30
const d = 40 // const,let声明的不会挂载在全局对象上
console.log(a) // 20
console.log(b) // 10
console.log(c) // 30
console.log(d) // undefined
函数中的this
函数上下文中的this,和调用该函数的方式息息相关。
在一个函数执行上下文中,this由该函数的调用者caller提供,由调用的方式决定。
- 有明确的调用者
- 独立调用,无明确调用者
function fn(a){
console.log(arguments.callee)
console.log(this)
}
window.fn(10)
很显然当前window是调用者callee,fn是被调用者caller,因此fn内部的this指向window。但同时还有一种写法:
function fn(a){
console.log(arguments.callee)
console.log(this)
}
fn(10)
此时需要分情况来讨论,在严格模式下,fn此时没有调用者,因此this指向undefined,正在非严格模式下,fn的this依然默认由window来承担。
call/apply/bind显示指定this
js提供了call/apply/bind方法显示的设置this的指向,所有函数均可以调用此方法。
var a = 20
var object = {
a: 40
}
function fn() {
console.log(this.a)
}
如果我们正常独立直接调用fn,在非严格模式下this会指向window对象,因此函数输出20,但我们还可以通过显示指定的方法设置fn的调用者。
fn.call(object) // 40
fn.apply(object) // 40
在调用call/apply时,实际上还是执行fn本身,只是将函数中的this指向设置为传入的第一个参数,它们的区别就是参数传递方式不同。
call的第一个参数是函数内部指定的this指向,后续参数是函数本身执行需要的参数,一个一个进行传递,
apply的第一个参数和call一样,而第二个参数则是函数本身需要的全部参数,整合为一个数组进行传递。
function fn(a,b){
return this.g + a + b
}
var g = 1
var object = {g: 2}
fn(10,10) // 21
fn.call(object,10,10) // 22
fn,apply(object,[10,10]) // 22
bind方法也能显示指定函数内部this指向,但是它和call/apply仍有不同。
当函数调用bind时,函数不会立即执行,而是返回一个新的函数,这个函数和原函数一样,但是并非原函数,新函数的this指向已经被绑定,参数为bind的后续参数。
function fn(a,b){
return this.g + a + b
}
var g = 1
var object = {g: 2}
var _fn = fn.bind(object,1,1)
console.log(_fn === fn) //false
_fn() // 4
_fn(2,2) // 6