【现代 JS】你真的懂 js 中的 Class 吗?

lxf2023-05-09 00:47:57

wiki 百科对 class 的定义:

在面向对象的编程中,class 是用于创建对象的可扩展程序代码模板,它为对象提供了状态(成员变量)的初始值和行为(成员函数或方法)的实现。

在开发中,我们经常需要创建许多相同类型的对象,比如用户(user)、商品(goods)等等,而现代 JavaScript 中的 class 就是为更便捷的解决以上问题。

class 语法

class MyClass {
  // class 方法
  constructor() { ... }
  method1() { ... }
  method2() { ... }
  method3() { ... }
  ...
}

let class = new MyClass()

我们通过使用 new MyClass() 来创建具有上述列出的所有方法的新对象,new 会自动调用 constructor() 方法。

有一点需要注意:类的方法之间没有逗号。 不要把这里的符号与对象字面量相混淆。在类中,不需要逗号

class 实现的原理

在 JavaScript 中,类是一种函数。

class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// 佐证:User 是一个函数
alert(typeof User); // function

class User {...} 构造实际上做了如下的事儿:

  1. 创建一个名为 User 的函数,该函数成为类声明的结果。该函数的代码来自于 constructor 方法(如果我们不编写这种方法,那么它就被假定为空)。
  2. 存储类中的方法,例如 User.prototype 中的 sayHi

【现代 JS】你真的懂 js 中的 Class 吗?

class 不仅仅是语法糖
// 用纯函数重写 class User

// 1. 创建构造器函数
function User(name) {
  this.name = name;
}
// 函数的原型(prototype)默认具有 "constructor" 属性,
// 所以,我们不需要创建它

// 2. 将方法添加到原型
User.prototype.sayHi = function() {
  alert(this.name);
};

// 用法:
let user = new User("John");
user.sayHi();

这个定义的结果与使用类得到的结果基本相同。因此,这确实是将 class 视为一种定义构造器及其原型方法的语法糖的理由。

但它们之间存在重大差异:

1.通过 class 创建的函数具有特殊的内部属性标记 [[IsClassConstructor]]: true

2.类方法不可枚举

3.类总是使用 use strict。 在类构造中的所有代码都将自动进入严格模式

类语法的其他功能

(1)类表达式

就像函数一样,类可以在另外一个表达式中被定义,被传递,被返回,被赋值等。

let User = class {
  sayHi() {
    alert("Hello");
  }
};

(2)class 字段

之前,我们的类仅具有方法。

“类字段”是一种允许添加任何属性的语法。

例如,让我们在 class User 中添加一个 name 属性:

class User {
name = "John";

  sayHi() {
    alert(`Hello, ${this.name}!`);
  }
}

new User().sayHi(); // Hello, John!

(3)丢失 this 问题

如果一个对象方法被传递到某处,或者在另一个上下文中被调用,则 this 将不再是对其对象的引用。

例如,此代码将显示 undefined

class Button {
  constructor(value) {
    this.value = value;
  }

  click() {
    alert(this.value);
  }
}

let button = new Button("hello");

setTimeout(button.click, 1000); // undefined

我们有两种可以修复它的方式

  1. 传递一个包装函数,例如 setTimeout(() => button.click(), 1000)
  2. 将方法绑定到对象,例如在 constructor 中。

类字段提供了另一种非常优雅的语法:

class Button {
  constructor(value) {
    this.value = value;
  }
click = () => {
    alert(this.value);
  }
}

let button = new Button("hello");

setTimeout(button.click, 1000); // hello

类字段 click = () => {...} 是基于每一个对象被创建的,在这里对于每一个 Button 对象都有一个独立的方法,在内部都有一个指向此对象的 this。我们可以把 button.click 传递到任何地方,而且 this 的值总是正确的。

下文我们继续说类继承

本网站是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 本网站还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 除此之外,本网站还拥有一个活跃的社区,您可以在社区中与其他前端开发者交流技术、分享经验、解决问题。我们相信,社区的力量可以帮助您更好地成长和进步。 在本网站中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!