深入理解es6 class

概覽

  • 類的基本語法
  • 類的繼承
  • 類的實例
  • es5下的面向對象

類的基本語法

  • 構造方法 實例屬性 實例方法(普通 generator方法 setter getter async)靜態屬性 靜態方法 私有屬性 私有方法
class People {
    constructor(name,age,sex) {
        this.name = name;
        this.age= age;
        this.sex= sex;
    }
}
//類裏面的成員方法與屬性都採用小駝峯
class Boy extends People {
    constructor(name,age) {
        super(name,age,'男');
    }
    
    /*私有屬性與私有方法在屬性或方法上加#,只能在類內部使用 私有屬性和私有方法前面,也可以加上static關鍵字,
    表示這是一個靜態的私有屬性或私有方法 私有隻是提案,現有chrome已經實現,見1.1*/
    #a;
    #b=3;
    static #c= 4;
    static #m(){}
    #parseName(){
        return this.name.replace(/\s/g,'');
    }
    
    //實例屬性的另外一種寫法 一種是constructor中this.x
    money;
    money= 1000;
    
    //靜態屬性 通過類訪問
    static maxAge= 120;//見1.2
    
    //getter
    get age(){
        retun this.age+1;//見1.4
    }
    //setter
    set age(value){
        this.age= Math.floor(value);
        //setter方法在對象中(非類)需要注意 可能內存溢出,見1.3
    }
    
    //靜態方法 不能訪問實例屬性與方法
    static getMaxAge(){
        return Boy.maxAge;
    }
    getAge(){
        return this.age+this.#b;
    }
    
    //generator方法
    *getName(){
        yield Promise.resolve(1);
        yield Promise.resolve(2);
    }
    
    //異步函數 串行執行 比如獲取了用戶的銀行餘額 再去付款
    async serial(){
        let b= await Promise.resolve(1);//返回值,不是promise
        let c= await Promise.resolve(b);
        return c; //返回promise包裝
    }
    
    //靜態方法 自我實現四捨五入
    static round(value){
        if(typeof value ==='number'){
            return (Number.parseInt(value)+.5>value)?Number.parseInt(value):(Number.parseInt(value)+1)
        }else{
            return 0;
        }
    }
}
//1.1
class PrivateVar{
    #a=2;
    b=3;
    getA(){
        return this.#a;
    }
}
var p1= new PrivateVar();
console.log(p1.#a);//報錯
console.log(p1.b);//3
console.log(p1.getA());//2
//1.2
class Static1{
    static width= 200;
    height= 100;
    static getArea(){
        //錯誤寫法 靜態不能訪問非靜態屬性
        return Static1.width*this.height;
    }
    getMaxSide(){
        //非靜態方法可以訪問靜態屬性
        return Math.max(Static1.width,this.height);
    }
}
let s1= new Static1();
s1.getMaxSide();
Static1.gettArea();
/*NaN (一個數字與undefined相加=NaN,null+數字=數字,字符串+數字=字符串拼接,true+1=2,false+1=1,對象+1=1)
轉化優先級undefined,null,boolean=>number=>string,
1.任何與字符串相加都是字符串
2.其它相加先轉化爲數字,undefined=》NaN,null=>0
3.NaN與其它數字相加等於NaN*/
//1.3
let user = {
  name: 'xx'.
  get name() {
    return this.name;
  },
  set name(value) {
    this.name = value //這句話報錯了
  }
};
user.name = "Peter"; //嘗試賦值的時候報錯Uncaught RangeError: Maximum call stack size exceeded
//解決方法
let user = {
  _name:'xx',
  get name() {
    return this._name;
  },
  set name(value) {
    this._name = value //設置一箇中轉變量
  }
};
//1.4
class SetVar{
    m=2;
    set m(d){this.m=d}
}
let d=new SetVar();
d.m=99;//{m:99}
  • 類方法之間不需要逗號分隔,加了會報錯
  • 類的內部所有定義的方法,都是不可枚舉的(non-enumerable)。
class Point {
  constructor(x, y) {
    // ...
  }
  toString() {
    // ...
  }
}
Object.keys(Point.prototype)// []
  • 類與模塊爲嚴格模式,不需要聲明 use strict;
  • 類必須使用new調用,否則會報錯。這是它跟普通構造函數的一個主要區別,後者不用new也可以執行。
function m(){console.log(new.target===m)}
m()//false
new m()// true  通過這個可以強制函數通過new來調用
  • 類不存在變量提升(hoist),這一點與 ES5 完全不同。
new Foo(); // ReferenceError
class Foo {}
  • 方法多層嵌套,this指向問題解決
1.箭頭函數
2.重新賦值 如 let _t= this;
3.綁定this指向
class Logger {
  constructor() {
    this.printName = this.printName.bind(this);
  }
  // ...
}
  • 類名採用大駝峯命名(單詞首字母大寫)

類的繼承

  • 類繼承使用 extends 關鍵字
  • super() 可以調用父類的構造方法(可以傳遞非默認參數)
  • 如果沒有顯式指定構造方法,則會添加默認的 constructor 方法。不顯式調用會默認調用父類的構造方法
基類默認構造方法
constructor() {}
派生類,默認構造函數
constructor(...args) {
  super(...args);
}
//-------
class A {constructor(a){this.a=a;}};
class B extends A{}
new B(1)//{a:1}
  • 派生類可以繼承父類的屬性與方法

類的實例化

  • 調用 new 類名(參數a,b...),實際執行constructor構造方法,接收參數,實例化一個實例對象
  • 類的所有實例共享一個原型對象 類名.prototype
  • 繼承與覆蓋
class A {
    x=1;
    y(){}
    z(){console.log('a')}
}
class B{
    constructor(a){if(a){this.m=a;}}
    m=2;
    z(){console.log('b')}
}
let p= new B(9);//m值=9; 
p.z();//'b' 覆蓋了父類的z方法
let p1= new B();// m值=2

es5下的面向對象

  • 生成實例對象的傳統方法是通過構造函數 ES6 的class可以看作只是一個語法糖,它的絕大部分功能,ES5 都可以做到,
    新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法而已
function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 2);
  • ES6 的類,完全可以看作構造函數的另一種寫法。
class Point {
  // ...
}

typeof Point // "function" 類的數據類型就是函數
Point === Point.prototype.constructor // true 類本身就指向構造函數
  • 類有prototype和__proto__ ,對象實例只有__proto__
function Foo(){}
let p= new Foo();
/*
p.__proto__===>Foo.prototype(其__proto__===>Object.prototype(其__proto__===>null))
Foo.prototype,Object.prototype,Function.prototype都是由構造函數創建的
自定義構造方法的__proto__=>Function.prototype(其__proto__==>Object.prototype) 
見github 圖
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章