js中this的指向问题

1.web全局环境下的this指向window

1
console.log(this);//`window`

2.默认绑定

函数直接调用的情况(无任何调用前缀)

非严格模式下,函数内部的this指向全局对象window;严格模式下为underfined

1
2
3
4
5
6
7
8
9
10
11
// 非严格模式
function fun1(){
console.log(this);//window
}
fun1();
// 严格模式
function fun2(){
"use strict";//严格模式的语法要求变量必须先声明后赋值
console.log(this);//underfined
}
fun2();

3.隐式绑定

函数调用时,前面存在调用它的对象,那么this就会隐式绑定到这个对象上。如果函数调用前存在多个对象,this指向距离调用自己最近的对象。简而言之,this指向调用函数的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
let obj={
name:'nancy',
age:23,
fun3:function(){
console.log(this);//指向obj
// 因为fun4是直接调用的,所以指向调用者window,fun3由obj调用,指向obj
function fun4(){
console.log(this);//指向window
}
fun4();
}
}
obj.fun3();

4.显示绑定

明确告诉JavaScript Engine 调用函数的时候 this所指向的值。用于显示this绑定的方法有call,apply和bind;

call和apply的第一个参数作为函数运行的this,后面的参数作为函数运行时的参数;二者区别是call 通过 剩余参数的形式 传递参数列表,apply 通过 数组的形式 传达参数列表;

bind就是给函数套一层函数,利用柯里化,提前设置好上下文对象。根据这个原理,可以知道,无论你外面包裹了多少层,目标函数不会变。且由于闭包的存在,最初的这个context对象也不会变,所以当包裹在外层的函数一层层褪去后,最终使用到的context对象依旧是第一次绑定的对象。硬绑定可以有效解决this丢失问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function fun5(year,name,obj){
console.log(this);//{age:18}
console.log(year+'年'+name+this.age+'岁');
}
let obj={
age:22
};
fun5.call(obj,2022,'小明');//2022年小明22岁
fun5.apply(obj,[2023,'小明'])//2023年小明22岁
let admin={
name:'woody'
}
let fun6=fun5.bind(admin);//this指向admin
fun6();

三点注意事项:

  • call和apply是立即执行,bind则是返回一个绑定了this的新函数,只有你调用了这个新函数才真的调用了目标函数
  • bind函数存在多次绑定的问题,如果多次绑定this,则以第一次为准。
  • bind函数实际上是显示绑定(call、apply)的一个变种,称为硬绑定。由于硬绑定是一种非常常用的模式,所以在 ES5 中提供了内置的方法Function.prototype.bind

5.new绑定

new关键字来执行函数,相当于构造函数来实例化对象,则this指向当前实例化的对象

使用new关键字来调用函数是,会执行如下的操作:

  1. 创建一个全新的对象
  2. 新对象的隐式原型等于构造函数的显示原型
  3. 这个新对象会绑定到函数调用的this上
  4. 将this所指向的那个对象返回

如果函数显示的返回了一个对象

那么就会将显示返回的那个对象作为函数的返回值返回

而不是使用this所指向的那个对象

1
2
3
4
function fun7(){
console.log(this);//fun7
}
let fn=new fun7();

6.箭头函数

箭头函数中的 this 与普通函数完全不同,也不受调用方式的影响,事实上箭头函数中并不存在 this !箭头函数中访问的 this 不过是箭头函数所在作用域的 this 变量。

箭头函数函数内不存在this,沿用上一级的,this是最近作用域中的this,向外层找

1
2
3
4
5
6
7
8
const obj1={
name:'nancy',
fun8:()=>{
// 箭头函数中的this与函数声明环境中的this一样
console.log(this);//window
}
}
obj1.fun8();

注意以下两点:

  1. 函数体内的this就是定义时所在的对象,而非调用时所在的对象,和普通函数相反。
  2. 箭头函数无法用做构造函数,即不能使用new调用