The “class” syntax

我們時常創造一樣的物件,像是 user、goods,建構函式可以幫我們創造一樣的物件,還有 class 結構可以幫我們。

The “class” syntax

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

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

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

// new User("John") => 新的物件產生,參數被帶到 constructor
// class 不需要,

What is a class?

// class 是一種函式
class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// proof: User is a function
alert(typeof User); // function
// class 的方法儲存在 User.prototype
class User {
  constructor(name) { this.name = name; }
  sayHi() { alert(this.name); }
}

// class is a function
alert(typeof User); // function

// ...or, more precisely, the constructor method
alert(User === User.prototype.constructor); // true

// The methods are in User.prototype, e.g:
alert(User.prototype.sayHi); // alert(this.name);

// there are exactly two methods in the prototype
alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi

Not just a syntax sugar

// 不需要 class 也可以寫出一樣的功能,有人說 class 只是一種語法糖
// rewriting class User in pure functions

// 1. Create constructor function
function User(name) {
  this.name = name;
}
// any function prototype has constructor property by default,
// so we don't need to create it

// 2. Add the method to prototype
User.prototype.sayHi = function() {
  alert(this.name);
};

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

// 以下有幾點跟一般函式不同
// 1. 當沒有使用 new 時 class 不能被呼叫
class User {
  constructor() {}
}

alert(typeof User); // function
User(); // Error: Class constructor User cannot be invoked without 'new'

// 2. class 函式用 class 開頭
class User {
  constructor() {}
}

alert(User); // class User { ... }

// 3. class 方法 non-enumerable,不能顯示在迴圈 for..in
// 4. class 永遠 use strict,在 class 的程式碼都是 strict 的模式

Class Expression

// 就像一般函式,class 可以寫成 expression
let User = class {
  sayHi() {
    alert("Hello");
  }
};

// class 的名稱可有可無
// "Named Class Expression"
// (no such term in the spec, but that's similar to Named Function Expression)
let User = class MyClass {
  sayHi() {
    alert(MyClass); // MyClass is visible only inside the class
  }
};

new User().sayHi(); // works, shows MyClass definition

alert(MyClass); // error, MyClass not visible outside of the class

// 依照需求創造 class
function makeClass(phrase) {
  // declare a class and return it
  return class {
    sayHi() {
      alert(phrase);
    };
  };
}

// Create a new class
let User = makeClass("Hello");

new User().sayHi(); // Hello

Getters/setters, other shorthands

// class 也有 get/set
class User {

  constructor(name) {
    // invokes the setter
    this.name = name;
  }

  get name() {
    return this._name;
  }

  set name(value) {
    if (value.length < 4) {
      alert("Name is too short.");
      return;
    }
    this._name = value;
  }

}

let user = new User("John");
alert(user.name); // John

user = new User(""); // Name too short.

Object.defineProperties(User.prototype, {
  name: {
    get() {
      return this._name
    },
    set(name) {
      // ...
    }
  }
});

// 使用計算的屬性
function f() { return "sayHi"; }

class User {
  [f()]() {
    alert("Hello");
  }

}

new User().sayHi();

Class properties

// 在 class 加屬性,並不會放到 User.prototype,該屬性是獨立的在不同物件相同 class 
class User {
  name = "Anonymous";

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

new User().sayHi();

Last updated