2022年了,你到底懂不懂this指向啊?!

122 阅读3分钟

前言

很多刚入门的小伙伴可能搞不懂this指向,很多时候就是硬凑,这个不对换一种写法,再不对再换一种,直到找到自己的目标this,反正能跑一个就行嘛。但是很多时候面试必不可少的会问到这些,而且如果开始时不注意会多写很多不必要的代码,可读性不强,今天我们就来看下this指向到底指的啥!

this 绑定规则

首先我们可以将this绑定大致分为以下几类:

默认绑定

独立函数调用时使用默认绑定,独立函数调用可以理解成函数没有被绑定到某个对象上进行调用

// 1. 普通函数独立调用
function foo(){
    console.log(this)
}
foo() // Window对象,严格模式时为undefined
// 2. 函数定义在对象中,赋值给一个变量独立调用
let obj={
    name:'xxx',
    bar:function(){
        console.log(`bar-this`, this);
    }
}
let foo1=obj.bar
foo1() // Window对象,严格模式时为undefined

再举个例子,

// 3. 高阶函数
let obj={
    name:'xxx',
    bar:function(){
        console.log(`bar-this`, this);
    }
}
function foo2(fn){
    fn()
}
foo2(obj.bar) // Window对象,严格模式时为undefined

由此看出this的绑定和编写的位置没有关系,它和调用方式以及位置有关

注:严格模式下独立调用函数中的this指向的是undefined

显式绑定

通过call或者apply或者bind方法

函数.call(对象,xx)
函数.apply(对象,[xx])
// 传入的这个对象会和this绑定上
// 后面的参数,call为参数列表,apply为数组

例如:

function foo(){
    console.log(this);
}
let obj = {
    name:'xx1'
}
foo.call(obj) // obj对象
foo.apply(obj) // obj对象

隐式绑定

通过某个对象进行绑定,换句话说就是通过某个对象发起的函数调用。下面举几个案例

function foo(){
    console.log(`foo-this`,this);
}
let obj = {
    name:'xxx',
    bar:foo
}
obj.bar() //obj对象
function foo(){
    console.log(`foo-this`,this);
}
let obj1 = {
    name:'xxx1',
    foo1:foo
}
let obj2 = {
    name:'xxx2',
    foo2:obj1
}
obj2.foo2.foo1() // obj1对象

new绑定

function Foo() {
    console.log(this);
}
new Foo() // Foo的实例对象

另外回顾下new做了哪些事

  1. 创建一个新的空对象
  2. 将this指向这个空对象
  3. 执行代码
  4. 没有显式返回非空对象时,默认返回此对象

一些内置函数

在此简单举例

  • 计时器
setTimeout(function(){
    console.log(this); // Window对象
},500)
  • forEach
const filmList = ["xx1", "xx2", "xx3"]
filmList.forEach(item=>{
    console.log(this); // Window对象
})

规则优先级

上面我们说的都是分类的独立调用,那多个的呢?如果应用类多条规则那优先级哪个更高些呢?

  1. 默认绑定优先级最低
  2. 显式绑定高于隐式绑定
  3. new绑定高于隐式绑定
  4. new不会和apply/call一起使用
  5. new绑定高于bind绑定
  6. bind高于apply/call

特殊

显示绑定nullundefined

function foo() {
    console.log(this);
}
foo.apply(null) // Window对象 严格模式下为null
foo.apply(undefined) // Window对象 严格模式下为undefined
foo.call(undefined) // Window对象 严格模式下为undefined

间接函数引用

let obj1 = {
    name: 'xx1',
    foo: function(){
        console.log(this);
    }
}
let obj2 = { name: 'xx2' };
(obj2.foo = obj1.foo)() // Window对象(会被当作独立函数调用)

箭头函数

写法:

let foo = (参1,参2) => {}
  • 箭头函数不会绑定this arguments
  • 箭头函数不能作为构造函数使用

箭头函数中没有this,如果在其中使用this,它会往它的上层作用域查找对应的this

举例:

// 一
let foo = () => {
   console.log(`foo-this`, this);
}
foo() // Window对象
foo.apply("xxx") // Window对象
// 二
let obj = {
   name: 'xx1',
   foo: function() {
       let bar = () =>{
           console.log(`bar-this`, this);
       }
       return bar
   }
}
let fn = obj.foo()
fn() // obj对象
fn.apply('xxx2') // obj对象
// 三,变形一下
let obj = {
   name: 'xx1',
   foo: () => {
       let bar = () =>{
           console.log(`bar-this`, this);
       }
       return bar
   }
}
let fn = obj.foo()
fn() // Window对象
fn.apply('xxx2') // Window对象

好了,以上就是this指向相关的内容,如果大家有不同意见可以在下方评论,一起探讨下✌️