详细

前端知识大纲

一、面试环节设置

  • 一面/二面 测试基础知识(html js css,html5 ES6 css3)
  • 二面/三面 高级工程师问基本原理(深入,往往根据简历和个人介绍来发问)
  • 三面/四面 技术负责人/业务负责人 关注你的从业经历中,你推动了什么,改变了什么
  • 终面 hr具有一票否决权,关注面试人的沟通、性格、潜力等

注意:

社会招聘:考察知识、能力、经验(抽象能力,把控能力)

二、面试准备

  1. JD分析
  • 职位描述
  • 业务分析,实战模拟
  1. 前端技术栈
  • 源码分析
例如:vue源码
注意:可结合博客上的分析快速看
  • 前端框架
vue angular react会用三个中的一到两种就可以。
关于理论:对其中一个要有深度研究,找博客源码分析。
关于实战:遇到什么问题,怎么解决的要准备。
注意:nodeJs前提是要说好,说不好就不要提,除非面试官问,不要画蛇添足。
  1. 简历和自我介绍
    • 简历

      • 1.基本信息:姓名 年龄 手机 邮箱 籍贯
      • 2.教育背景:学历
      • 3.工作经历:时间 公司 岗位 项目背景 技术栈 职责 业绩
      • 4.开源项目和博客 github和开源项目说明,博客地址 注意:不要在简历中放自我评价
    • 自我陈述

      • 1.把握面试沟通方向(为面试官提问埋伏笔)
      • 2.豁达,自信,节奏适宜,适度发挥,务实谦虚 (面试中不存在标准答案,凡事不能太绝对) (不要因为自己比别人懂得多了一点而对面试官产生鄙视,那是玩火自焚)

三、一/二

目录

  • 页面布局
  • css盒模型
  • DOM事件
  • 原型链
  • 面向对象 & 类
  • http协议 & 跨域
  • 安全:XSS CSRF
  • 算法:没有标准

1. 页面布局

position相关属性
1. static 默认定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声明)
2. relative相对定位,不脱离文档流,相对于自身原本位置进行偏移
3. absolute 绝对定位,使元素完全脱离文档流,相对非static的父元素偏移(若其父元素没有定位则逐层上找,直到document——页面文档对象)
4.fixed 固定定位,相对浏览器窗口(视口,即正在浏览的文档的那一部分)进行定位(视口共包括三种:布局视口、视觉视口和理想视口)
5. sticky粘性定位,不脱离文档流,它的行为就像 position:relative; 而当页面滚动超出目标区域时,它的表现就像 position:fixed;,它会固定在目标位置。
浮动:脱离文档流
绝对定位:脱离文档流
flex:比较完美的布局方式
table:兼容性比较好
grid:兼容性不是很好,一般用100%比模拟,例如bootstrap的网格布局
- 动画的实现:
- dom变化 svg的path canvas(2d,3d) CSS3
- js相关 requestAnimationFrame
- css3 GPU加速(transform: translate3d(0,0,0),translateZ(0))
- web标准 ES6 CSS3 HTML5
- 模块化 ES6中如何处理模块化,CommonJS之间的模块化区别(AMD,CMD不表)
- 模板引擎 ejs undersocore vue lodash.js
- css动态语言 sass stylus
- 构建工具 webpack vite

2. css盒模型

概念:
由外至内:margin->border->padding->content
①标准模型+IE模型
②两种模型区别:计算高度和宽度不同
IE模型宽度和高度包括框和填充
③如何设置:box-sizing: border-box, content-box
④js如何设置盒模型对应的宽和高
var dom = document.querySelector('.demo')
dom.style.width //只有在style存在的时候才能获取到,style中width为什么就是什么
dom.getBoundingClientRect().width //获取到的为数字,单位是px
window.getComputedStyle(dom).width //获取到的为带px单位的字符串
dom.currentStyle.width //ie下特有的属性 获取到的为带单位的字符串,单位为css中定义的单位
⑤根据盒模型解释边距重叠
父子元素 兄弟元素 空元素
参考网址:https://www.cnblogs.com/zhangmingze/articles/4664074.html
⑥BFC/IFC边距重叠解决方案
概念:块级元素格式化上下文
影响:
1.阻止外边距重叠
2.包含内部浮动
3.排除外部浮动
创建BFC:
overflow不为visible
float不为none
position不为static和relative
display为table-cell table-caption inline-block

3. DOM事件类

①DOM事件的级别
DOM0 element.onclick=function(){}
DOM1 没有定义事件相关的内容
DOM2 elment.addEventListener('click', function(){})
DOM3 增加了事件类型例如keyup等
②事件模型
捕获和冒泡
③事件流
捕获阶段->目标阶段->冒泡阶段
④描述DOM事件捕获阶段的具体流程
window->document->html(documentElement)->body->...->目标
⑤Event对象
event.preventDefault()
event.stopPropagation()
event.stopImmediatePropagation()
event.currentTarget // 当前绑定事件的元素
event.target // 被点击的元素
⑥自定义事件
var eve = new Event('custom',{bubbles: false, cancelbable: false}); //第二个可省略
dom.addEventListener('custom', function(){});
dom.dispatchEvent(eve);
CustomEvent和Event相同,但是可以带参数detail

4. 原型链

  1. 创建对象的几种方法?

    点击查看代码
    var o1 = {name: 'reamd'};
    var o2 = new Object({name: 'reamd'});
    var M = function(){
    this.name = 'reamd';
    };
    var o3 = new M();
    var p = {name: 'reamd'};
    var o4 = Object.create(p); // 把obj赋到o4的__proto__上
  2. 原型链图示 image#160px#200px

    • 只有函数才有prototype(function的声明时产生)

    • 只有实例对象才有__proto__

    • 修改了构造函数的prototype,相当于改变了实例所指向的原型对象

  3. instanceof 原理 image

    • instanceof用来判断构造函数的prototype是否在实例对象的原型链上。
  4. new运算符原理

    • 新对象obj被创建,继承自foo.prototype,构造函数foo被执行。执行时传入相应的实参,同时上下文this会被指定为这个新实例obj,不传参的情况下,new foo等同于new foo()。

    • 如果构造函数返回了一个”对象”,那么这个对象会取代整个new出来的结果。如果构造函数没有返回对象,那么new出来的结果为创建的对象obj。

5. 面向对象&类

  • 类与实例
    • 类的声明:构造函数、class
    • 实例:new
  • 类与继承
    • 实现继承的方式-基于原型链的继承、extends
点击查看代码
class Parent {
constructor (name, age) {
this.name = name;
this.age = age;
}
speak () {
console.log('my name is ', this.name);
}
}
class Child extends Parent {
constructor (name, age=18) {
super(name, age);
}
speakAge () {
super.speak();
console.log('my age is ', this.age);
}
}
let child = new Child('reamd');
child.speakAge();
// 寄生组合式继承
function P(name) {
this.name = name;
}
P.prototype.speak = function() {
console.log(this.name);
}
function S(name) {
P.call(this, name);
}
S.prototype = Object.create(P.prototype);
S.prototype.constructor = S;
const s = new S('a');
console.log(s.__proto__.__proto__.__proto__); // Object.prototype
const p= new P('b');
console.log(p.__proto__.__proto__); // Object.prototype
const obj = {
name: 'c'
};
console.log(obj.__proto__, obj.__proto__.__proto__); // Object.prototype, null

6. http协议类

http1.1新特性:
1.默认持久连接
2.管线化
3.断点续传
https特性:
内容加密+身份认证+完整性保护
http2特性:
1.二进制传输
2.头压缩(请求头缓存在客户端,存在描述符)
3.多路复用的流
4.服务端主动推送
【管线化和多路复用的区别】
HTTP管线化主要解决的是请求的排队和等待时间,而多路复用则主要解决的是TCP连接的建立和销毁开销,两者结合可以更好地提高网络通信效率。
①http协议的主要特点
简单快速(URI) 灵活(头配置) 无连接(连接一次就断开) 无状态(无非区分身份)
②http报文组成
请求报文:
请求行 http方法/页面地址 http协议及版本
请求头
空行
请求体
响应报文:
状态行 协议/版本 状态码 状态码说明
响应头
空行
响应体
③http方法
GET POST DELET PUT HEAD
获取 传输 删除 更新 获取报文首部
④POST和GET区别
回缓历长传
⑤状态码
1xx:指示信息
2xx:成功
3xx:重定向
4xx:客户端错误
5xx:服务端错误
200
206 range
301 永久重定向
302 临时重定向
304 缓存
400 bad request
401 未授权
403 forbidden
404 找不到页面
500 运行错误
503 负载高或宕机
⑥持久连接
keep-alive http1.1支持 判断请求是否结束?content-length or chunked 空chunked块
⑦http管线化
a.通过持久连接完成,仅http1.1支持此技术
b.只有GET和HEAD请求可以进行管线化,POST则有所限制
c.初次创建连接不应启动管线机制,服务器可能不支持http1.1

image

  1. 通信类

    • 同源策略及限制

      源: 协议 + 域名 + 端口 = 源

      限制:不是同源的文档能操作另一源的资源

      - cookie indexDB localstorage
      - dom无法获得
      - ajax请求不能发送
    • 前后端如何通信

      ajax websocket cors
    • 创建ajax

      点击查看代码
      var ajax = function(param) {
      var xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
      var type = (param.type || 'get').toUpperCase();
      var url = param.url;
      if (!url) {
      return
      }
      var data = param.data,
      dataArr = [];
      for (var k in data) {
      dataArr.push(k + '=' + data[k]);
      }
      dataArr.push('_=' + Math.random());
      if (type == 'GET') {
      url = url + '?' + dataArr.join('&');
      xhr.open(type, url);
      xhr.send();
      } else {
      xhr.open(type, url);
      xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
      xhr.send(dataArr.join('&'));
      }
      xhr.onload = function() {
      if (xhr.status == 200 || xhr.status == 304) {
      var res;
      if (param.success && param.success instanceof Function) {
      res = xhr.responseText;
      if (typeof res === 'string') {
      res = JSON.parse(res);
      param.success.call(xhr, res);
      }
      }
      }
      };
      };
    • 跨域通信

      1. JSONP
      2. cors
      3. websocket
      4. postMessage
      5. Image对象
      6. Hash & window.name
      7. cookie & localstorage
      8. form表单

7. 安全类

  • CSRF 跨站请求伪造
    • 攻击原理 image
    要素:
    1. 接口存在漏洞
    2. 访问的网站登录过
    防御措施:
    1. Token验证
    2. Referer验证
    3. 隐藏令牌
    4. 验证码
    5. ip地址(比较老的不推荐)
  • XSS 跨站脚本攻击
    • 攻击原理 向页面注入脚本运行,自动触发,引诱触发,iframe广告插入。 xss定义(反射型,存储型) 1.反射型: 发出请求时,xss代码出现在url中,作为输入提交到服务器端,服务器解析后相应,xss代码随响应内容一起传回给浏览器,最后浏览器解析执行xss代码。

      2.存储型: 存储型xss与反射型xss差别仅在于提交的代码会存储在服务器端,下次请求页面不用再提交。

      3.DOM型: 属于特殊的反射型。DOM 型 XSS攻击中,取出和执行恶意代码由浏览器端完成,属于前端JavaScript自身的安全漏洞。

    • 防御措施

      编码,过滤,校正
      1. 编码
      对HTML进行html entity编码
      2.过滤
      移除用户上传的dom属性,如onerror
      移除用户上传的style节点,script节点,iframe节点等
      3.校正
      避免直接对html entity解码
      使用dom parse转换,校正不配对的DOM标签

8. 算法类

  • 排序 冒泡排序, 快速排序, 选择排序,希尔排序

  • 数据结构 堆栈,队列,链表

  • 递归 60%算法都要用递归(本质要抓住,中止条件,参数如何传,尾递归)

  • 波兰式和逆波兰式

    • (1 + 2 * (4 - 3) + 6/2)中缀表达式
    • +1+*2-4 3/6 2 前缀表达式(波兰式,从右向左)
    • 1 2 4 3-*+6 2/+ 后缀表达式(逆波兰式,从左向右)
  • 哈夫曼编码

    • 给定N个权值作为N个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树。
    • 哈夫曼编码示例 注意: 基本功和理解题意,让面试官提示,写清原理。

四、二/三

A. 渲染机制

  1. 什么是DOCTYPE及作用 DTD告诉浏览器我是什么类型 DOCTYPE声明文档类型

    HTML5 <!DOCTYPE html>
    HTML4 传统和严格模式
    不包括展示性和弃用元素比如<font>
  2. 浏览器过程 image

  3. 重排(Reflow)/ 回流

dom中各元素都有自己的盒子,根据样式计算,并根据计算结果将元素放到它该出现的位置。

触发:
1. 增删改dom
2.移动dom的位置
3.修改css样式
4.resize窗口或滚动
5.修改网页默认字体
  1. 重绘(Repaint)

当盒子的位置,大小,颜色,字体大小都确定下来后,浏览器便把这些元素按照各自特性绘制一遍,于是页面内容出现了,这个过程称之为repaint。

触发:
1.dom改动
2.css改动

注意点: 一次添加节点

B. JS运行机制类

  • js单线程:一个时间内js只能干一件事
  • 任务队列:同步任务、异步任务
  • event loop image
  • 微任务micro task是跟屁虫,总是跟在同步任务的后面
  • 异步任务:
    • setTimeout和setInterval
    • Dom事件 点击的时候和时间到了才扔到异步任务中
    • ES6中的promise
      1. macrotasks和microtasks的区别?
      macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering
      microtasks: process.nextTick, Promise, MutationObserver
      任务队列中,在每一次事件循环中,macrotask只会提取一个执行,而microtask会一直提取,直到microtask队列为空为止。
      2. 为啥要用microtask?
      根据 HTML Standrad, 在每个task运行完以后,UI都会重新渲染,那么在microtask中就完成数据更新,因此当前task结束就可以得到最新的UI了。反之:如果新建一个task来做数据更新的话,那么渲染会执行两次。

C. 页面性能

  1. 提升页面性能有哪些方式

    • 资源压缩合并,减少http请求
    • 非核心代码异步加载(异步加载方式?区别?)
    • 利用浏览器缓存(缓存分类?缓存原理?)
    • 使用CDN
    • 预解析DNS
      <meta http-equiv="x-dns-prefetch-control" content="on">
      <link rel="dns-prefetch" href="//host.com"/>
  2. 异步加载

  • 方式: 1.动态脚本加载 2.defer 3.async
  • 区别:
    1. defer在HTML解析完才执行,多个按加载的顺序执行
    2. async加载完之后立即执行,多个执行顺序和加载顺序无关 注意:
    3. 普通的script(不使用async和defer)加载完会立即执行,会阻塞script标签下面的资源加载和dom的解析
    4. 使用async后,script加载完后会立即执行。(网络)资源的加载过程是异步的,不会阻塞后续资源的加载dom和解析。
    5. 使用defer后,script异步加载,html解析之后执行、DomContentLoaded之前执行。
  1. 浏览器缓存 缓存分类:
    • 强缓存 1.Expires: Thu,21 Jan 2017 23:09:02 GMT (绝对时间,服务器下发的,与本地浏览器比较) 2.cache-control: max-age=3600(相对时间,单位s) 同时存在,以cache-control为准 ①public 所有内容都将被缓存(客户端和代理服务器都可缓存) ②private 内容只缓存到私有缓存中(仅客户端可以缓存,代理服务器不可缓存) ③no-cache 浏览器将不再使用强制缓存, 而是直接去请求服务器, 如果存在协商缓存这个时候就会用到了 ④no-store 浏览器则不会在使用缓存的数据也不缓存数据,即强制缓存和协商缓存都失效了

    • 协商缓存 下发 请求

    1. Last-Modified If-Modified-Since
    2. Etag If-None-Match 浏览器默认优先强制缓存,强制缓存失效了,才使用协商缓存,协商缓存服务器两个都下发,根据客户端支持程度决定用啥,优先If-None-Match

D. 错误监控

  1. 实现一个埋点监控SDK? A: 一般埋点监控SDK满足三个功能:用户行为监控(pv/uv/点击行为)、页面性能监控(页面开始加载时间,白屏时间)、页面错误告警监控。 实现要素productID,send(image、navigator.sendBeacon),performance.timing(FP,DCL,LOADED) 错误告警监控分为JS原生错误和React/Vue的组件错误的处理。 js原生错误:try catch和未捕获的error及unhandledrejection vue和react可以使用错误边界组件解决错误问题。

  2. 错误上报

    1. 采用ajax通信方式上报
    2. 采用Image对象上报

五、三/四

业务能力 团队协作能力 事物推动能力 带人能力 其他能力(组织能力 学习能力 行业经验)

六、终

  1. 职业竞争力 业务能力 思考能力 学习能力 无上限付出

  2. 职业规划

    1. 目标:业务上成为专家,技术上成为大牛
    2. 近期目标: 不断学习积累各方面经验,学习为主
    3. 长期目标:做几件有价值的事情,开源作品,技术框架
    4. 方式方法:先完成业务上的主要问题,做到极致,然后逐步向目标靠拢。
  3. 总结

    • 胜不骄,败不馁,总结经验,步步为营,多拿offer
    • 30%技术 + 70%状态

七、常用知识点

# 常用
1. gulp和grunt的对比
高效:基于unix流的概念,管道连接
高质量:gulp每个插件只完成一个功能
易学:五个API, src dest watch task run
易用:代码优于配置
Q: js三座大山
A: 1. 作用域和闭包 2. 原型和原型链 3. 异步和单线程
- 作用域主要是隔离变量,分为:全局作用域、模块作用域、函数作用域、块级作用域
- 闭包: 函数A里包含了函数B,而函数B使用了函数A的变量,那么函数B被称为闭包或者闭包就是能够读取函数A内部变量的函数。a.变量常驻内存 b.改变外部函数的变量
Q:普通函数,箭头函数,call关于this的指向
A:普通函数:this总是指向调用它的对象,如果用作构造函数,this指向创建的对象实例。
箭头函数:箭头函数本身没有this,按照作用域链的就近原则到上级作用域查找,把执行时上下文的this供自己使用。
call:改变this的指向,因为箭头函数没有this,改变不了。
Q: js优先级
A: 括号 点 new参 函数调用 new无参
Q: CommonJS模块和ES模块区别?
A:
- CommonJS模块
导入: require
导出: module.exports or exports.xxxx
- ES模块
导入:import
导出: export xxx or export default xxx
- 其他说明
1. CommonJS模块输出的是一个值的复制(一旦输出一个值,模块内部的变化就影响不到这个值),ES6模块输出的是值得引用(这个变量是只读的,对它进行重新赋值会报错)。
2. CommonJS模块是运行时加载,ES6模块是编译时输出接口。
3. ES6模块之中,顶层的this指向的是undefined,CommonJS模块的顶层this指向当前模块。
Q: type和interface区别
A: 对象函数都适用,都能通过extends扩展
type可以别名声明,可用于基础类型、联合类型、元组。
interface可以同名合并,type不行。
Q: vue $nextTick实现原理
A: nextTick在DOM更新完毕之后执行一个回调。当数据变化时,Vue不会立即更新 DOM,而是将需要更新组件标记为“脏”。当前事件循环结束后,Vue.js 会将所有“脏”组件更新合并到一起,在下一个事件循环中更新DOM。优先选择 Promise、MutationObserver 或 setImmediate,如果都不支持则回退到 setTimeout。
Q: Webpack 和 Vite区别?
A: 1. 开发服务器:Webpack 使用 webpack-dev-server 进行整体打包,重新构建速度可能较慢;Vite 使用原生 ES 模块按需编译,启动和热更新速度更快。
2. 构建速度:Webpack 使用依赖图策略打包,可能导致较慢的构建速度;Vite 在开发环境中按需编译,生产环境使用高性能的 Rollup 打包。
3. 兼容性:Webpack 支持多种模块格式和旧版浏览器;Vite 侧重于现代浏览器和原生 ES 模块,可能对旧版浏览器支持不如 Webpack。
4. 插件生态:Webpack 拥有庞大的插件生态;Vite 插件生态相对较小,但兼容大部分 Rollup 插件,正在快速成长。
Q: Vue2、Vue3、React diff 的区别
A: React diff 特点 - 仅向右移动
Vue2 diff 特点 - 双端比较
Vue3 diff 特点 - 最长递增子序列
Vue3 dom diff算法:
1. 头部比较,不同break
2. 尾部比较,不同break
3. 经过1,2两个步骤,比较结束的话,如果旧节点数量 > 新节点数量,卸载;否则,新增;
4. 如果是3步骤对立面,没比较完,则把剩余待比较多新节点遍历一遍记录newMap,key-index,然后遍历旧节点剩余部分,如果其key在newMap里面,记录到newIndexToOldMap中,否则卸载节点。
5. newIndexToOldMap其实是一个数组,数组index是新节点索引,其值是旧节点索引,然后把旧节点采用最长递增子序列的方式进行移动。
Q: tree shaking
A: 如果想要做到tree shaking,在引入模块时就应该避免将全部引入,应该引入局部才可以触发tree shaking机制。
Q:vue2和vue3的区别
A:1. 选项式 vs 组合式
2. webpack vs vite
3. 双向绑定底层实现Object.defineProperty和Proxy,为什么改为proxy,a. 不用重写数组相关方法 b.不用遍历整个对象属性(随着对象属性规模变大,vue2性能也会下降)
Q: vue路由模式?
A: 形式上:hash模式url里面永远带着#号,路由默认使用这个模式。history模式没有#号,是个正常的url,适合推广宣传。
功能上:把vue做的页面,分享到第三方的app里,有的app里面url是不允许带有#号的,使用history模式,在二级页面做刷新操作,会出现404,需要运维同学配置一下apache或是nginx的url重定向,重定向到你的首页路由。
技术上:哈希模式其实是利用了window.onhashchange事件,history模式是HTML5 History Interface 中新增的两个神器 pushState() 和 replaceState() 方法。
Q:JS的垃圾回收机制
两种:
1. 标记清除:函数内的变量在函数执行的时候记录为“进入环境”,函数执行结束,记录为“离开环境”,垃圾处理器会给每个变量打标,然后去掉在使用的变量的标记,回收完成后,变量块不连续,采用标记整理。
2. 引用计数,容易引发内存泄漏,现在不怎么用了
3. v8引擎基于标记清除回收机制的优化:分为新生代和老生代,新生代又分为使用区和空闲区,垃圾回收使用区的变量后,空闲区和使用区置换,这样就进行了内存整理,然后下一次回收变量的时候,把上一次没回收和这一次也没回收的变量放到老生代。
Q: 输入网址后,发生了什么?
A: DNS解析:
(1)递归查询
DNS服务器接收客户机请求,必须使用一个准确的查询结果回复客户机。如果DNS服务器本地没有存储查询DNS信息,那么该服务器会询问其他服务器,并将返回的查询结果提交给客户机。
(2)迭代查询
DNS服务器会向客户机提供其他能够解析查询请求的DNS服务器地址,当客户机发送查询请求时,DNS 服务器并不直接回复查询结果,而是告诉客户机另一台DNS服务器地址,客户机再向这台DNS服务器提交请求,依次循环直到返回查询的结果为止。
TCP三次握手:
http请求
http回应(重定向)
服务器返回
解析HTML
*注:DNS解析原理:优先级=> dns缓存 > hosts > dns服务*
  • ts常用示例
点击查看代码
// 1. 函数返回值声明
interface Person {
name: string;
gender: string;
}
const fetchPerson = async (): Promise<Person> => {
const data = await fetch("http://test.com/api/people/1").then((res) => {
return res.json();
});
return data;
};
const fetchPerson2 = async () => {
const data: Person = await fetch("http://test.com/api/people/1").then((res) => {
return res.json();
});
return data;
};
const fetchPerson3 = async () => {
const data = await fetch("http://test.com/api/people/1").then((res) => {
return res.json();
});
return data as Person;
};
// 2. Record
const cache: Record<string, string> = {};
const cache2: {
[id: string]: string;
} = {};
// 3. try catch,catch的变量类型只能为any或unknow
try {
} catch (e: any) {
console.log(e.message);
}
try {
} catch (e) {
console.log((e as Error).message);
}
// 4. extends
interface Base {
id: string;
}
interface User extends Base {
firstName: string;
lastName: string;
}
// 相当于
interface User {
id: string;
firstName: string;
lastName: string;
}
// 5. Omit && Pick && keyof
interface User {
id: string;
firstName: string;
lastName: string;
}
/**
type MyType = {
firstName: string;
lastName: string;
};
*/
type MyType = Omit<User, 'id'>;
type MyType2 = Pick<User, 'firstName' | 'lastName'>;
function setProp<T, K extends keyof T>(obj: T, key: K, val: T[K]): T {
obj[key] = val;
return obj;
}
interface Person {
name: string;
age: number;
}
const person: Person = {
name: 'a',
age: 18
};
setProp(person, 'name', 'b');
// 6. function type
type FocusListener = (isFocused: boolean) => void;
const addListener = (onFocusChange: FocusListener) => {};
interface User {
id: string;
firstName: string;
lastName: string;
}
interface CreateUserType {
(): Promise<string>;
}
interface GetUserType {
(id: string): Promise<User>;
}
const createThenGetUser = async (
createUser: CreateUserType,
getUser: GetUserType,
): Promise<User> => {
};
// 7. 类型守卫
- typeof
- instanceof
- in
- 字面量 if (status === 'active') { } else {}
- 用户定义
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
type Shape = Square | Rectangle;
function isSquare(shape: Shape): shape is Square {
return shape.kind === "square";
}
function getArea(shape: Shape): number {
if (isSquare(shape)) {
return shape.size * shape.size; // 这里 shape 被推断为 Square 类型
} else {
return shape.width * shape.height; // 这里 shape 被推断为 Rectangle 类型
}
}
  • css 水平垂直居中 image