一. 首先明确,this指向是在函数运行时才确定的
二. 误解
- this 指向函数自身(错误)
function foo(num) { console.log('foo', num); this.count ++ } foo.count = 0 // 初始化函数的count属性值是0 for(let i = 0; i < 5; i ++) { foo(i) } console.log(foo.count); //count最终还是0 复制代码
上面代码中,定义了foo函数,通过this每次执行foo就把this的count加1,但是,循环执行了五次之后,foo.count还是等于0,说明了,this不指向foo函数
- this指向函数的作用域(错误)
function foo() { var a = 2 this.bar() } function bar() { console.log(this.a); } foo() // undefined 复制代码
上面代码想通过this指向foo函数的作用域,但是a打印出undefined,可见,this不是指向函数的作用域
三. this的指向
再次强调,this指向只有在函数运行时才能够确定下来
1. 默认绑定
函数不加任何修饰,直接调用时,如果非严格模式,默认绑定规则this绑定到全局对象
var a = 1
function f() {
console.log(this.a)
}
f() // 在非严格模式下1, 严格模式下undefined
复制代码
2. 隐式绑定
默认绑定是对象中有函数属性,当使用对象调用函数时,函数中的this指向调用的对象
let obj = {
a: 123,
foo(){
console.log(this.a);
}
}
obj.foo()
复制代码
当连续调用对象时,this指向直接调用的对象
let obj = {
a: 123,
foo(){
console.log(this.a);
}
}
let obj2 = {
a: 2,
obj
}
obj2.obj.foo() // 123
复制代码
绑定丢失
函数名只是函数的一个引用,所以,下面代码中的newF实际上指向了obj.foo的指针,所以newF实际是指向foo的指针,也就是说现在调用newF,就是不带任何修饰的函数调用了,采用默认绑定。
let obj = {
a: 123,
foo(){
console.log(this.a);
}
}
let newF = obj.foo
newF() // undefined
复制代码
3. 显式绑定
显示绑定时借助call,apply,bind来显示的指定this指向,一旦指向之后,就不再改变
let obj = {
a: 123,
foo(){
console.log(this.a);
}
}
let o = {
a: 22
}
obj.foo.call(o) // this被强制指向o
复制代码
4. new 绑定
new操作会经过以下步骤
- 创建一个新的对象,把函数的this指向这个新对象
- 将对象的原型指向构造函数的原型
- 如果没有显式的返回对象 返回这个新创建的对象,如果是,则返回指定对象
所以通过new调用的函数,其中的this指向new返回的对象
以上所有方法都是介绍普通函数的this绑定规则对于箭头函数,则有所不同
箭头函数中的this指向
箭头函数中this指向箭头函数定义时的作用域(全局作用域或者函数作用域,而不是对象块)中的this
function foo() {
return () => {
console.log(this.a);
}
}
let obj1 = {
a:1
}
let obj2 = {
a: 2
}
let bar = foo.call(obj1)
bar.call(obj2) // 1
// 这里函数中返回的箭头函数借用了它定义时所在的作用域(foo)中的this
// 因为foo中的this被硬绑定到了obj1,所以 返回的箭头函数中的this也指向obj1,不能通过call修改
复制代码
箭头函数可以代替bind保持函数中的this到特定对象,箭头函数使用了类似如下写法
function foo() {
var self = this
setTimeout(function() {
console.log(self); // 暂存变量保存,函数定义时作用域中的this
}, 1000);
}
复制代码
一道面试题,看this
var msg1 = 1;
const msg2 = 2;
const obj = {
msg1: 3,
msg2: 4,
log1: function() {
console.log(this.msg1, this.msg2)
},
log2: () => {
console.log(this.msg1, this.msg2)
}
};
const {
log1,
log2
} = obj;
obj.log1(); // 3, 4
// 隐式绑定规则,this指向调用的对象
obj.log2(); // 1, undefined
// 箭头函数中的this指向定义时的作用域,即全局作用域,所以this指向全局,
// 注意,箭头函数定义是的作用域,不是obj,obj不是一个作用域,作用域只有全局作用域和函数作用域
//和块级作用域,obj只是一个引用变量,不是一个作用域,
//所以this指向的是window,const和let定义的变//量不挂载载window上,所以访问是undefined
log1(); // 1, undefined
// 解构赋值,导致隐式绑定丢失,相当于直接调用
log2(); // 1, undefined
// 箭头函数仍然指向全局
复制代码
参考文献:《你不知道的javascript上卷》
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END