← Back
前端开发 2025.03.08

In-depth Understanding of ES6 009 [Learning Notes]

前端开发

Table of Contents

Classes in JavaScript

function PersonType(name){
  this.name = name;
}
PersonType.prototype.sayName = function(){
  console.log(this.name)
}
var person = new PersonType("Nicholas")
person.sayName(); // outputs "Nicholas"

console.log(person instanceof PersonType) // true
console.log(person instanceof Object) // true

Class Declarations

class PersonClass {
  // 等价于PersonType构造函数
  constructor(name){
    this.name = name
  }
  // 等价于PersonType.prototype.sayName
  sayName(){
    console.log(this.name)
  }
}
let person = new PersonClass("Nicholas");
person.sayName(); // outputs "Nicholas"

console.log(person instanceof PersonClass) //true
console.log(person instanceof Object) // true
console.log(typeof PersonClass) // function
console.log(typeof PersonClass.prototype.sayName) // function

class is a syntactic sugar. A PersonClass declaration actually creates a function with the behavior of a constructor method. A default iterator can be defined by defining a generator method via Symbol.iterator.

class Collection {
  constructor(){
    this.items = [];
  }

  *[Symbol.iterator](){
    yield *this.items.values()
  }
}
var collection = new Collection();
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);

for(let x of collection){
  console.log(x);
}
// 输出:
// 1
// 2
// 3

Static Members

The ES6 class syntax simplifies the process of creating static members. You can use the formal static annotation before a method or accessor property name.

class PersonClass {
  // 等价于PersonType构造函数
  constructor(name){
    this.name = name
  }
  // 等价于PersonType.prototype.sayName
  sayName(){
    console.log(this.name)
  }
  // 等价于等价于PersonType.create
  static create(name){
    return new PersonClass(name)
  }
}
let person = PersonClass.create("Nicholas")

Inheritance and Derived Classes

Implementing inheritance and custom types is a significant task; strict inheritance requires multiple steps.

function Rectangle(length,width){
  this.length = length;
  this.width = width;
}
Rectangle.prototype.getArea = function(){
  return this.length*this.width
}

function Square(length){
  Rectangle.call(this,length,length)
}

Square.prototype = Object.create(Rectangle.prototype,{
  constructor:{
    value:Square,
    enumerable:true,
    writable:true,
    configurable:true
  }
})
var square = new Square(3)
console.log(square.getArea()); // 9
console.log(square instanceof Square) // true
console.log(square instanceof Rectangle) // true

ES6 uses the extends keyword to specify the function a class inherits from. The prototype is automatically adjusted, and the base class’s constructor can be accessed by calling the super() method.

class Rectangle {
  constructor(length,width){
    this.length = length;
    this.width = width
  }
  getArea(){
    return this.length*this.width;
  }
}
class Square extends Ractangle {
  constructor(length){
    // Rectangle.call(this,length,length)
    super(length,length)
  }
}
var square = new Square(3)
console.log(square.getArea()); // 9
console.log(square instanceof Square) // true
console.log(square instanceof Rectangle) // true

Classes that inherit from others are called derived classes. If a constructor is specified in a derived class, super() must be called; otherwise, the program will throw an error.

  • super
  • super() can only be used in the constructor of a derived class, not in non-derived classes.
  • super must be called before accessing this in the constructor, as it is responsible for initializing this.
  • If you do not want to call super(), the only way is to have the class’s constructor return an object.

Class Method Shadowing

Access in a derived class will always override a method with the same name in the base class. If you want to call the method in the base class, you can use super.getArea().

class Square extends Rectangle {
  constructor(length){
    super(length,length)
  }
  //覆盖并遮蔽Rectangle.prototype.getArea()方法
  getArea(){
    return this.length*this.length
  }
}

Classes Derived from Expressions

Perhaps one of the most powerful aspects of ES6 is the ability to derive classes from expressions. As long as an expression can be resolved to a function with a [[Construct]] property and a prototype, it can be extended using `extends`.

Inheriting Built-in Objects

class MyArray extends Array {
  // 空
}
var colors = new MyArray();
colors[0]="red"
console.log(colors.length) // 1
colors.length = 0
console.log(colors[0]); // undefined

MyArray directly inherits from Array, and its behavior is very similar to Array. Operations on numeric properties update the length property, and operations on the length property also update numeric properties. Thus, you can correctly inherit the Array object to create your own derived array types.

Symbol.species Property

A practical aspect of built-in object inheritance is that methods in built-in objects that originally returned an instance of themselves will automatically return an implementation of the derived class. For example, if you have a derived class MyArray that inherits from Array, methods like slice() will also return an instance of MyArray.

class MyArray extends Array{
  // 空
}
let items = new MyArray(1,2,3,4),
subitems = items.slice(1,3);
console.log(items instanceof MyArray); //true
console.log(subitems instanceof Myarray); // true

Symbol.species is one of several internal Symbols, used to define a static accessor property that returns a function. The returned function is a constructor that must be used whenever an instance of the class is to be created within an instance method (not in the constructor). The following are all Symbol.species implementations that define this property:

  • Array
  • ArrayBuffer
  • Map
  • Promise
  • RegExp
  • Set
  • Typed arrays
// 几个内建类型像这样使用
class MyClass {
  static get [Symbol.species](){
    return this
  }
  constructor(value){
    this.value = value
  }
  clone(){
    return new this.constructor[Symbol.species](this.value)
  }
}

Using new.target in Constructors

class Shape {
  constructor(){
    if(new.target === Shape){
      throw new Error("这个类是不能直接被实例化的")
    }
  }
}
class Rectangle extends Shape {
  constructor(length,width){
    super();
    this.length = length;
    this.width = width;
  }
}
let x = new Shap(); // 抛出错误
let y = new Rectangle(3,4) // 正常执行
console.log(y instanceof Shape) //true