ES6 class 類的理解(一)

優勢

ES6 的類提供了幾點明顯的好處:html

兼容當前大量的代碼。
相對於構造器和構造器繼承,類使初學者更容易入門。
子類化在語言層面支持。
能夠子類化內置的構造器。
再也不須要繼承庫;框架之間的代碼變得更加輕便。
爲未來的高級特性奠基了基礎: traits (或者 mixins ), 不可變實例,等等。
使工具可以靜態分析代碼( IDE ,類型檢測器,代碼風格檢測器,等等)。git

缺點

ES6 類掩蓋了 JavaScript 繼承的本質;
類會禁錮你,由於強制性的 new。es6

傳統的類

function Point(x, y){
      this.x = x;
    this.y = y;
}
Point.prototype.toString = function(){
    return "(" + this.x + "," + this.y + ")";
}
const p = new Point(1,2);
console.log(p);//Point {x: 1, y: 2}
console.log(p.toString());//(1,2)

ES6的class寫法就至關於語法糖

上面代碼的改用class來寫github

class Points {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    toString(){
        return '(' + this.x + ',' + this.y + ')';            }
}
const ps = new Points(1, 2);
console.log(ps);//Points {x: 1, y: 2}
console.log(ps.toString());//(1,2)

ES6的類能夠看做構造函數的另外一種寫法bash

class Cty{
    //....
}
console.log(typeof Cty);//function
console.log(Cty === Cty.prototype.constructor);//true
//類的數據類型是函數,類自己就指向構造函數

使用的時候,也是直接對類使用new命令,跟構造函數的用法徹底一致框架

class Bar {
    doStuff(){
        console.log('stuff');
    }
}
const b =new Bar();
b.doStuff();//stuff

類的實例上面的方法,其實就是調用原型上的方法函數

class B {};
const BS = new B();
console.log(BS.constructor === B.prototype.constructor);//true

類與子類

class Poin{
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
    toString(){
        return `(${this.x},${this.y})`;
    }
}
class ColorPoin extends Poin{
    constructor(x,y,color){
        super(x,y);
        this.color = color;
    }
    toString(){
        return super.toString() + " in " + this. color;
    }
}
// 類型
console.log(typeof Poin);//function
//news實例
const cp = new ColorPoin(25,8,'green');
console.log(cp.toString());//(25,8) in green
console.log(cp instanceof ColorPoin);//true
console.log(cp instanceof Poin);//true
// instanceof測試構造函數的prototype屬性是否出如今對象的原型鏈中的任何位置

下面是一些方法:工具

Object.assign方法能夠很方便的一次像類添加多個方法

class ObjAssign {
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
}
Object.assign(ObjAssign.prototype,{
    toString(){
        console.log("string");
    },
    toValue(){
        console.log("value")
         }
})
const Obj = new ObjAssign('Bob',24);
console.log(Obj);
Obj.toString();//string
Obj.toValue();//value
console.log(Object.keys(ObjAssign.prototype));//["toString", "toValue"]
console.log(Object.getOwnPropertyNames(ObjAssign.prototype));// ["constructor", "toString", "toValue"]

類的實例

class Pott {
    constructor(x,y){
        this.x = x;
        this.y = y;
    }
    toString() {
        return '(' + this.x + ',' + this.y + ')';
    }
}
const pott = new Pott(2,3);
pott.toString();
console.log(pott.hasOwnProperty("x"));//true
console.log(pott.hasOwnProperty("y"));//true
console.log(pott.hasOwnProperty("toString"));//false
console.log(pott);
console.log(pott.__proto__);
console.log(pott.__proto__.hasOwnProperty("toString"));//true

const p1 = new Pott(2,3);
const p2 = new Pott(3,3);

console.log(p1.__proto__ === p2.__proto__);//true

p1.__proto__.printName = function(){
    return "Oops";
}
console.log(p1.printName());//Oops
console.log(p2.printName());//Oops
const p3 = new Pott(4,2);
console.log(p3.printName());//Oops

取值函數(getter)和存值函數(setter)

prop屬性有對應的存值函數和取值函數測試

class MyClass {
   constructor(){
        //...
    }
    get prop(){
        return 'getter';
    }
    set prop(value){
        console.log("setter:" + value);
    }
}
const inst = new MyClass();
inst.prop = 123;//setter: 123
console.log(inst.prop)//getter

存值函數和取值函數是設置在屬性的Descriptor對象上的

class CustomHTMLElement {
   constructor(element) {
        this.element = element;
    }

    get html() {
        return this.element.innerHTML;
    }

    set html(value) {
        this.element.innerHTML = value;
    }
}

const descriptor = Object.getOwnPropertyDescriptor(
    CustomHTMLElement.prototype, "html"
);

console.log("get" in descriptor)  // true
console.log("set" in descriptor)  // true

calss 表達式

const MyCl = class Me {
    getClassName() {
        return Me.name;
    }
}
const inMe = new MyCl();
console.log(inMe.getClassName());//Me  只在class內部有定義

person當即執行實例

const person = new class{
    constructor(name){
        this.name = name;
    }
    sayName(){
        console.log(this.name);
    }
}('張三');
person.sayName();//張三

class name 屬性

class Mine {
//...
}
console.log(Mine.name);//Mine

class this的指向問題

this.printName = this.printName.bind(this)綁定解決this

class Logger{
   constructor(){
        this.printName = this.printName.bind(this);
    }
    printName(name = 'there'){
        this.print(`Hello ${name}`);
    }
    print(text){
        console.log(text);
    }
}
const logger = new Logger();
const {printName} = logger;
printName();//Hello there

靜態方法static

若是在一個方法前,加上static關鍵字,就表示該方法不會被實例繼承,而是經過類來調用

class Foo{
    static classMethod() {
        return 'hello';
    }
}
console.log(Foo.classMethod());//Hello

const foo = new Foo();
// console.log(foo.classMethod())//foo.classMethod is not a function
class Fun {
   static bar(){
       this.baz();
   }
   static baz(){
       console.log('hello');
   }
   baz(){
       console.log('world');
   }
}
Fun.bar();//hello

父類靜態方法能夠被子類調用

class Func{
   static classMethod() {
        return 'hello';
    }
}
class Baa extends Func{
    static classMethod(){
        console.log(super.classMethod + ",too") ;
    }
}
Baa.classMethod();//hello,too

實例屬性的新寫法

class IncreasingCounter{
    // constructor(){
    //     this._count = 0;
    // }
    _count = 0;
    get value(){
        console.log('getting the current value');  
        return this._count;           
    }
    increment(){
        this._count++;
    }
}

new.target屬性

確保函數只能經過new命令調用

function PersonMan(name){
    if(new.target !== undefined){
        this.name = name;
    }else{
        throw new Error('必須使用new命令生成實例')
    }
}
function PersonWoman(name){
    if(new.target === PersonWoman){
        this.name = name;
    }else{
        throw new Error('必須使用new命令生成實例')
    }
}
const personman = new PersonMan('張三');
const personwoman = new PersonWoman('張三');
// const personwoman2 =  PersonWoman.call(PersonWoman,'張三');//報錯

內部調用new.target會返回當前的class

class Rectangle{
    constructor(length,width){
        console.log(new.target);
        console.log(new.target===Rectangle);
        this.length = length;
        this.width = width;
    }
}
const rectangle = new Rectangle(3,4);

子類繼承父類時,new.target會返回子類

class Rec{
   constructor(length,width){
        console.log(new.target);
        console.log(new.target===Rectangle);
        console.log(new.target===Square);
        this.length = length;
        this.width = width;
        //...
    }
}
class Square extends Rec{
    constructor(length,width){
        super(length,width);
    }
}
const squareA = new Square(3,6);//false/true

參考文章
探索ES6
ES6阮一峯

相關文章
相關標籤/搜索