什么是class成员可见性?
ts中允许设置类的属性或者方法在类的外部是否可以访问。
public
public为类成员的默认可见性,被public修饰的成员可在class的内部和外部被访问,如
class Base {
public publicProperty = 'A Public Property'
}
const b = new Base()
console.log(b.publicProperty)
protected
当我们不想直接暴露类的属性,想让类属性在子类进行一定的逻辑计算,通过子类暴露。或者想让类属性只能在同一子类内部访问时,可以使用protected关键字,如
class Base {
protected pp = 'A protected property';
}
class DrivedClass extends Base {
getPP(){
return this.pp
}
}
const b = new Base()
console.log(b.pp) //Property 'pp' is protected and only accessible within class 'Base' and its subclasses.
const d = new DrivedClass();
console.log(d.pp); // Property 'pp' is protected and only accessible within class 'Base' and its subclasses.
console.log(d.getPP()) // noError
这里的子类指的是同一个子类,比如想要子类2中直接访问子类1中的继承父类的protected成员是不行的,详细可通过“protected注意事项”理解。
protected注意事项(protected不允许跨层级访问)
与c++等语言一样,被protected修饰的成员无法跨层级被访问,即在子类1中,只能访问子类1中以及其实例的从父类继承的protected属性,而无法通过接受父类型的实例,来访问父类型的protected成员。如
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 = 10; //Property 'x' is protected and only accessible through an instance of class 'Derived2'. This is an instance of class 'Base'
}
getX(){
return this.x
}
}
const d2 = new Derived2()
const d21 = new Derived2()
console.log(d21.getX()) // 1
d2.f1(d21)
console.log(d21.getX()) // 10
在上面例子中f2方法想通过在Drived2中通过父类实例去访问实例的protected属性x是不被允许的。(不同的语言规定不同,Java则允许)
private
被private修饰的成员只允许在类的内部访问,子类也不具备访问性。如
class Base {
private pp = 'private property'
}
class DerivedClass extends Base{
getPP(){
console.log(this.pp)//Property 'pp' is private and only accessible within class 'Base'.
}
}
const b = new Base()
console.log(b.pp)//Property 'pp' is private and only accessible within class 'Base'.
private允许跨实例被访问
ts允许被priavte修饰的类成员在同一类中的不同实例中被访问(不同语言规定不同,Ruby则不允许),如
class Base {
private pp = 'private property'
getDInstancePP(dBase: Base){
console.log(dBase.pp) //no error
}
}
const b1 = new Base()
const b2 = new Base()
console.log(b1.getDInstancePP(b2))
priavte protected注意事项
- 在ts中private protected只是提供编译时的类型检查,编译后的结果并不受影响,如:
class Base {
private pp = 'private property'
}
console.log(new Base().pp) //Property 'pp' is private and only accessible within class 'Base'.
console.log(new Base()['pp']) // no error
假如无视报错,第一个console.log编译成js后还是会输出'private property'
- priavte在编译时期具备“逃生窗口”,即用中括号的形式访问private成员不会报错,如上例中第二个console.log不会报错。
static
被static关键字修饰的成员与具体的实例无关,它可以通过"类名.成员名"来访问,如:
class Base {
static pp = 'stiac pp'
static printPP(){
console.log(Base.pp)
}
}
console.log(Base.pp)//"stiac pp"
Base.printPP()//"stiac pp"
static同样可以被public private protected修饰,且能够被继承
class MyClass {
private static x = 0;
protected static pp = 'pp'
}
class DMyclass extends MyClass{
someMethod(){
console.log(MyClass.pp)
}
}
console.log(MyClass.x);//Property 'x' is private and only accessible within class 'MyClass'.
new DMyclass().someMethod()
特殊的staitc成员名称不可取,即所有属于Function.prototype的属性名都不可取,如
console.log(Object.getOwnPropertyNames(Function.prototype))
['length', 'name', 'arguments', 'caller', 'constructor', 'apply', 'bind', 'call', 'toString']
原因
class本身就是Function而static实现其实是通过Function名.static成员名来实现的,如
class MyClass{ static sp = 'sp'} 转换成js为 MyClass{} MyClass.sp = 'sp'
console.log(typeof MyClass) //function
此时Myclass会从Function.prototype继承 ['length', 'name', 'arguments', 'caller', 'constructor', 'apply', 'bind', 'call', 'toString']等属性。我们知道覆写Function.prototype上的属性是不被允许的,如在js中
class MyClass {
static sp = 'static property'
}
console.log(MyClass.name)// MyClass
MyClass.name = 'abc'
console.log(MyClass.name)// MyClass
可以见到我们修改Function.prototype上的属性是无效的,而假如允许class修改被static修饰的与Function.prototype对象上的属性名同名的属性,实际上也是在做无用功。
static不可以修饰类
原因是ts并不要求所有的代码都写在类里面,要实现静态类的功能直接书写方法或者对象更合适。如
static class MyClass { // static' modifier cannot appear on a module or namespace element.
sp = 'sp'
}
这个功能书写成对象更合适
const MyClass = {
sp: 'sp'
}
static代码块
static代码块指的是在class中被static修饰的代码片段,其随着类的加载被运行一次,如
class MyClass {
pp = 'pp'
constructor(){
console.log("constructor first?")
}
static {
console.log("static first?")
}
}
new MyClass()
new MyClass()
/**
* 控制台结果
* "static first?"
* "constructor first?"
* "constructor first?"
*/