目录
  • 简言
  • Class(类)
    • 定义类
      • 类声明
      • 类表达式
      • 类体和方法定义
    • 类的 constructor
      • 语法
      • 特点
    • 类继承(extends)
      • 类体中的修饰词
        • 私有属性和方法(#)
        • 静态属性和方法(static)
        • 公有字段
        • Static initialization blocks
    • 结语

      简言

      在面向对象编程中(object-oriented programming), 一个 类 定义了一个对象(object’s)的特征。类是定义对象属性(properties)和方法(methods)的模板,是用来绘制具体对象实例的“蓝图”。

      js中类是用于创建对象的模板,他们用代码封装数据以处理该数据,JS 中的类建立在原型上的。

      虽然js通过构造函数和原型链也能实现面向对象编程的特性,但是直接实现的话比较复杂,所以JavaScript 提供了Class(类)模型,它是把面向对象编程特性从原型的基础上实现的,从而能够更为直观地在 JavaScript 中使用基于类的面向对象编程中的概念。

      Class(类)

      实际上,类是“特殊的函数”,就像你能够定义的函数表达式和函数声明一样。

      定义类

      类语法有两个组成部分:类表达式和类声明。类声明和类表达式的主体都执行在严格模式下。比如,构造函数,静态方法,原型方法,getter 和 setter 都在严格模式下执行。

      类声明

      定义类的一种方法是使用类声明。要声明一个类,你可以使用带有class关键字的类名。

      类声明不会提升。你首先需要声明你的类,然后再访问它,否则将抛出ReferenceError

      class Rectangle {
        constructor(height, width) {
          this.height = height;
          this.width = width;
        }
      }
      

      类表达式

      类表达式是定义类的另一种方法。类表达式可以命名或不命名。命名类表达式的名称是该类体的局部名称。(不过,可以通过类的 (而不是一个实例的) name 属性来检索它)。

      // 未命名/匿名类
      let Rectangle = class {
        constructor(height, width) {
          this.height = height;
          this.width = width;
        }
      };
      console.log(Rectangle.name);
      // output: "Rectangle"
      
      // 命名类
      let Rectangle = class Rectangle2 {
        constructor(height, width) {
          this.height = height;
          this.width = width;
        }
      };
      console.log(Rectangle.name);
      // 输出:"Rectangle2"
      
      

      类体和方法定义

      一个类的类体是一对花括号/大括号 {} 中的部分。这是你定义类成员的位置,如方法或构造函数。

      constructor方法是一个特殊的方法,这种方法用于创建和初始化一个由class创建的对象。一个类只能拥有一个名为“constructor”的特殊方法。如果类包含多个constructor的方法,则将抛出 一个SyntaxError 。

      一个构造函数可以使用 super 关键字来调用一个父类的构造函数。

      类里面的方法和对象里的方法写法一样,不过它可以加些特殊的修饰词,修饰词不同作用不同,例如加 static就变了静态方法,添加#就变成了私有方法。

      类的 constructor

      constructor 是一种用于创建和初始化class创建的对象的特殊方法。
      constructor函数创建类对象实例时的new息息相关。

      语法

      constructor([arguments]) { ... }
      

      特点

      • 在一个类中只能有一个名为“constructor”的特殊方法。一个类中出现多次构造函数 (constructor)方法将会抛出一个 SyntaxError 错误。

      • 在一个构造方法中可以使用super关键字来调用一个父类的构造方法。

      • 如果没有显式指定构造方法,则会添加默认的 constructor 方法。

      • 如果不指定一个构造函数 (constructor) 方法,则使用一个默认的构造函数 (constructor)。

      对于基类,默认构造函数是:

      constructor() {}

      对于派生类(有祖先类)的默认构造函数:

      constructor(...args) {
        super(...args);
      }

      例子

      class Polygon {
        constructor() {
          this.name = "Polygon";
        }
      }
      
      class Square extends Polygon {
        constructor() {
          super();
        }
      }
      
      class Rectangle {}
      
      Object.setPrototypeOf(Square.prototype, Rectangle.prototype);
      
      console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false
      console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true
      
      let newInstance = new Square();
      console.log(newInstance.name); //Polygon

      类继承(extends)

      extends 关键字用于类声明或者类表达式中,以创建一个类,该类是另一个类的子类,也叫派生类。
      特点

      • 派生类创建构造函数时要带上super(),不然会报错。
      • 派生类会继承类的方法和属性,并可以在类实例和类体中使用。
      • 派生类重写的同名方法和属性,将会覆盖基类的方法和属性。
      class Animal {
        name = "";
        constructor(name) {
          this.name = name;
        }
        eat() {
          console.log("吃东西");
        }
      }
      class Cat extends Animal {
        constructor(name, color) {
          super(name);
          //  通过this可获取祖先类的属性
          this.color = color;
        }
        skill() {
          console.log(this.name + "抓老鼠");
        }
        eat2() {
          //  通过this可获取祖先类的方法
          this.eat();
          console.log(`${this.color}猫` + this.name + "吃东西");
        }
      }
      const tom = new Cat("汤姆", "skyblue");
      tom.eat2(); //  继承Animal的方法
      tom.skill();
      

      javascript中Class(类)的介绍和使用方法

      类体中的修饰词

      私有属性和方法(#)

      类属性在默认情况下是公有的,但可以使用增加哈希前缀 # 的方法来定义私有类字段(私有属性和方法统称私有字段)。

      class ClassWithPrivateField {
        #privateField;
      }
      
      class ClassWithPrivateMethod {
        #privateMethod() {
          return "hello world";
        }
      }
      
      class ClassWithPrivateStaticField {
        static #PRIVATE_STATIC_FIELD;
      }
      
      class ClassWithPrivateStaticMethod {
        static #privateStaticMethod() {
          return "hello world";
        }
      }

      私有字段分为私有实例字段和私有静态字段:

      • 私有实例字段使用 #名称(发音为“哈希名称”)声明,这些名称以 # 开头。即 # 是名称本身的一部分,声明和访问时也需要加上。它只能在类体中访问和修改,不能在外面直接使用和修改。
      • 私有静态字段。在私有实例字段前面加 static。在类体中只能通过类本身调用和修改。
      class Obj {
        #name = ""; //  私有,只能在里面使用
        static #age = 18; //  私有,只能在里面被类本身使用
        constructor(name, age) {
          this.#name = name;
          Obj.#age = age;
        }
        base() {
          console.log(`${this.#name}   ${Obj.#age}`);
        }
      }
      const obj1 = new Obj("hh", 20);
      obj1.base();
      

      静态属性和方法(static)

      类(class)通过 static 关键字定义静态方法。不能在类的实例上调用静态方法,而应该通过类本身调用。这些通常是实用程序方法,例如创建或克隆对象的功能。

      特点:

      • 静态方法调用同一个类中的其他静态方法,可使用 this 关键字。
      • 静态方法调用直接在类上进行,不能在类的实例上调用。
      • 非静态方法中,不能直接使用 this 关键字来访问静态方法。而是要用类名来调用或者用构造函数的属性来调用该方法。
      class Tripple {
        static tripple(n = 1) {
          return n * 3;
        }
      }
      
      class BiggerTripple extends Tripple {
        static tripple(n) {
          return super.tripple(n) * super.tripple(n);
        }
      }
      
      console.log(Tripple.tripple()); // 3
      console.log(Tripple.tripple(6)); // 18
      
      let tp = new Tripple();
      
      console.log(BiggerTripple.tripple(3)); // 81(不会受父类实例化的影响)
      console.log(tp.tripple()); // 'tp.tripple 不是一个函数'.

      公有字段

      公有静态字段和公有实例字段都是可编辑、可枚举和可配置的属性。因此,不同于私有对应值(private counterpart)的是,它们参与原型的继承。
      默认就是公有字段。可以在类对象实例中使用和修改。

      Static initialization blocks

      静态初始化块在类中声明。
      特点:

      • 在类体中 用static修饰的{}括号内容区域。里面this指向类的构造函数对象,可以使用this调用其他公共静态字段。
      • {}内可以声明变量,这包括 var、function、const 和 let 声明。
      • 可以有多个 静态初始化块。
      class MyClass {
        static field1 = console.log("static field1");
        static {
          console.log("static block1");
        }
        static field2 = console.log("static field2");
        static {
          console.log("static block2");
        }
      }
      // 'static field1'
      // 'static block1'
      // 'static field2'
      // 'static block2'

      如何从类外的对象访问类的私有实例字段。

      let getDPrivateField;
      
      class D {
        #privateField;
        constructor(v) {
          this.#privateField = v;
        }
        static {
          getDPrivateField = (d) => d.#privateField;
        }
      }
      
      console.log(getDPrivateField(new D("private"))); // 'private'

      结语

      类编程室es6的,不是兼容所有版本的浏览器。

      声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。