** 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面試真題-常見性能優化方法