一文读懂 es6 中class方法中的this绑定

一直以来有这么个疑问? class 的方法中没有自动的绑定this 为什么手动绑定之后,在绑定之后的方法里调用class中的其他的方法(这个方法为什么就能使用this,不也应该是null或者undefined或者window吗) 还是说这就是class的机制?

于是带着这个疑问去寻找答案

在 JavaScript 中,类的方法中的 this 关键字通常会自动绑定到当前实例对象上。然而,当你将一个类的方法提取出来作为独立的函数调用时,this 的绑定就会丢失,变成 undefined(在严格模式下)或全局对象(在非严格模式下),而不是 null。

手动绑定 this 通常使用 bind、call 或 apply 方法来实现。当你手动绑定 this 之后,你实际上是在创建一个新的函数,并且在这个新函数中,this 被固定为你所指定的对象。因此,在绑定之后的方法里调用类中的其他的方法时,this 仍然指向你所绑定的对象,而不是 null。

这是因为当你使用 bind 方法时,bind 会返回一个新的函数,这个新函数中的 this 值会被永久性地绑定到 bind 方法中传入的第一个参数。当你调用这个新函数时,无论是在哪里调用,this 的值都是你绑定的那个对象。

这是 JavaScript 类和对象机制的一部分,确保了在实例方法中调用其他实例方法时,this 能够正确地引用实例对象。如果你在调用方法时不手动绑定 this,而方法是在类之外的地方被调用,那么 this 就不会自动指向类的实例,而是会丢失绑定,这可能会导致 this 指向全局对象或变为 undefined。

因此,手动绑定 this 是为了确保在方法被提取为独立函数之后,依然可以正确地访问类的实例属性和其他方法。
下面是一个简单的例子,展示了如何在类之外的地方调用类的方法,并解释为什么需要手动绑定 this。

复制代码
class MyClass {
  constructor(name) {
    this.name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }

  sayGoodbye() {
    console.log(`Goodbye, ${this.name}!`);
    this.afterGoodbye();
  }

  afterGoodbye() {
    console.log(`After goodbye, ${this.name} is still here.`);
  }
}

const myInstance = new MyClass('Alice');

// 正常调用类中的方法
myInstance.greet(); // 输出: Hello, my name is Alice

// 将方法提取到类之外并尝试调用
const extractedGreet = myInstance.greet;
extractedGreet(); // 输出: Hello, my name is undefined

// 手动绑定 this 后再调用
const boundGreet = myInstance.greet.bind(myInstance);
boundGreet(); // 输出: Hello, my name is Alice

// 类中的一个方法在类之外调用另一个方法
myInstance.sayGoodbye(); // 输出: Goodbye, Alice! After goodbye, Alice is still here.

// 将另一个方法提取到类之外并尝试调用
const extractedSayGoodbye = myInstance.sayGoodbye;
extractedSayGoodbye(); // 输出: Goodbye, undefined! TypeError: this.afterGoodbye is not a function

// 手动绑定 this 后再调用
const boundSayGoodbye = myInstance.sayGoodbye.bind(myInstance);
boundSayGoodbye(); // 输出: Goodbye, Alice! After goodbye, Alice is still here.

在这个例子中:

  1. MyClass 是一个类,其中包含三个方法:greet、sayGoodbye 和 afterGoodbye。
  2. myInstance 是 MyClass 的一个实例,初始化时 name 属性被设置为 'Alice'。
  3. greet 方法正常调用时会输出 Hello, my name is Alice,因为 this 指向 myInstance。
  4. 当我们将 greet 方法提取到类之外并直接调用时,this 不再指向 myInstance,而是指向全局对象(在非严格模式下)或 undefined(在严格模式下),因此输出 Hello, my name is undefined。
  5. 使用 bind 方法手动绑定 this 到 myInstance 后,再次调用 greet 方法,this 指向 myInstance,输出 Hello, my name is Alice。
  6. sayGoodbye 方法在类内部调用 afterGoodbye 方法时,this 正常指向 myInstance,因此输出 Goodbye, Alice! After goodbye, Alice is still here.。
  7. 当我们将 sayGoodbye 方法提取到类之外并直接调用时,this 不再指向 myInstance,导致 this.name 输出 undefined,并且 this.afterGoodbye 不是一个函数,抛出 TypeError。
  8. 使用 bind 方法手动绑定 this 到 myInstance 后,再次调用 sayGoodbye 方法,this 指向 myInstance,输出 Goodbye, Alice! After goodbye, Alice is still here.。

通过这个例子,你可以看到手动绑定 this 的重要性,特别是在将方法提取到类之外调用时。

相关推荐
Beginner x_u3 天前
ES6 中的 class 是什么?和ES5构造函数差别是什么?
javascript·es6·class
好学且牛逼的马5 天前
ES6 核心语法精讲
前端·ecmascript·es6
辰风沐阳5 天前
ES6 新特性: 解构赋值
前端·javascript·es6
得一录7 天前
ES6核心语法
前端·ecmascript·es6
利刃大大13 天前
【ES6】变量与常量 && 模板字符串 && 对象 && 解构赋值 && 箭头函数 && 数组 && 扩展运算符 && Promise/Await/Async
开发语言·前端·javascript·es6
天若有情67313 天前
ES6 模块与 CommonJS 的区别详解
前端·javascript·es6
wangbing112514 天前
ES6 (ES2015)新增的集合对象Set
前端·javascript·es6
yyt36304584115 天前
TypeScript { [key: string]: unknown } 索引签名写法和 Record 替代
前端·javascript·vue.js·typescript·ecmascript·es6
梦65015 天前
JavaScript ES5 + ES6+ 字符串 (String) 所有方法大全
前端·javascript·es6
梦65015 天前
JavaScript (ES5)+ES6+jQuery 核心对象方法大全
javascript·es6·jquery