This你到底在指谁

185 阅读3分钟

今天在学习过程中碰到了一个bind与call和apply这三种显示绑定的方法有什么区别,于是呢就想写篇这个有关this指向的文章

引言

在JavaScript中,this关键字是一个重要且复杂的概念。而且也是在面试时,面试官会经常拿出来考察我们对JS基础知识是否合格的一个点。this关键字可以根据函数的调用方式指向不同的对象,使得它在编写代码时既灵活又具有挑战性。理解this的指向可以显著提升代码质量,减少上下文参数的传递,增强代码的可读性和可维护性。那么直接来聊一聊this的几种指向规则吧

this 的指向规则

默认绑定

默认绑定是指当一个函数独立调用时(即不带任何修饰符的调用),this指向全局对象。在浏览器中,全局对象是 window。在Node.js中则是指向global

// 非严格模式
function sayHello() {
    console.log(this === window); // true
}
sayHello();

// 严格模式
"use strict";
function sayHelloStrict() {
    console.log(this); // undefined
}
sayHelloStrict();

如果是在严格模式下,this 将不会被绑定到任何特定的对象。相反,它会被设置为 undefined

隐式绑定

当一个函数被某个对象所拥有,或者函数被某个上下文对象调用时,该函数中的this指向该上下文对象。

const obj = {
  name: 'Alice',
  getName: function() {
    console.log(this.name);
  }
};
obj.getName(); // 输出 'Alice'

隐式丢失

当一个函数被多个对象链式调用时,this指向最近的那个对象。或者在某些情况下,即使函数被作为对象的方法调用,this 可能会失去其预期的绑定,尤其是当函数被赋值给一个变量或以其他方式间接调用时。

两个例子:

var obj1={
    name:"Alice",
    obj2:{
        name:"Bob",
        getName:function () {
            console.log(`Hello ${this.name}`);
        }
    }
}
obj1.obj2.getName()  // 输出'Hello Bob'
const obj = {
    name: 'Alice',
    getName: function () {
        console.log(`Hello, ${this.name}`);
    }
};

const getName = obj.getName;
getName(); // 输出:Hello, undefined (非严格模式) 或 抛出错误 (严格模式)

隐式丢失和隐式绑定这两种情况总结来说就是谁调用this就☞向谁。

显示绑定

有三种方法 call apply bind都是能指定this的指向,比较强硬。但是他们的用法还是有点区别的

call

call 方法接受的第一个参数是 this 应该指向的对象,随后的参数则是函数应该接收的参数列表。

var obj={
    a:1
}
function foo(x,y){
    console.log(this.a,x+y);
}
foo.call(obj,1,2)  // 输出1  3

apply

apply的方法与call相似,第一个参数是指向的对象,随后的参数都是用数组的方式添加。

var obj={
    a:1
}
function foo(x,y){
    console.log(this.a,x+y);
}
foo.apply(obj,[2,3])  // 输出1   5

bind

  • call 和 apply 都可以立即调用函数,但 call 接受参数列表,而 apply 接受一个参数数组。
  • bind 方法创建并返回一个新的函数,在调用这个新函数时,this 被绑定到 bind 方法的调用者所指定的对象。这意味着使用 bind 创建的新函数将始终以指定的 this 值进行调用,无论后续如何调用该函数。

最主要的区别还是在执行时机上,bind 返回一个新的函数,不立即执行;call 和 apply 立即执行函数。

var obj={
    a:1
}
function foo(x,y){
    console.log(this.a,x+y);
}
const bar=foo.bind(obj,1,2)   
bar(1,2)   // 输出1  3

new 绑定

当使用 new 关键字调用构造函数时,构造函数内的 this 会绑定到新创建的对象实例。

function Person(){
    this.name='Alice'
}
let p=new Person()
console.log(p.name);   // 输出Alice

可以看下前端面试js系列:手写new - 掘金 (juejin.cn)这篇手写new可能会更容易理解

箭头函数

箭头函数并没有自己的 this 值。它们继承自定义箭头函数的最近一层非箭头函数的作用域的 this 值。

var obj={
    a:1,
    foo:function(){
        const fn=()=>{
            console.log(this.a);
        }
        fn()
    }
}
obj.foo()

这段代码箭头函数里的this就是继承离它最近的foo函数的this,然后foo作为 obj 的一个方法被调用的。