全部 / 前端 / 技术 · 2022年7月1日 0

50 – 类,不仅仅是语法糖

原文地址:https://dev.to/bhagatparwinder/classes-not-just-syntactic-sugar-1n0m

上篇文章我们提到了类以及它是如何根据模板更简单的创建对象。class 关键字是在 ES2015/ES6 中引入的,有个常见的误区类只是语法糖仅此而已。类是面向对象编程的基础,我的这篇文章的目的是阐明这个误区和展示与通过 new 关键字创建对象的细微差别。

类都做了什么?

class EmployeeRecord {
    name = "New User";
    id = 0;

    constructor(firstName, lastName, id) {
        this.name = `${firstName} ${lastName}`;
        this.id = id;
    }

    reverseName() {
        return this.name.split("").reverse().join("");
    }
}

const employee1 = new EmployeeRecord("Parwinder", "Bhagat", 1);
const employee2 = new EmployeeRecord("Lauren", "L", 2);

console.log(employee1.name); // Parwinder Bhagat
console.log(employee2.name); // Lauren L
console.log(employee1.reverseName()); // tagahB redniwraP

在上面的 class 例子中:

  1. 在底层,创建了一个名为 EmployeeRecord 的函数,函数体就是由类的构造函数组成。如果没有构造函数,函数体将是空的。
  2. 类中所有的函数都会被存储在 EmployeeRecord 的原型上。

根据上面的逻辑,我们可以不用 class 关键字来重写上面的例子。

function EmployeeRecord(firstName, lastName, id) {
    this.name = `${firstName} ${lastName}`;
    this.id = id;
}

EmployeeRecord.prototype.reverseName = function () {
    return this.name.split("").reverse().join("");
}

let employee1 = new EmployeeRecord("Parwinder", "Bhagat", 1);
const employee2 = new EmployeeRecord("Lauren", "L", 2);

console.log(employee1.name); // Parwinder Bhagat
console.log(employee2.name); // Lauren L
console.log(employee1.reverseName()); // tagahB redniwraP

类有何不同?

  • 有一个特定的函数种类分配给类,并且在多个地方被检查,最重要的是当我们实例化一个类时。
class EmployeeRecord {
    constructor() { }
}

console.log(typeof EmployeeRecord); // function
EmployeeRecord(); // Value of type 'typeof EmployeeRecord' is not callable. Did you mean to include 'new'?
  • 构造函数式的继承依赖原型链,而类则是通过 extends 关键字。
class Person {
    sayName() {
        console.log("My name is Person");
    }

    sayAge() {
        console.log("I am 30 years old."); // I am 30 years old.
    }
}

class Employee extends Person {
    sayDepartment() {
        console.log("I work for the tech department."); // I work for the tech department.
    }

    sayHello() {
        console.log("Hi, I am the new employee"); // Hi, I am the new employee
    }
}

let employee = new Employee;

employee.sayHello();
employee.sayAge();
employee.sayDepartment();

console.log(employee instanceof Person); // true
console.log(employee instanceof Employee); // true
  • 函数声明是会被提升,而类的声明不会。
const employee = new Employee(); // ReferenceError or Employee is not a constructor

class Employee {
    constructor() {}
}
  • 类始终运行在严格模式下,类中的所有代码自动都在严格模式下。
  • 函数声明或表达式可以被覆盖就像 var 声明的变量而类则不行。类就像 letconst 关键字声明的变量,let 在同一个作用域中是不允许声明同名变量的。
  • 对象的不可枚举属性在迭代的时候不会出现,类中的方法不会被迭代到。若我们使用 for...in 来遍历类中的对象,不会有方法出现。