深入理解ES6 009【學習筆記】

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 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是語法糖,PersonClass聲明實際上創建了一個具有構造函數方法行為的函數。通過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

靜態成員

ES6類語法簡化了創建靜態成員的過程,在方法或訪問器屬性名前使用正式的靜態注釋即可。

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")

繼承與派生類

實現繼承與自定義類型是一個不小的工作,嚴格意義上的繼承需要多個步驟實現

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使用extends關鍵字可以指定類繼承的函數。原型會自動調整,通過調用super()方法即可訪問基類的構造函數

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

繼承自其的類我們稱之為派生類,如果在派生類中指定了構造函數必須調用super(),如果不這樣做程序就會報錯。

  • super
  • 只可在派生類的構造函數中使用super(),非派生類不可使用
  • 在構造函數中訪問this之前一定要調用super,它負責初始化this,
  • 如果不想調用super(),則唯一的方法是讓類的構造函數返回一個對象。

類方法遮蔽

派生類中的訪問總會覆蓋基類中的同名方法,如果想調用基類中的方法,我們可以使用super.getArea()

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

派生自表達式的類

ES6最強大的一面或許是從表達式導出類的功能了。只要表達式可以被解析為一個函數並且具有[[Construct]]屬性和原型,那麼就可以用extends進行派生。

內建對象的繼承

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直接繼承自Array,其行為與Array也很相似,操作數值型屬性會更新length屬性,操作length屬性也會更新數值型屬性。於是可以正確地繼承Array對象來創建自己的派生數組類型

Symbol.species屬性

內建對象繼承的一個實用之處是,原本在內建對象中返回實例自身的方法將自動返回派生類的實現。如你有一個繼承自Array的派生類MyArray,那麼像slice()這樣的方法也會返回一個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是諸多內部Symbol中的一個,它被用於定義返回函數的靜態訪問器屬性。被返回的函數是一個構造函數,每當要在實例方法中(不是構造函數中)創建類的實例時必須使用這個構造函數。以下這些都是實現該屬性定義的Symbol.species

  • 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)
  }
}

在構造函數中使用new.target

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

主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4335

(0)
Walker的頭像Walker
上一篇 2026年3月10日 00:00
下一篇 2026年3月8日 15:40

相關推薦

  • Go工程師體系課 008【學習筆記】

    訂單及購物車 先從庫存服務中將 srv 的服務代碼框架複製過來,查找替換對應的名稱(order_srv) 加密技術基礎 對稱加密(Symmetric Encryption) 原理: 使用同一個密鑰進行加密和解密 就像一把鑰匙,既能鎖門也能開門 加密速度快,適合大量數據傳輸 使用場景: 本地文件加密 數據庫內容加密 大量數據傳輸時的內容加密 內部系統間的快速通…

    個人 2025年11月25日
    26400
  • Go工程師體系課 018【學習筆記】

    API 網關與持續部署入門(Kong & Jenkins) 對應資料目錄《第 2 章 Jenkins 入門》《第 3 章 通過 Jenkins 部署服務》,整理 Kong 與 Jenkins 在企業級持續交付中的實戰路徑。即便零基礎,也能順著步驟搭建出自己的網關 + 持續部署流水線。 課前導覽:甚麼是 API 網關 API 網關位於客戶端與後端微服務…

    個人 2025年11月25日
    24700
  • 深入理解ES6 001【學習筆記】

    塊級作用域綁定 之前的變量聲明var無論在哪裡聲明的都被認為是作域頂部聲明的,由於函數是一等公民,所以順序一般是function 函數名()、var 變量。 塊級聲明 塊級聲明用於聲明在指定塊的作用域之外無法訪問的變量。塊級作用域存在於: 函數內部 塊中(字符和{和}之間的區域) 臨時死區 javascript引擎在掃描代碼發現變量聲明時,要麼將它們提升至作…

    個人 2025年3月8日
    1.7K00
  • 熱愛運動,挑戰極限,擁抱自然

    熱愛 在這個快節奏的時代,我們被工作、生活的壓力所包圍,常常忽略了身體的需求。而運動,不僅僅是一種健身方式,更是一種釋放自我、挑戰極限、與自然共舞的生活態度。無論是滑雪、攀岩、衝浪,還是跑步、騎行、瑜伽,每一種運動都能讓我們找到內心的激情,感受到生命的躍動。 運動是一場自我挑戰 挑戰極限,不僅僅是職業運動員的專屬,而是每一個熱愛運動的人都可以追求的目標。它可…

    個人 2025年2月26日
    1.4K00
  • 深入理解ES6 013【學習筆記】

    用模塊封裝代碼 javascript用“共享一切”的方法加載代碼,這是該語言中最容易出錯且另人感到困惑的地方。其他語言使用諸如包這樣的概念來定義代碼作用域。在es6以前,在應用程序的每一個js中定義的一切都共享一個全局作用域。隨著web應用程序變得更加複雜,js代碼的使用量也開始增長,這一做法會引起問題,如命名衝突和安全問題。es6的一個目標是解決作用域問題…

    個人 2025年3月8日
    1.2K00
簡體中文 繁體中文 English