TypeScript学习39

继承内置类型

从内置类型Array, Error, Map等类型继承稍微有点特殊,不过对于target是ES6/ES2015之上的版本,你可以不用考虑。

简单来说,对于这些类,你可能需要使用setPrototypeOf,或者__proto__来维护原型链。

class MsgError extends Error {
    constructor(m: string) {
        super(m);
        Object.setPrototypeOf(this, MsgError.prototype);
    }
    sayHello() {
        return "hello " + this.message;
    }
}

const err: MsgError = new MsgError('abc');
console.log(err.sayHello());


TypeScript学习39

不过现在一般目标代码ES6/ES2015都没有什么问题,所以这个问题基本可以忽略。

成员的可见性

TypeScript可以使用public/protected/private来控制成员变量或者方法的对外可见性。

Public

对外可见,也是默认的行为。这些方法或变量可以通过实例变量任意的访问。

class Greeter {
    public greet() {
        console.log("Hi!");
    }
}
const g: Greeter = new Greeter();
g.greet()


TypeScript学习39

因为public是默认行为,所以这里的public是可以不加的。

Protected

只有自己和子类可以访问。

class Greeter {
    protected greet() {
        console.log("Hi!");
    }
}

class NewGreeter extends Greeter {
    public newGreet() {
        this.greet();
        console.log("Hi in NewGreeter");
    }
}
const g: NewGreeter = new NewGreeter();
// g.greet()  // Error
g.newGreet();


TypeScript学习39

子类可以通过newGreet()调用父类的greet()方法,但是不能直接调用g.greet()。


暴露protected成员

子类可以通过重新定义,来暴露父类的protected成员。但是类型要保持兼容。

class Greeter {
    protected m = 10;
    protected greet() {
        console.log("Hi!");
    }
}

class NewGreeter extends Greeter {
    public m = 15;
    public newGreet() {
        this.greet();
        console.log("Hi in NewGreeter");
    }
}
const g: NewGreeter = new NewGreeter();
console.log(g.m);


TypeScript学习39

通常来说,这样的暴露protected成员是没有意义的。

由于public是默认行为,可以不加。所以这里更多的是要提醒,重新设置成员变量初值的时候要小心检查是否要加上protected,否则很容易就把原来的protected变量给暴露出来了。



跨继承访问protected变量

是否能够通过基类的引用来访问protected变量,在不同的语言里面有不同的行为。

在Java里面是合法的,但是在C#和C++里面是非法的。TypeScript参照的是C#和C++里面的方式,所以这样是非法的。

class Base {
    protected x: number = 1;
}

class Derived1 extends Base {
    protected x: number = 2;
}

class Derived2 extends Base {
    f1(other: Derived2) {
        other.x = 10;
    }
    f2(other: Base) {
        // other.x = 20; <-- Error
    }
}


TypeScript学习39

Private

Private很简单,就是除了自己,就算是子类也不能访问。

class Base {
    private x = 1;
}

class Derived extends Base {
    showX() {
        // console.log(this.x);  <-- Error, x cannot be accessed.
    }
}


TypeScript学习39

Derived类也是不能访问x变量的。


由于private成员对于子类也是不可见的,所以子类也不能重新定义可见性。

class Base {
    private x = 1;
}

class Derived extends Base {
    protected x = 5;
}


TypeScript学习39

编译阶段就报错了。


TypeScript学习39

跨实例访问private成员

TypeScript是允许跨实例访问private成员的。

class A {
    private x: number = 5;
    public sameAs(other: A) {
        return this.x === other.x;
    }
}


TypeScript学习39

缺陷

TypeScript的private,只用在编译期,运行期,private的标签就被完全移除了。所以一旦到了JavaScript的领域,就没有了这里的private。

因此,你可以通过中括号来访问private成员。

class A {
    private x: number = 5;
    public sameAs(other: A) {
        return this.x === other.x;
    }
}

const a: A = new A();
console.log(a['x']);


TypeScript学习39

这样是可以访问的。


JavaScript有定义使用”#”开头的成员是私有的,这个用法和TypeScript的private尽管含义差不多,但是不是一个东西。TypeScript的private在编译成JavaScript的时候,会被全部抹除。如果希望在JavaScript里面仍然有效,应该使用JavaScript的”#”成员。

发表评论
留言与评论(共有 0 条评论) “”
   
验证码:

相关文章

推荐文章