欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

类中成员的可见性(public,protected,private,static)

最编程 2024-07-14 18:52:17
...

什么是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注意事项

  1. 在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'

  1. 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?" 
 */

推荐阅读