ES6 Class关键字详解:从原型链到现代类定义

作者:函数茶馆时间:2026-10-22 09:57:04浏览:157

本文详细解析ES6中class关键字的核心特性,包括其作为构造函数包装的本质、constructor方法的默认行为、严格模式的强制应用以及私有属性和私有方法的模拟实现方案。重点探讨this在类方法中的指向问题及解决方案,并对比Class表达式与变量提升机制,帮助开发者掌握现代JavaScript面向对象编程的关键规范。

ES6 Class关键字概述

class关键字是ES6标准引入的核心特性之一,它极大地简化了JavaScript中面向对象编程的语法结构。在ES6出现之前,开发者主要依赖原型链机制来模拟类的行为,这种方式虽然灵活但较为晦涩。

Class基础与语法规范

1、基础介绍


  //定义类
  class Point {
   constructor(x, y) {
   this.x = x;
   this.y = y;
   }
   toString() {
   return '(' + this.x + ', ' + this.y + ')';
   }
  }

以Point类为例,该类不仅包含构造方法,还定义了一个toString方法。在定义类的方法时,无需添加function关键字,直接将函数体放入类定义块中即可。需要注意的是,各个方法之间不需要使用逗号进行分隔,若错误地添加逗号,代码执行时会抛出语法错误。


 //类的数据类型就是函数,类本身就指向构造函数。用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。
  class Bar {
   doStuff() {
   console.log('stuff');
   }
  }
  var b = new Bar();
  b.doStuff() // "stuff"

严格模式与Constructor方法

2、严格模式

类定义内部以及模块作用域内,默认强制启用严格模式,因此无需显式使用'use strict'指令。只要代码编写在class或模块结构中,运行环境即自动处于严格模式下,这有助于避免一些常见的JavaScript陷阱。

3、constructor方法

constructor是类的默认构造方法,当使用new命令创建对象实例时,该方法会被自动调用。每个类都必须包含constructor方法,如果开发者未显式定义,解释器会默认添加一个空的constructor方法,以确保类的实例化过程正常进行。


class Point {
  }
  // 等同于
  class Point {
   constructor() {}//constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
  }
  //注意:类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。

实例对象与属性定义

4、实例对象生成

生成类的实例需使用new命令,这是创建对象的标准方式。

实例属性的归属取决于定义位置:若属性显式定义在实例本身(即this对象上),则属于实例属性;否则,属性默认定义在原型链上(即class定义中),所有实例共享这些属性。


 class Point {
   // ...
  }
  // 报错
  var point = Point(2, 3);
  // 正确
  var point = new Point(2, 3);

Class表达式与变量提升

5、Class表达式

可以通过表达式形式定义类,例如将类赋值给变量。需注意,此类表达式的名称(如Me)仅在类内部代码中可用,用于指代当前类,而在外部访问时,应使用赋值给的变量名(如MyClass)。


 const MyClass = class Me {
   getClassName() {
   return Me.name;
   }
  };
  //采用 Class 表达式,可以写出立即执行的 Class。
  var person = new class {
   constructor(name) {
   this.name = name;
   }
   sayName() {
   console.log(this.name);
   }
  }('张三');
  person.sayName(); // "张三"

6、变量提升机制

与函数不同,类声明不存在变量提升(hoisting)现象。

若尝试在类定义之前使用该类(如调用new Foo()而Foo类定义在后),代码将抛出ReferenceError。这是因为ES6规定类的声明不会提升到代码头部,这一设计旨在确保子类在定义时,其父类已经存在,从而保证继承关系的正确性。


  new Foo(); // ReferenceError
  class Foo {} 

私有方法与属性实现

7、私有方法模拟

ES6标准本身并未直接提供私有方法的语法支持,但可通过变通方案模拟实现私有行为。

常见的私有方法实现策略包括以下两种:

第一种是通过命名约定进行区分,通常以_(下划线)开头的方法名暗示其为私有方法,尽管这并非真正的私有,仅是开发者的约定。

第二种是利用Symbol值的唯一性,将私有方法名定义为Symbol值,从而在类外部无法通过常规方式访问该方法,实现更严格的私有控制。


 /*命名上加以区别*/
  class Widget {
   // 公有方法
   foo (baz) {
   this._bar(baz);
   }
   // 私有方法
   _bar(baz) {
   return this.snaf = baz;
   }
   // ...
  }
  /*利用Symbol*/
  const bar = Symbol('bar');
  const snaf = Symbol('snaf');
  
  export default class myClass{
   // 公有方法
   foo(baz) {
   this[bar](baz);
   }
   // 私有方法
   [bar](baz) {
   return this[snaf] = baz;
   }
   // ...
  };

8、私有属性提案

与私有方法类似,ES6标准初期也不支持私有属性。目前已有相关提案,通过在属性名或方法名前添加#符号来表示私有成员,这是目前实现真正私有属性的主流语法方案。


 class Point {
   #x;
   constructor(x = 0) {
   #x = +x; // 写成 this.#x 亦可
   }
   get x() { return #x }
   set x(value) { #x = +value }
  }

This指向与Name属性

9、this指向问题

在类的方法内部,this关键字默认指向该类的实例。然而,如果将某个方法单独提取出来使用(例如作为回调函数或解构后调用),this的指向可能会发生改变,指向调用时的上下文环境,这可能导致找不到预期方法而报错。


 class Logger {
   printName(name = 'there') {
   this.print(`Hello ${name}`);
   }
  
   print(text) {
   console.log(text);
   }
  } 
  const logger = new Logger();
  const { printName } = logger;
  printName();
  //上面代码中,printName方法中的this,默认指向Logger类的实例。但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境,因为找不到print方法而导致报错。
  /*解决方法是,在构造方法中绑定this,这样就不会找不到print方法了。*/
  class Logger {
   constructor() {
   this.printName = this.printName.bind(this);
   }  
   // ...
  }

10、name属性

由于ES6的类本质上是ES5构造函数的语法糖,它继承了函数的许多特性,其中包括name属性。name属性始终返回紧跟在class关键字后的类名,这有助于调试和识别类的身份。


 class Point {}
  Point.name // "Point"

总结

以上内容涵盖了ES6中class关键字的主要特性和使用注意事项,旨在帮助开发者更好地理解和应用现代JavaScript的面向对象编程特性。

作者最新文章