[{"data":1,"prerenderedAt":323},["ShallowReactive",2],{"content:\u002F2023\u002Ftypescript\u002Fts-13":3,"surround:\u002F2023\u002Ftypescript\u002Fts-13":312},{"id":4,"title":5,"body":6,"categories":288,"date":291,"description":92,"draft":292,"extension":293,"image":294,"meta":295,"navigation":297,"path":298,"permalink":294,"published":294,"readingTime":299,"recommend":294,"references":294,"seo":304,"sitemap":305,"stem":308,"tags":309,"type":310,"updated":294,"__hash__":311},"content\u002Fposts\u002F2023\u002Ftypescript\u002Fts-13.md","面向对象之 class（下）",{"type":7,"value":8,"toc":278},"minimark",[9,13,27,36,48,62,74,78,85,95,118,128,134,140,143,149,153,160,166,169,175,181,184,208,211,232,238,248,259,263,266,272],[10,11,12],"h2",{"id":12},"四种成员可见性",[14,15,16,20,24,25],"p",{},[17,18,19],"strong",{},"public（类外可见）",[21,22,23],"code",{"code":23},"public"," 修饰的属性或方法是公有的，可以在任何地方被访问到，默认所有的属性和方法都是 ",[21,26,23],{"code":23},[14,28,29,32,35],{},[17,30,31],{},"private（类内可见）",[21,33,34],{"code":34},"private"," 修饰的属性或方法是私有的，不能在声明它的类的外部访问",[14,37,38,41,44,45,47],{},[17,39,40],{},"protected（子类可见）",[21,42,43],{"code":43},"protected"," 修饰的属性或方法是受保护的，它和 ",[21,46,34],{"code":34}," 类似，区别是它在子类中也是允许被访问的",[14,49,50,53,54,57,58,61],{},[17,51,52],{},"#var（真私有属性）","\n上面的都是 TS 的语法（访问修饰符），而 ",[21,55,56],{"code":56},"#var"," 是 JS 的语法，在属性名前面加上 ",[21,59,60],{"code":60},"#"," 即可做到真正的属性私有",[63,64,65],"blockquote",{},[14,66,67,68,70,71,73],{},"注意：由于 ",[21,69,34],{"code":34}," 是 TS 的语法，在类型被擦除后就没了；真正的私有属性得使用 ",[21,72,60],{"code":60}," 才能做到",[10,75,77],{"id":76},"static-属性与-static-block","static 属性与 static block",[14,79,80,81,84],{},"我们可以使用 ",[21,82,83],{"code":83},"static"," 来定义一个静态属性，静态属性只能通过类名来访问",[86,87,93],"pre",{"className":88,"code":90,"language":91,"meta":92},[89],"language-ts","class Dog {\n  static kind = \"狗\";\n\n  constructor() {\n    \u002F\u002F ...\n  }\n}\n\nconst dog = new Dog();\nconsole.log(dog.kind); \u002F\u002F undefined\nconsole.log(Dog.kind); \u002F\u002F \"狗\"\n","ts","",[21,94,90],{"__ignoreMap":92},[14,96,97,98,100,101,104,105,104,108,104,111,104,114,117],{},"注意：用 ",[21,99,83],{"code":83}," 声明的属性，其名称不能是 ",[21,102,103],{"code":103},"name","、",[21,106,107],{"code":107},"prototype",[21,109,110],{"code":110},"length",[21,112,113],{"code":113},"arguments",[21,115,116],{"code":116},"caller"," 其中之一",[119,120,122],"folding",{"title":121},"因为 js 中的类都是通过函数来模拟的",[14,123,124],{},[125,126],"img",{"alt":92,"src":127},"\u002Fimages\u002Ftypescript\u002Fts-13\u002Fts_13_01.png",[14,129,130,133],{},[21,131,132],{"code":132},"static block"," 主要用来初始化私有属性（类外部无法初始化私有属性）",[86,135,138],{"className":136,"code":137,"language":91,"meta":92},[89],"class Foo {\n  static #count = 0;\n  static {\n    const count = loadFromLocalStorage() || 0;\n    Foo.#count += count;\n  }\n  constructor() {\n    console.log(Foo.#count);\n  }\n}\n",[21,139,137],{"__ignoreMap":92},[10,141,142],{"id":142},"类与泛型",[86,144,147],{"className":145,"code":146,"language":91,"meta":92},[89],"class Hash\u003CK, V> {\n  map: Map\u003CK, V> = new Map();\n  set(key: K, value: V) {\n    this.map.set(key, value);\n  }\n  get(key: K) {\n    return this.map.get(key);\n  }\n}\n\nclass Hash\u003CK, V> extends Map\u003CK, V> {\n  destroy() {\n    this.clear();\n  }\n}\n",[21,148,146],{"__ignoreMap":92},[10,150,152],{"id":151},"class-表达式","class 表达式",[14,154,155,156,159],{},"将匿名的 ",[21,157,158],{"code":158},"class"," 赋值给一个变量",[86,161,164],{"className":162,"code":163,"language":91,"meta":92},[89],"const Rectangle = class {\n  constructor(public height: number, public width: number) {}\n  area() {\n    return this.height * this.width;\n  }\n};\nconst r = new Rectangle(100, 200);\n",[21,165,163],{"__ignoreMap":92},[10,167,168],{"id":168},"抽象类",[14,170,171,174],{},[21,172,173],{"code":173},"abstract"," 用于定义抽象类和其中的抽象方法",[86,176,179],{"className":177,"code":178,"language":91,"meta":92},[89],"abstract class Base {\n  abstract getName(): string;\n  printName() {\n    console.log('Hello, ' + this.getName());\n  }\n}\nconst b = new Base();\n\u002F\u002F            ^--- 报错：Cannot create an instance of an abstract class\n",[21,180,178],{"__ignoreMap":92},[14,182,183],{},"抽象类：",[185,186,187,195,198,205],"ul",{},[188,189,190,191,194],"li",{},"不能被直接实例化：",[21,192,193],{"code":193},"new Base()"," ❌ 会报错",[188,196,197],{},"必须通过子类继承实现",[188,199,200,201,204],{},"可以包含具体实现（如 ",[21,202,203],{"code":203},"printName()"," 方法）",[188,206,207],{},"可以定义抽象方法",[14,209,210],{},"抽象方法：",[185,212,213,223,229],{},[188,214,215,218,219,222],{},[17,216,217],{},"只有声明，没有实现","（没有方法体，比如 ",[21,220,221],{"code":221},"getName()","）",[188,224,225,228],{},[17,226,227],{},"强制子类必须实现","这些方法",[188,230,231],{},"定义核心接口，确保子类行为一致性",[86,233,236],{"className":234,"code":235,"language":91,"meta":92},[89],"abstract class Base {\n  abstract getName(): string;\n  printName() {\n    console.log('Hello, ' + this.getName());\n  }\n}\nclass Derived extends Base {\n  \u002F\u002F 强制实现 getName\n  getName() {\n    return 'world';\n  }\n}\nconst d = new Derived();\nd.printName();\n",[21,237,235],{"__ignoreMap":92},[14,239,240,241,244,245,247],{},"可以看出，抽象类是介于 ",[21,242,243],{"code":243},"interface"," 和 ",[21,246,158],{"code":158}," 之间的一种写法",[14,249,250,251,253,254,256,257],{},"如果一个 ",[21,252,158],{"code":158}," 中的属性全都是抽象属性，那么也可以直接把这个 ",[21,255,158],{"code":158}," 当作 ",[21,258,243],{"code":243},[10,260,262],{"id":261},"把类当作参数常用","把类当作参数（常用）",[14,264,265],{},"注意是把类作为参数，而不是把类的实例化对象作为参数",[86,267,270],{"className":268,"code":269,"language":91,"meta":92},[89],"class Person {\n  constructor(public name: string) {}\n  sayHi() {\n    console.log(`Hi, I am ${this.name}`);\n  }\n}\nfunction greet(constructor: typeof Person) {\n  const p = new constructor('ClariS');\n  p.sayHi();\n}\ngreet(Person); \u002F\u002F 不报错\ngreet(new Person('ClariS')); \u002F\u002F 报错\n",[21,271,269],{"__ignoreMap":92},[86,273,276],{"className":274,"code":275,"language":91,"meta":92},[89],"class Person {\n  constructor(public name: string) {}\n  sayHi() {\n    console.log(`Hi, I am ${this.name}`);\n  }\n}\nfunction greet(constructor: new (name: string) => Person) {\n  const p = new constructor('ClariS');\n  p.sayHi();\n}\ngreet(Person); \u002F\u002F 不报错\ngreet(new Person('ClariS')); \u002F\u002F 报错\n",[21,277,275],{"__ignoreMap":92},{"title":92,"searchDepth":279,"depth":279,"links":280},4,[281,283,284,285,286,287],{"id":12,"depth":282,"text":12},2,{"id":76,"depth":282,"text":77},{"id":142,"depth":282,"text":142},{"id":151,"depth":282,"text":152},{"id":168,"depth":282,"text":168},{"id":261,"depth":282,"text":262},[289,290],"学习笔记","TypeScript","2023-02-17",false,"md",null,{"comments":292,"slots":296},{},true,"\u002F2023\u002Ftypescript\u002Fts-13",{"text":300,"minutes":301,"time":302,"words":303},"4 min read",3.655,219300,731,{"title":5,"description":92},{"loc":298,"images":306},[307],{"loc":127},"posts\u002F2023\u002Ftypescript\u002Fts-13",[290,158],"tech","8kpYwcdi-fBSC-NjKrArXq-8ohLHdiNxTievO7rctmY",[313,318],{"title":314,"path":315,"stem":316,"date":317,"type":310,"children":-1},"面向对象之 class（上）","\u002F2023\u002Ftypescript\u002Fts-12","posts\u002F2023\u002Ftypescript\u002Fts-12","2023-02-16",{"title":319,"path":320,"stem":321,"date":322,"type":310,"children":-1},"浅尝类型体操","\u002F2023\u002Ftypescript\u002Fts-14","posts\u002F2023\u002Ftypescript\u002Fts-14","2023-02-22",1793699838422]