** class的super,有两种指向,在静态方法和构造函数,指向父类,在普通函数中,指向父类的prototype
**
### 5.8 抽象类
* 抽象描述一种抽象的概念,无法被实例化,只能被继承
* 无法创建抽象类的实例
* 抽象方法不能在抽象类中实现,只能在抽象类的具体子类中实现,而且必须实现
~~~
abstract class Animal3 {
name:string;
abstract speak();
}
class Cat extends Animal3{
speak(){
console.log('喵喵喵');
}
}
let cat = new Cat();
cat.speak();
~~~
| 访问控制修饰符 | private protected public |
| --- | --- |
| 只读属性 | readonly |
| 静态属性 | static |
| 抽象类、抽象方法 | abstract |
### 5.9 抽象类 vs 接口
* 不同类之间公有的属性或方法,可以抽象成一个接口(Interfaces)
* 而抽象类是供其他类继承的基类,抽象类不允许被实例化。抽象类中的抽象方法必须在子类中被实现
* 抽象类本质是一个无法被实例化的类,其中能够实现方法和初始化属性,而接口仅能够用于描述,既不提供方法的实现,也不为属性进行初始化
* 一个类可以继承一个类或抽象类,但可以实现(implements)多个接口
* 抽象类也可以实现接口
~~~
abstract class Animal5{
name:string;
constructor(name:string){
this.name = name;
}
abstract speak();
}
interface Flying{
fly()
}
class Duck extends Animal5 implements Flying{
speak(){
console.log('汪汪汪');
}
fly(){
console.log('我会飞');
}
}
let duck = new Duck('zhufeng');
duck.speak();
duck.fly();
~~~
### 5.10 抽象方法
* 抽象类和方法不包含具体实现,必须在子类中实现
* 抽象方法只能出现在抽象类中
~~~
abstract class Animal{
abstract speak():void;
}
class Dog extends Animal{
speak(){
console.log('小狗汪汪汪');
}
}
class Cat extends Animal{
speak(){
console.log('小猫喵喵喵');
}
}
let dog=new Dog();
let cat=new Cat();
dog.speak();
cat.speak();
~~~
### 5.11 重写(override) vs 重载(overload)
* 重写是指子类重写继承自父类中的方法
* 重载是指为同一个函数提供多个类型定义
~~~
class Cat6 extends Animal6{
speak(word:string):string{
return 'Cat:'+word;
}
}
let cat6 = new Cat6();
console.log(cat6.speak('hello'));
function double(val:number):number
function double(val:string):string
function double(val:any):any{
if(typeof val == 'number'){
return val *2;
}
return val + val;
}
let r = double(1);
console.log(r);
~~~
### 5.12 继承 vs 多态
* 继承(Inheritance)子类继承父类,子类除了拥有父类的所有特性外,还有一些更具体的特性
* 多态(Polymorphism)由继承而产生了相关的不同的类,对同一个方法可以有不同的响应
~~~
class Animal7{
speak(word:string):string{
return 'Animal: '+word;
}
}
class Cat7 extends Animal7{
speak(word:string):string{
return 'Cat:'+word;
}
}
class Dog7 extends Animal7{
speak(word:string):string{
return 'Dog:'+word;
}
}
let cat7 = new Cat7();
console.log(cat7.speak('hello'));
let dog7 = new Dog7();
console.log(dog7.speak('hello'));
~~~
## 6\. 接口
* 接口一方面可以在面向对象编程中表示为`行为的抽象`,另外可以用来描述`对象的形状`
* 接口就是把一些类中共有的属性和方法抽象出来,可以用来约束实现此接口的类
* 一个类可以继承另一个类并实现多个接口
* 接口像插件一样是用来增强类的,而抽象类是具体类的抽象概念
* 一个类可以实现多个接口,一个接口也可以被多个类实现,但一个类的可以有多个子类,但只能有一个父类
### 6.1 接口
* interface中可以用分号或者逗号分割每一项,也可以什么都不加
~~~
//接口可以用来描述`对象的形状`,少属性或者多属性都会报错
interface Speakable{
speak():void;
name?:string;//?表示可选属性
}
let speakman:Speakable = {
name:string;//多属性也会报错
speak(){}//少属性会报错
}
~~~
~~~
//接口可以在面向对象编程中表示为行为的抽象
interface Speakable{
speak():void;
}
interface Eatable{
eat():void
}
class Person5 implements Speakable,Eatable{
speak(){
console.log('Person5说话');
}
eat(){}
}
class TangDuck implements Speakable{
speak(){
console.log('TangDuck说话');
}
eat(){}
}
~~~
~~~
//无法预先知道有哪些新的属性的时候,可以使用 `[propName:string]:any`,propName名字是任意的
interface Person {
readonly id: number;
name: string;
[propName: string]: any;
}
let p1 = {
id:1,
name:'zhufeng',
age:10
}
~~~
### 6.2 接口的继承
* 一个接口可以继承自另外一个接口
~~~
interface Speakable{
speak():void
}
interface SpeakChinese extends Speakable{
speakChinese():void
}
class Person5 implements SpeakChinese{
speak(){
console.log('Person5')
}
speakChinese(){
console.log('speakChinese')
}
}
~~~
### 6.3 readonly
* 用 readonly 定义只读属性可以避免由于多人协作或者项目较为复杂等因素造成对象的值被重写
~~~
interface Person{
readonly id:number;
name:string
}
let tom:Person = {
id :1,
name:'zhufeng'
}
tom.id = 1;
~~~
### 6.4 函数类型接口
* 对方法传入的参数和返回值进行约束
~~~
interface discount{
(price:number):number
}
let cost:discount = function(price:number):number{
return price * .8;
}
~~~
### 6.5 可索引接口
* 对数组和对象进行约束
* userInterface 表示:只要 index 的类型是 number,那么值的类型必须是 string
* UserInterface2 表示:只要 index 的类型是 string,那么值的类型必须是 string
~~~
interface UserInterface {
[index:number]:string
}
let arr:UserInterface = ['zfpx1','zfpx2'];
console.log(arr);
interface UserInterface2 {
[index:string]:string
}
let obj:UserInterface2 = {name:'zhufeng'};
~~~
### 6.6 类接口
* 对类的约束
~~~
interface Speakable{
name:string;
speak(words:string):void
}
class Dog implements Speakable{
name:string;
speak(words){
console.log(words);
}
}
let dog=new Dog();
dog.speak('汪汪汪');
~~~
## 7\. 泛型
* 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
* 泛型`T`作用域只限于函数内部使用
### 7.1 泛型函数
* 首先,我们来实现一个函数 createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值
~~~
function createArray(length: number, value: any): Array<any> {
let result: any = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result = createArray(3,'x');
console.log(result);
~~~
~~~
function createArray(length: number, value: any): Array<any> {
let result: any = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result = createArray(3,'x');
console.log(result);
function createArray2<T>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result2 = createArray2<string>(3,'x');
console.log(result);
~~~
### 7.2 类数组
* 类数组(Array-like Object)不是数组类型,比如`arguments`
~~~
function sum(...parameters:number[]){
let args:IArguments = arguments;
for(let i=0;i<args.length;i++){
console.log(args[i]);
}
}
sum(1,2,3);
let root = document.getElementById('root');
let children:HTMLCollection = root.children;
children.length;
let nodeList:NodeList = root.childNodes;
nodeList.length;
~~~
### 7.3 泛型类
~~~
class MyArray<T>{
private list:T[]=[];
add(value:T) {
this.list.push(value);
}
getMax():T {
let result=this.list[0];
for (let i=0;i<this.list.length;i++){
if (this.list[i]>result) {
result=this.list[i];
}
}
return result;
}
}
let arr=new MyArray();
arr.add(1); arr.add(2); arr.add(3);
let ret = arr.getMax();
console.log(ret);
~~~
### 7.5 泛型接口
* 泛型接口可以用来约束函数
~~~
interface Calculate{
<T>(a:T,b:T):T
}
let add:Calculate = function<T>(a:T,b:T){
return a;
}
add<number>(1,2);
~~~
### 7.6 多个类型参数
* 泛型可以有多个
~~~
function swap<A,B>(tuple:[A,B]):[B,A]{
return [tuple[1],tuple[0]];
}
let swapped = swap<string,number>(['a',1]);
console.log(swapped);
console.log(swapped[0].toFixed(2));
console.log(swapped[1].length);
~~~
### 7.7 默认泛型类型
~~~
function createArray3<T=number>(length: number, value: T): Array<T> {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result2 = createArray3(3,'x');
console.log(result2);
~~~
### 7.8 泛型约束
* 在函数中使用泛型的时候,由于预先并不知道泛型的类型,所以不能随意访问相应类型的属性或方法。
~~~
function logger<T>(val:T){
console.log(val.length)
}
interface LengthWise{
length:number
}
//可以让泛型继承一个接口
function logger2<T extends LengthWise>(val:T){
console.log(val.length)
}
logger2(1);
logger2('zhufeng');
~~~
### 7.9 泛型接口
* 定义接口的时候也可以指定泛型
~~~
interface Cart<T>{
list:T[]
}
let cart:Cart<{name:string,price:number}> = {
list:[{name:'zhufeng',price:10}]
}
console.log(cart.list[0].name,cart.list[0].price);
~~~
### 7.10 泛型类型别名
* 泛型类型别名可以表达更复杂的类型
~~~
type Cart<T> = {list:T[]} | T[];
let c1:Cart<string> = {list:['1']};
let c2:Cart<number> = [1];
~~~
### 7.11 泛型接口 vs 泛型类型别名
* 接口创建了一个新的名字,它可以在其他任意地方被调用。而类型别名并不创建新的名字,例如报错信息就不会使用别名
* 类型别名不能被 extends和 implements,这时我们应该尽量使用接口代替类型别名
* 当我们需要使用联合类型或者元组类型的时候,类型别名会更合适
~~~
//为什么会有泛型,它的意义在哪里
import React from 'react';
namespace a {
//定义函数 类
function createArray<T>(length: number, value: T): Array<T> {
let result: Array<T> = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
let result = createArray<number>(3, 3);
console.log(result);
let result2 = createArray<string>(3, 'x');//就相当 于一个参数
console.log(result2);
//类数组 ArrayLike arguments
function sum(...args2: any[]) {
let args: IArguments = arguments;
for (let i = 0; i < args.length; i++) {
console.log(args[i]);
}
}
sum(1, 2, '3', 4);
//ReferenceError: document is not defined
/* let root: HTMLElement | null = document.getElementById('root');
let children: HTMLCollection = root!.children;
let childNodes: NodeListOf<ChildNode> = root!.childNodes; */
class MyArray<T>{
private list: T[] = [];
add(val: T) {
this.list.push(val);
}
getMax(): T {
let result: T = this.list[0];
for (let i = 1; i < this.list.length; i++) {
if (this.list[i] > result) {
result = this.list[i];
}
}
return result;
}
}
let arr = new MyArray<number>();
arr.add(1); arr.add(2); arr.add(3);
let result3: number = arr.getMax();
console.log(result3);
//接口泛型
/* interface Calculate<T> {
(a: T, b: T): T
t?: T
}
let add: Calculate<string> = function (a: string, b: string) {
return a;
} */
interface Calculate {
<T>(a: T, b: T): T
}
let add: Calculate = function (a, b) {
return a;
}
let result4 = add(2, 2);
//console.log(result4);
//多个类型参数 如何在不增加中间变量的情况下,交换二个变量的值
function swap<A, B>(tuple: [A, B]): [B, A] {
return [tuple[1], tuple[0]];
}
let result5 = swap<string, number>(['zhufeng', 10]);
console.log(result5);//[10,'zhufeng']
//let a = 1, b = 2;
//[b, a] = [a, b];
// 默认泛型类型
function createArray2<T = string>(length: number): T | null {
let t: T | null = null;
return t;
}
let result6 = createArray2<boolean>(3);
//泛型的约束
//在函数中使用泛型的时候,由于预先并不知道具体的类型,所以不能访问相应类型的方法
interface LengthWise {
length: number
}
function logger<T extends LengthWise>(val: T) {
console.log(val.length);
}
logger('zhufeng');
interface Cart<T> {
list: T[]
}
let cart: Cart<string> = {
list: ['1', '2', '3']
}
// 泛型类型别名
type Cart2<T> = { list: T[] } | T[];
let c1: Cart2<string> = { list: ['1'] };
let c2: Cart2<string> = ['1']
//interface 定义一个实实在在的接口,它是一个真正的类型
//type一般用来定义别名,并不是一真正的类型
}
~~~
- 文档简介
- 基础面试题【珠峰2019.8】
- P01_call,aplly区别
- P02_综合面试题讲解2-2
- P03_箭头函数和普通函数区别-综合面试题讲解2-3
- P05_实现indexOf
- P06_综合面试题讲解2-6
- P07_URL解析题
- P08_原型题
- P09_图片延时加载
- P10_正则-包含数字字母下划线
- P11_综合面试题讲解2-11
- P12_英文字母加空格
- P13_数组扁平化并去重
- P14_模拟实现new
- P15_合并数组
- P16_定时器,打印012345
- P17_匿名函数输出值问题
- P18_a在什么情况下打印输出+1+1+1
- P19_对数组的理解
- P20_冒泡排序
- P21_插入排序
- P22_快速排序
- P23_销售额存在对象中
- P24_求数组的交集
- P25_旋转数组
- P26_ [函数柯理化思想]
- P27_ [柯理化函数的递归]
- 网络协议【珠峰2019.6】
- TypeScript+Axios入门+实战【珠峰2019.11】
- 1.数据结构
- 2.函数和继承
- 3.装饰器
- 4.抽象类-接口-泛型
- 05-结构类型系统和类型保护
- 06-类型变换
- AST-抽象语法树
- React性能优化【珠峰2019.10】
- 1-react性能优化
- 2-react性能优化
- 3.react-immutable
- React Hooks【珠峰2019.12】
- 前端框架及项目面试
- 第07章 React 使用
- 7-1 React使用-考点串讲
- 7-2 JSX基本知识点串讲
- 7-3 JSX如何判断条件和渲染列表
- 7-4 React事件为何bind this
- 7-5 React事件和DOM事件的区别
- 7-6 React表单知识点串讲
- 7-7 React父子组件通讯
- 7-8 setState为何使用不可变值
- 7-9 setState是同步还是异步
- 7-10 setState合适会合并state
- 7-11 React组件生命周期
- 7-12 React基本使用-知识点总结和复习
- 7-13 React函数组件和class组件有何区别
- 7-14 什么是React非受控组件
- 7-15 什么场景需要用React Portals
- 7-16 是否用过React Context
- 7-17 React如何异步加载组件
- 7-18 React性能优化-SCU的核心问题在哪里
- 7-19 React性能优化-SCU默认返回什么
- 7-20 React性能优化-SCU一定要配合不可变值
- 7-21 React性能优化-PureComponent和memo
- 7-22 React性能优化-了解immutable.js
- 7-23 什么是React高阶组件
- 7-24 什么是React Render Props
- 7-25 React高级特性考点总结
- 7-26 Redux考点串讲
- 7-27 描述Redux单项数据流
- 7-28 串讲react-redux知识点
- 7-29 Redux action如何处理异步
- 7-30 简述Redux中间件原理
- 7-31 串讲react-router知识点
- 7-32 React使用-考点总结
- 第08章 React 原理
- 8-1 React原理-考点串讲
- 8-2 再次回顾不可变值
- 8-3 vdom和diff是实现React的核心技术
- 8-4 JSX本质是什么
- 8-5 说一下React的合成事件机制
- 8-6 说一下React的batchUpdate机制
- 8-7 简述React事务机制
- 8-8 说一下React组件渲染和更新的过程
- 8-9 React-fiber如何优化性能
- 第09章 React 面试真题演练
- 9-1 React真题演练-1-组件之间如何通讯
- 9-2 React真题演练-2-ajax应该放在哪个生命周期
- 9-3 React真题演练-3-组件公共逻辑如何抽离
- 9-4 React真题演练-4-React常见性能优化方式
- 9-5 React真题演练-5-React和Vue的区别
- 第10章 webpack 和 babel
- 10-1 webpack考点梳理
- 10-2 webpack基本配置串讲(上)
- 10-3 webpack基本配置串讲(下)
- 10-4 webpack如何配置多入口
- 10-5 webpack如何抽离压缩css文件
- 10-6 webpack如何抽离公共代码和第三方代码
- 10-7 webpack如何实现异步加载JS
- 10-8 module chunk bundle 的区别
- 10-9 webpack优化构建速度-知识点串讲
- 10-11 happyPack是什么
- 10-12 webpack如何配置热更新
- 10-13 何时使用DllPlugin
- 10-14 webpack优化构建速度-考点总结和复习
- 10-15 webpack优化产出代码-考点串讲
- 10-16 什么是Tree-Shaking
- 10-17 ES Module 和 Commonjs 的区别
- 10-18 什么是Scope Hostin
- 10-19 babel基本概念串讲
- 10-20 babel-polyfill是什么
- 10-21 babel-polyfill如何按需引入
- 10-22 babel-runtime是什么
- 10-23 webpack考点总结和复习
- 10-24 webpack面试真题-前端代码为何要打包
- 10-25 webpack面试真题-为何Proxy不能被Polyfill
- 10-26 webpack面试真题-常见性能优化方法