问题
- public, private, protected的用法和注意事项,适用场景
- 抽象对象的用法
- 接口的用法
- 抽象对象和接口的区别
修饰符
所谓在类的外部访问,也就是通过实例person.xxx的形式访问
public
private 不可读写
- 不能在类的外部访问,即不能通过person.name访问,能通过person.getName()方法访问
- 子类的内部、外部都不能访问
当构造函数修饰为
private时,该类不允许被继承或者实例化:protected
与private类似
- 不同的是可以在子类的内部访问,外部也不能访问
protected constructor 构造函数被标记为constructor,这个类不能被实例化,即不能new Person(),但是可以继承 class Employee extends Person
readonly 只读 (包括类与接口中)
-
super
子类的构造函数中用
super(name),调用父类的constructor;
子类的方法中,调用super.someExtendsFunc(),效果和this.someExtendsFunc()一样
参数属性
通过给构造函数参数添加一个访问限定符来声明,相当于把变量定义和在构造函数中初始化简写为一步。
class Animal {// 这里的name是构造函数参数// 声明了一个同名的私有属性constructor(private name: string) { }move(distanceInMeters: number) {console.log(`${this.name} moved ${distanceInMeters}m.`);}}
存取器
通过设置get, set,即使成员变量是public,也会限制在类的外部set(通过鉴证password等方法)。
首先,存取器要求你将编译器设置为输出ECMAScript 5或更高。 不支持降级到ECMAScript 3。 其次,只带有get不带有set的存取器自动被推断为readonly。
抽象类与接口的区别
- 门和警报的例子
- 抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类主要用来继承、复用。
继承是一个 “是不是”的关系,而 接口 实现则是 “有没有”的关系。接口主要用来约束行为。
抽象类
用来被继承,相当于建立一个类的模子,就像一个接口是建立一个对象的模子一个道理。
子类的构造函数中必须调用super()
- 子类中必须实现抽象类定义的抽象方法
- 抽象类中没有定义的方法,子类中无法实现
抽象方法的语法与接口方法相似,两者都是定义方法签名但不包含方法体- 不同于接口,抽象类可以包含成员的实现细节——即包含非抽象方法(包含方法体)。
抽象类中的
抽象方法不包含具体实现并且 必须 在派生类中实现abstract class Animal {abstract makeSound(): void;move(): void {console.log("roaming the earth...");}}
接口(java中)
接口中的变量会被隐式地指定为public static final变量(并且只能是public static final变量)。
- 方法会被隐式地指定为public abstract方法且只能是public abstract方法(用其他关键字),一般情况下不在接口中定义变量。
- 如果一个非抽象类遵循了某个接口,就必须实现该接口中的所有方法。
- Java8的interface新特性 新 interface 的方法可以用default 或 static修饰
类与接口
接口的两种模式:
- 对「对象的形状(Shape)」进行描述
- 类的一部分行为进行抽象
把不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口。这个接口相当于一个抽象类中的抽象方法。implements 实现
一个类可以实现1个、多个接口
接口继承接口
接口继承类(把类当做接口使用)
class Point {x: number;y: number;}interface Point3d extends Point {z: number;}let point3d: Point3d = {x: 1, y: 2, z: 3};
类与接口的使用
类
- 定义数据模型的话,不仅为了编辑器的智能提示和类型检查
- 可以直接new对应实例
-
接口
定义数据模型的话,大部分功能只是为了编辑器的智能提示和类型检查
-
创建对象
接口:对「对象的形状(Shape)」进行描述
- 类:也可作为类型定义
- 使用接口
declare class和interface的区别
declare class语法实际上是用于为未在TypeScript中编写的外部代码添加类型定义 - 因此实现在其他地方
例如jQuery等插件,不是本身这个项目使用,而是引用他的地方使用
接口interface和type的区别
typescript 中的 interface 和 type 到底有什么区别
个人认为两种场景可能会使用到type而不能用interface:我的评论
组合与继承
组合优于继承的例子,鸭子
java继承和组合的区别,看两个例子,你就明白了
template method 模板方法
Practice
let bookTags: string[] = ['畅销', '经典', '必读'];let bookGrades: Array < number > = [1, 2, 3, 4, 5];// 接口:对「对象的形状(Shape)」进行描述interface Production {// 对象中只读readonly name: string,author: string,category: string,edition ? : string;repertery ? : number | boolean;[propName: string]: any;}class Library {// 静态私有属性private static language = 'Chinese';private buildingHeight: number = 18;// 参数属性constructor(private name: string,private address: string,) {}getName(): string {return this.name;}getAddress(): string {return this.address;}// getterget generation(): number {return this.generation;}// setterset generation(value: number) {console.log('generation is updated');}}let createLibrary: () => void = () => {let library: Library = new Library('Deepdraw Library', 'ChengDu');// 内部访问private属性addressconsole.log("library's name: " + library.getAddress());// address为private属性,外部不能访问(读)console.log("library's address" + library.address);// address为private属性,外部不能访问(写)library.address = '成都';// 静态私有属性外部也不能访问console.log("library'S buildingHeight" + library.buildingHeight);// getter行为console.log(library.generation);// setter行为library.generation = 6;}class Book {readonly name: string;private author: string;protected category: string;static isBook(book: Book): boolean {return book instanceof Book;}constructor(private id: string,detail: Production) {this.name = detail.name;this.author = detail.author;this.category = detail.category;}getAuthor(): string {return this.author;}getCategory(): string {return this.category;}}class ITBook extends Book {static difficulty: number = 5;private buyer: string = 'software developer';private seller: string = '孔夫子';constructor(private sId: string, detail: Production) {// 调用父类的constructorsuper(sId, detail);}getParent() {// readyonly属性,子类的内部可以访问console.log(this.name);// private属性,子类的内部也不能访问console.log(this.id);// private属性,子类的内部也不能访问console.log(this.author);// protected属性,子类的内部可以访问console.log(this.category);}// names是父类的只读属性,子类继承后可以读// buyer, seller是子类的private属性,子类内部可以访问getWholeInfo(): string {return `${this.name} for ${this.buyer}, and the seller is ${this.seller}`;}}class JSBook extends ITBook {protected constructor(private ssId: string,detail: Production,private rate: number) {super(ssId, detail);}}function addCommonBook(): Book {let bookDetail: Production = {name: '鲁迅选集',author: '鲁迅',category: '文学',edition: '1900'}let book = new Book('01', bookDetail);// readonly属性name,可以读console.log("book name is" + book.name);// readonly属性name,不能写book.name = 'readonly属性name不能修改';// private属性author,内部可以访问console.log("book'category is: " + book.getAuthor());// protected属性category,内部可以访问console.log("book'category is: " + book.getCategory());// privatge, protected属性,外部不能访问console.log(book.author);console.log(book.category);return book;}function addITBook(): ITBook {let bookDetail = {name: '前端攻城狮',author: '严靖',category: '计算机'}let frontEndBook = new ITBook('001', bookDetail);// 静态公有属性,鉴别是否子类console.log('is instance of Book?', Book.isBook(frontEndBook));// buyer, seller, 子类的private属性,子类内部可以访问console.log("book's whole infomation: " + frontEndBook.getWholeInfo());// 检查子类的内部是否可以访问派生属性frontEndBook.getParent();return frontEndBook;}// 当构造函数修饰为 private 时,该类不允许被继承或者实例化:// 当构造函数修饰为 protected 时,该类只允许被继承function addJSBook(): void {let professionalJSBook = new JSBook();}interface BookKeyWords {(tag: string, rate: number): string;}let createBookCategory: BookKeyWords = (tag: string = '经典', rate?: number): string => {return tag + rate;}createLibrary();addCommonBook();addITBook();
