JS類—class


典型的面向對象編程語言(比如C++和Java)存在類(class)這個概念。所謂類就是對象的模板,對象是類的實例

JS中沒有類,在ES5中使用構造函數(constructor)作為對象的模板。但是ES5中實現繼承的代碼非常冗長與混亂(盜用構造函數、組合繼承、原型式繼承等等),因此在ES6中新引入了class關鍵字具有了正式定義類的能力

  類(class)是ECMAScript中新的基礎性語法糖結構。其背后使用的仍然是原型和構造函數的概念

1.類定義

class Person {}
const Person = class {}

 說明:

  • class聲明不存在變量提升:
    • console.log(classDemo);
      class classDemo {};        // var_let_const.html:12 Uncaught ReferenceError: Cannot access 'classDemo' before initialization
  • 函數受函數作用域限制,而類受塊作用域限制:
    •         {
                  class classDemo { };
              }
      
              console.log(classDemo);        // var_let_const.html:16 Uncaught ReferenceError: classDemo is not defined
  • 類名首字母同函數構造函數一樣,建議類名首字母大寫

2.類構造函數

constructor關鍵字用於在類定義塊內部創建類的構造函數。方法名constructor會告訴解釋器在使用new操作符創建類的新實例時,應該調用這個函數。

構造函數非必須,不定義相當於構造函數為空

示例:

        class Person { 
            constructor(override){
                console.log("我是一個人")
            }
        };

        let p1 = new Person()        // 我是一個人

 (1)使用new實例化類

  使用new實例化的操作等於使用new調用其構造函數,new執行的操作有:

  • 在內存中創建一個新對象
  • 這個新對象內部的__proto__屬性賦值為構造函數的prototype屬性
  • 構造函數內部的this被賦值為這個新對象(this指向了新對象)
  • 執行構造函數內部的代碼
  • 如果構造函數返回非空對象,則返回該對象,否則返回剛創建的新對象

說明:

  • 類實例化時傳入的參數會用作構造函數的參數。如果不需要參數,則類名后面的括號是可選的
  • 類構造函數與構造函數的主要區別在於:
    • 調用類構造函數必須使用new操作符。不使用new則會拋出錯誤(Uncaught TypeError: Class constructor Person cannot be invoked without 'new'
    • 而普通構造函數如果不使用new調用,那么就會以全局的this(window)作為內部對象

(2)把類當成特殊函數

JS中並沒有正式的類這個類型。從各方面看,ECMAScript的類就是一種特殊的函數。可以使用typeof 檢測表明它是一個函數:

        class Person { };

        console.log(typeof Person);    // function
  • 可以使用instanceof操作符檢查一個對象是不是類的實例:
1         class Person {};
2 
3         let p = new Person()
4 
5         console.log(p instanceof Person);    // true
  • 類也可以向其他對象或者函數引用一樣把類作為參數傳遞
 1         let pList = [
 2             class Person {
 3                 constructor ( id ){
 4                     this._id = id
 5                     console.log("類作為參數:",this._id)
 6                 }
 7             }
 8         ]
 9 
10         function createIns( classDefinition, id ){
11             return new classDefinition(id)
12         }
13 
14         let foo = createIns(pList[0],1234)    // 類作為參數: 1234
  •  類還可以立即實例化
1         let foo = new class Person {
2             constructor(id) {
3                 console.log("立即實例化對象")
4             }
5         }

3.實例、原型和類成員

每次通過new調用類標識符時,都會執行類構造函數,在這個函數內部,可以為新創建的實例(this)添加自有屬性。且構造函數執行完畢以后,仍然可以給實例繼續添加新成員。

(1)實例成員

每個實例都對應一個唯一的成員對象,即所有成員都不會在原型上共享:

 1         class Person {
 2             constructor(id) {
 3                 this.name = new String('Jack')
 4 
 5                 this.sayName = () => console.log(this.name);
 6 
 7                 this.nickNames = ['張三','李四']
 8             }
 9         }
10 
11         let p1 = new Person(),p2 = new Person();
12 
13         p1.sayName();    // Jack
14         p2.sayName();    // Jack
15         console.log(p1.name === p2.name); // false
16         console.log(p1.sayName === p2.sayName); // false
17         console.log(p1.nickNames === p2.nickNames); // false

(2)原型方法與訪問器

為了在實例間共享方法,類定義語法把在類塊中定義的方法作為原型方法

 1         class Person {
 2             constructor() {
 3                 // 存在這個類的不同的實例上
 4                 this.locate = () => console.log("instance");
 5             }
 6             // 在類塊中定義的所有內容都會定義在類的原型上
 7             locate() {
 8                 console.log("prototype");
 9             }
10         }
11 
12         let p = new Person()
13 
14         p.locate()    // instance
15         Person.prototype.locate()    // prototype
  • 可以把方法定義在類構造函數中或者類塊中,但不能在類塊中給原型添加原始值或對象作為成員數據
1         class Person {
2             name: '張三'
3         }
4         // Uncaught SyntaxError: Unexpected identifier
  • 類方法等同於對象屬性,因此可以使用字符串、符號或計算的值作為鍵
 1         let funName = "fn02"
 2 
 3         class Person {
 4             
 5             fn01(){
 6                 console.log("字符串屬性名");
 7             }
 8 
 9             [funName](){
10                 console.log("變量屬性名");
11             }
12 
13             ['fn' + '03'](){
14                 console.log("計算屬性名");
15             }
16 
17         }
18         
19         let p = new Person()
20         p.fn01()    // 字符串屬性名
21         p.fn02()    // 變量屬性名
22         p.fn03()    // 計算屬性名
  • 類定義也支持get與set訪問器:
 1         class Person {
 2 
 3             set name(newName){
 4                 console.log("設置新值為:",newName);
 5                 this._name = newName
 6             }
 7             
 8             get name(){
 9                 console.log("讀取到新值:",this._name);
10                 return this._name
11             }
12 
13         }
14         
15         let p = new Person()
16         p.name = "張三"        // 設置新值為: 張三
17         p.name    // 讀取到新值: 張三

 (3)非函數原型和類成員

類定義並不顯式支持在原型或類上添加成員數據,但是可以在類定義外部手動添加:

 1         class Person {
 2 
 3             sayName() {
 4                 console.log(`${ Person.greeting }${ this.name }`);
 5             }
 6 
 7         }
 8         // 在類上定義數據成員
 9         Person.greeting = ' 我的名字是'
10         // 在原型上定義數據成員
11         Person.prototype.name = '張三'
12         
13         let p = new Person()
14         p.sayName()    // 我的名字是張三

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM