前端总结

89 阅读10分钟

一、Html

二、Css

三、Js

2、Es6相关

1、数组解构、...展开运算符的原理

let [a,b,c] = [1,2,3]
let z = [...arr]

调用数组的iterator迭代器遍历原数组,通过生成器for of生成新数组

对象没有iterator 生成器for of不能遍历的遍历对象 遍历对象用for in

2、Proxy

proxy Es6新增的类,用于创建一个代理对象,原对象的操作由代理对象完成

const obj = {
    name:'cj',
    age:18
}
const objProxy = new Proxy(obj,{})

参数1 需求代理的对象 参数2 包含回调函数的对象

const objProxy = new Proxy(obj,{
    //get操作符
    get:function(target,key){
        console.log(`监听到访问${key}属性`,target)
        return target[key]    //返回访问属性的值
    },
    //set操作符
    set:function(target,key,newValue){
        console.log(`监听到给${key}属性设置值`,target)
        tarset[key] = newValue    //将属性最新值,赋值给代理对象属性
    }
    //has操作符
    has:function(target,key){
        console.log(`监听到使用in操作符${key}`,target)
        return key in target
    }
    //delete操作符
    deleteProperty:function(){
        console.log(`监听到使用delete操作符${key}`,target)
        delete target[key]    
    }
})
 
console.log(objProxy.name)
console.log(objProxy.age)
 
objProxy.name = 'wx'
objProxy.age = 20
 
//in操作符
console.log('name' in objProxy)  //true
//delete操作符
delete objProxy.name

Object.defineProperty直接监听对象的属性,proxy是监听整个代理对象

四、Ts

1、Ts数据类型

1、基础类型

字符串类型

 let a:string='string'

number类型

let num:number= 1

布尔类型

let boolean:boolean=true

空值类型

void 表示没有任何返回值的函数
void 也可以定义undefined和null

function voidFn (): void 
    {console.log('test void')}
    
let u: void = undefined

let n: void = null

null、undefined类型

let u: undefined = undefined
let n: null = null

void、null、undefined的区别 null、undefined 可以分配给其他类型 void不能

2、任意类型

any类型、unknown类型

1、any类型为没有指定类型、可以改变的类型,不需要检查类型

2、声明变量时没有指定类型默认为any类型

3、缺点any类型失去Ts类型检查作用

4、Ts3.0中引入unknown类型,可以分配给任意类型,比any类型更安全、更严格

any和unknown的区别 1、unknown类型声明的变量不能赋值给其他类型非any类型的变量

// 不可以
let names:unknown = '123'
let names2:string = names
// 可以
let bbb:unknown = '123'
let aaa:any= '456'

2、any类型定义的对象访问不存在的属性和方法时不会报错,unknown类型不能

// 不会报错
let obj:any = {b:1}
obj.a

// 会报错
let obj:unknown = {b:1,ccc:():number=>213}
obj.b
obj.ccc()

3、对象类型(接口 interface)

用interface关键字声明一个满足所有数据类型的集合来定义对象

interface Rule {
    a?:number,
    readonly b:string,   
    [propName: string]: any,
    fun:()=>void
  
 }
 
 const example:Rule = {
    a:123,
    b:'123',
    fun:()=>{
    console.log('123')
    }
 }

1、相同名称的interface会被合并一个

2、example对象中的数据要与interface定义的类型、数量一致

(1)、可用?可选链操作符定义interface兼容

(2)、可以添加任意属性 [propName: string]: any

3、定义readonly只读属性 只能被读取 不能修改和重新赋值

4、可以定义函数

4、数组类型

1、类型[]

let arr:number[] = [1, 2, 3]; //数字类型的数组
let arr:string[] = ["1", "2"]; //字符串类型的数组
let arr:any[] = [1, "2", true]; //任意类型的数组
let arr:any[][] = [[1,2], ['3','4'],[true,false]]; //任意类型的数组

数组内不能存在非对应类型的数据

2、数组泛型 Aray[类型]

let arr:Array<number> = [1,2,3,4,5]
let arr:Array<string> = ['1','2','3','4','5']

业务接口数组对象数据常用写法

interface Item {
    age: number,
    name: string
} 
const array: Array<Item> = [
     { age: 123, name: "1" },
     { age: 123, name: "2" },
     { age: 123, name: "3" }
]

5、元组(Tuple)

元组为数组的变种,数量相同、类型不同的元素的集合

let arr:readonly[number,srting,boolean,any]=[1,'2',true,3]

6、枚举

使用enum关键字定义枚举 1、数字枚举

enum colors{
   Red=1
   Green
   Yellow
}

默认从0开始,依次递增,给默认值后续从默认值开始递增、

2、字符串枚举

enum colors{
   Red='red'
   Green='green'
   Blue='blue'
}
colors[Red]

字符串枚举没有自增行为,可以很好的序列化

3、异构枚举

enum colors{
    red=1
    green='1'
}

异构枚举可以包含各种不同类型

7、never类型

never类型标识不应该存在的状态 常用于报错的处理

function err (message:string):never {
      throw new Errow (message) 
}

never void的区别 1、void类型是定义函数返回值为空 never定义的抛出错误没有返回值

2、联合类型中never会被移除

type A = string | void | never // 不会显示never

8、symbol类型

symbol类型是通过Symbol构造函数创建的唯一值,只支持string和number类型的传参

2、Ts在函数中的拓展

 const fn = (name: string, age?:number=1): string => {
  return name + age
  }
 fn('张三',18)

1、参数、默认值、函数的返回值要与限制类型的相同

2、可用?兼容可能不存在的参数

3、类型断言、联合类型、交叉类型

1、联合类型

// 可以
let a:string | number='1'
let a:string | number= 1
// 不可以
let a:string | number= true

2、交叉类型 多种类型的集合,联合对象具有所有联合类型的所有属性

interface People {
  age: number,
  height: number
}
interface Man{
  sex: string
}
const xiaoman = (man: People & Man) => {
  console.log(man.age)
  console.log(man.height)
  console.log(man.sex)
}
xiaoman({age: 18,height: 180,sex: 'male'});

3、类型断言

语法

interface A {
       run: string
}
 
interface B {
       build: string
}
 
const fn = (type: A | B): string => {
       return (type as A).run
       return <A>type.run
}

类型断言只能跳过Ts编译器,无法避免错误

4、class类的定义

class Person {
    public name:string
    private age:number
    protected some:any = 0
    static staus:any
     constructor (name:string,age:number){
     this.name = name
     this.age = age
     this.any=any
     }
 
}

1、定义了变量但未使用会报错,声明的时候给默认值或赋值

2、类的修饰符

(1)public 定义的变量内外部都可以访问 默认public

(2)private 定义的变量为私有 只能在内部访问不能在外部访问

(3)protected 定义的变量为私有 只能在内部或在继承的子类中访问

(4)static 定义的变量和函数只能用类名调用,不能通过this调用

5、类型推论、类型别名

1、类型推论

变量声明后未定义类型 Ts会自动推测出一个类型,不能再赋值给其他类型

2、类型别名

type关键字 可以给一个类型定义一个名字 多用于复合类型

   type value = boolean | 0 | '213' 
   let s:value = true

类型别名type,接口interface的区别

1、interface可以继承,重名可以自动合并,type不可以

2、type可以定义联合、交叉类型,interface不可以

6、泛型

1、函数泛型

function Add<T>(a: T, b: T): Array<T>  {
    return [a,b]
}
 
Add<number>(1,2)
Add<string>('1','2')

函数名后面加 <参数>

2、接口定义泛型

interface MyInter<T> {
   (arg: T): T
}
 
function fn<T>(arg: T): T {
   return arg
}
 
let result: MyInter<number> = fn
 
result(123)

声明接口的时候 在名字后面加一个<参数> 使用的时候传递类型

3、泛型约束

interface Len {
   length:number
}
 
function getLegnth<T extends Len>(arg:T) {
  return arg.length
}
 
getLegnth<string>('123')

约束其为具有length属性的类型,这里我们会用到interface

7、Tsconfig.js文件

通过tsc --init命令生成tsconfig.json文件

常用选择项

1.include 指定编译文件默认是编译当前目录下所有的ts文件

2.exclude 指定排除的文件

3.target 指定编译js 的版本例如es5  es6

4.allowJS 是否允许编译js文件

5.removeComments 是否在编译过程中删除文件中的注释

6.rootDir 编译文件的目录

7.outDir 输出的目录

8.sourceMap 代码源文件

9.strict 严格模式

10.module 默认common.js 可选es6模式 amd umd 等

8、命名空间(namespace)

  • 内部模块,主要用于组织代码,避免命名冲突。
  • 命名空间内的类默认私有
  • 通过 export 暴露
  • 通过 namespace 关键字定义
namespace a {
    export const Time: number = 1000
    export const fn = <T>(arg: T): T => {
        return arg
    }
    fn(Time)
}
 
 
namespace b {
     export const Time: number = 1000
     export const fn = <T>(arg: T): T => {
        return arg
    }
    fn(Time)
}
 
a.Time
b.Time

9、Ts内置工具

Partial、Required、Pick、Record、Readonly

  • Partial 将所有属性变为可选
type Partial<T> = {
  [P in keyof T]?: T[P];
  };
  • Required 将所有属性变为必选
  • Pick 从类型定义T的属性中,选取指定一组属性,返回一个新的类型定义
  type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};
  • Readonly 将所有属性变为只读属性
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};
  • Record 生产一个新的属性为K,类型为T的类型集合
  type Record<K extends keyof any, T> = {
  [P in K]: T;
  };

五、Vue

1、Vue2和Vue3的区别

语法区别

  • template编译模版中可以写多个节点
  • setup语法糖模式 包含了vue2的beforecreate和created生命周期
  • 组合式Api,数据逻辑写在一起,需要用到的import引入
  • 数据双向绑定用ref和reactive代替原data定义
  • 生命周期函数名称改变前面+on
  • 新增了watchEffect高级监听器

源码区别

  • 数据绑定用Es6的Proxy代理替换了Object.defineProperty监听数据改变
  • diff算法优化了最长增加递增子序列算法

2、Vue3 ref和reactive的区别

  • ref支持所有类型,reactive只支持引用类型 object、array
  • ref取值、赋值要加.value reactive不需要
  • reactive是Proxy代理的一个对象不能直接赋值,会破坏响应式

六、React

七、Webpack

1、为什么要用打包工具

  • 开发中使用的框架、css预处理、高级语法浏览器无法识别,必须要经过编译才能识别
  • 打包工具能压缩代码,兼容处理,提升性能
  • webpack生产环境会压缩代码 开发环境不会

2、webpack五大模块

1、entry(入口)

从那个文件作为入口开始打包

  entry: "./src/main.js", // 相对路径

2、output(输出)

打包完成的文件输出到哪里

 output: {
    path: path.resolve(__dirname, "dist"), // 输出文件路径
    filename: "static/js/main.js", // 输出文件名
    clean: true, // 打包前清空dist目录
  }

3、loader(加载器)

借助loader解析其他非js、json格式文件

  module: {
    // loader的配置
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"], // 处理cssloader 从后往前解析
      },
      // webpack5 内置图片处理
      {
        test: /\{png|jpe?g|gif|webp}$/,
        type: 'asset',
        parser:{
        dataUrlCondition:{
             maxSize:10*1024 // 小于10kb的图片转base64 减少服务器请求 但体积会变大
          },
        generator: {
            filename: "static/images/[hash:10][ext][query]",
          } // 处理图片保存路径
        }
      }
    ],
  },

常用loader

  • css-loader less-loader sass-loader 处理css文件
  • file-loader url-loader 处理图片资源 webpack5 已内置不用单独配置
  • eslint-loader babel-loader 处理代码格式 es6高级语法兼容

4、plugins(插件)

扩展webpack其他功能

常用plugins

  • HtmlWebpackPlugin 生成一个html文件 自动引入外部资源
  • EslintWebpackPlugin 对代码进行格式校验
  • IgnorePlugin 处理不需要引入的模块
  • MiniCssExtractPlugin link引入css样式 阻止图片闪屏
  • CssMinimizerWebpackPlugin css文件压缩插件

5、mode(模式)

  • 开发模式 development
  • 生产模式 production

3、devServer

webpack配置 devServer 启动代理服务 可配置proxy处理开发跨域问题

  devServer: {
    host: "localhost", // 启动服务器域名
    port: "3000", //  启动服务器端口
    open: "true",
    // 配置代理 处理跨域问题
    proxy: {
      '/insurance': {
          target: 'http://www.baidu.com',
          changeOrigin: true,
          pathRewrite: {
            'aaa': ''
           }
         }
       }
     },

八、Vite

九、NodeJs

十、NestJs

十一、微前端

十二、性能优化、前端安全

十三、设计模式

1、发布订阅模式

定义三个角色:发布者 订阅者 调度者

发布者发生变化后通知调度者变化,订阅者通过调度者的变化随之改变

  • on订阅/监听

  • emit 发布/注册

  • once 只执行一次

  • off解除绑定

interface EventFace {
    on: (name: string, callback: Function) => void,
    emit: (name: string, ...args: Array<any>) => void,
    off: (name: string, fn: Function) => void,
    once: (name: string, fn: Function) => void
}
 
interface List {
    [key: string]: Array<Function>,
}
class Dispatch implements EventFace {
    list: List
    constructor() {
        this.list = {}
    }
    on(name: string, callback: Function) {
        const callbackList: Array<Function> = this.list[name] || [];
        callbackList.push(callback)
        this.list[name] = callbackList
    }
    emit(name: string, ...args: Array<any>) {
        let evnetName = this.list[name]
        if (evnetName) {
            evnetName.forEach(fn => {
                fn.apply(this, args)
            })
        } else {
            console.error('该事件未监听');
        }
    }
    off(name: string, fn: Function) {
        let evnetName = this.list[name]
        if (evnetName && fn) {
            let index = evnetName.findIndex(fns => fns === fn)
            evnetName.splice(index, 1)
        } else {
            console.error('该事件未监听');
        }
    }
    once(name: string, fn: Function) {
        let decor = (...args: Array<any>) => {
            fn.apply(this, args)
            this.off(name, decor)
        }
        this.on(name, decor)
    }
}
const o = new Dispatch()
 
 
o.on('abc', (...arg: Array<any>) => {
    console.log(arg, 1);
})
 
o.once('abc', (...arg: Array<any>) => {
    console.log(arg, 'once');
})
// let fn = (...arg: Array<any>) => {
//     console.log(arg, 2);
// }
// o.on('abc', fn)
// o.on('ddd', (aaaa: string) => {
//     console.log(aaaa);
// })
//o.off('abc', fn)
 
o.emit('abc', 1, true, '小满')
 
o.emit('abc', 2, true, '小满')
 
// o.emit('ddd', 'addddddddd')