【Javascript 部分】
* 事件
1. 注册事件
false: 未开启捕获, 从里向外执行事件
true: 开启捕获, 从外向里执行事件
el.addEventListener(事件, 回调函数, false)
2. 删除事件
el.removeEventListener(事件, 回调函数, false)
3. 取消默认事件
event.preventDefault()
4. 阻止冒泡
event.stopPropagation()
什么是事件委托:
事件委托是一种优化事件监听器的方式,它利用事件冒泡机制,在父元素上统一绑定事件,通过判断事件源来执行对应的操作,从而提高性能。 例如,如果有一个列表,每个列表项都有一个点击事件,如果使用传统的事件监听方式,需要为每个列表项都绑定一个点击事件,当列表项很多时,会导致性能问题。而使用事件委托的方式,只需要在列表的父元素上绑定一个点击事件,当点击列表项时,事件会冒泡到父元素,通过判断事件源来执行对应的操作,从而避免了为每个列表项都绑定事件的问题,提高了性能。 事件委托在实际开发中经常用到,特别是在列表、表格等需要大量绑定事件的场景下,可以显著提高页面性能。
* react 16.8 之前 事件代理 事件委托 注册在 document.onClick
react 16.8 root
* 事件代理优点:
1. 新插入标签可以不用注册事件
2. 减少内存占用
* 例子:
const ull = document.querySelector("ul");
ull.addEventListener("click", function (e) {
//nodeName:节点名称
//className: 类名
//target.id: 对比id
if (event.target.nodeName === "LI") {
console.log("a");
}
});
* new 类 经过哪几步
1. 创建一个空对象 {}
2. 执行构造器 把 {} 赋值给 this
3. 给 {} 赋值
4. 返回对象给类的实例
* 单点登录
1. cookie设置 domian 域名
2.
postMessage:
用法: 单点登录,给其他的网址传值
iframe的一个window对象
iframe是浏览器的一个窗口
iframecontentWindow.postmessage(参数,路径(*//给所有网站传值))
传递的页面监听:
window.addEventListener('message',evt=>{
evt.data
})
3. sso
* class
1. class 怎么实现继承
class A {
constants () {
// 为什么要调用 super 因为 子类没有自己的 this 需要调用 super 继承父类的 this
super()
}
}
class B extends A {
// constructor 不写默认会调用
constructor () {
// 调用 super 是因为 子类没有自己的 this, 需要继承父类的 this
super()
}
}
静态属性定义
static 属性
Person.属性
* 继承
// 1. E6 class 继承: 引用类型 共享的
// 2. 原型链继承: 引用类型 共享的
// 3. 寄生组合式继承
function inheritPrototype(subType, superType){
var prototype = Object.create(superType.prototype); // 创建对象,创建父类原型的一个副本
prototype.constructor = subType; // 增强对象,弥补因重写原型而失去的默认的constructor 属性
subType.prototype = prototype; // 指定对象,将新创建的对象赋值给子类的原型
}
// 父类初始化实例属性和原型属性
function SuperType () {
this.colors = ["red", "blue", "green"];
}
// 借用构造函数传递增强子类实例属性(支持传参和避免篡改)
function SubType () {
SuperType.call(themeVariables);
}
// 将父类原型指向子类
inheritPrototype(SubType, SuperType);
// { colors: ["red", "blue", "green"];}
var instance1 = new SubType();
// { colors: ["red", "blue", "green"];}
var instance2 = new SubType();
instance1.colors.push("2"); // ["red", "blue", "green", "2"]
instance1.colors.push("3"); // ["red", "blue", "green", "3"]
console.log(instance2.colors, 1111);
* httponly:
不可修改的 cookie
* cdn oss:
cdn 是内容分发网络, 是一组分散在不同地理位置的web服务器 打开网站时 找最近的cdn服务器访问 可以加速访问网站速度
oss 存储文件的服务器 公司项目一般存在 oss 上
* window.onload 页面dom 和 image js css 全部加载完成触发
window.addEventListener('DOMContentLoaded', () => {
// 页面 dom 加载完成 触发
})
* 前端性能优化
javascript:
* 把 script 放在 html 底部
* 使用 e6, 7 减少代码量
css:
* 尽可能使用 css3 属性
图片:
* 雪碧图
* webp
* icon
* 图片懒加载
* 避免图片src属性为空
http:
* 尽可能减少页面 http 请求
* cdn
* 浏览器缓存 包括 强缓存 和 协商缓存
* 避免重定向
* 开启 Gzip 压缩
react, vue:
* 路由懒加载
* SSR (前后端同构)
* 图片裂图处理:
export default function Isimg(props) {
const [x, setX] = useState(false)
const onError = () => {
console.log('加载失败');
setX(true)
}
return (
)
}
* 移动端开发:
一. 移动端类型
wap (手机浏览器 输入网址)
hybrid (混合 前端 + 安卓 前端 + IOS) 壳子原生 + H5 + C3
原生app (安卓 IOS)
二. hybrid 壳子
安卓 WebView 封装了一个自定义的浏览器(https://www.douyin.com)
IOS WKWebView 封装了一个自定义的浏览器
三. 布局类型
自适应布局 rem
响应式布局 @media
@media screen and (max-width: 1000){
.div {
color:
flex:
}
}
四. 前端 + 安卓 IOS 代码交互
ios: WebViewJavascriptBridge
android: jsbridge
五. 调试 hybrid
1. 手机连接USB线 输入chrome://inspect/#devices
2. 点击inspect 进行调试
3. 手机 和 电脑 必须是同网段
* 内存泄漏:
1. 闭包
2. 死循环
* 网页白屏可能是哪些原因引起的:
1. 网络延迟 加载慢
2. css 隐藏了页面模块
3. js 加载慢阻塞整个页面加载
4. 进行比较大运算 页面卡死
5. 路由错误 加载页面没有内容
* async 原理
function spawn (genF) {
return new Promise(resolve => {
const gen = genF()
function step (nextF) {
let next
next = nextF()
if(next.done) {
return resolve(next.value)
}
Promise.resolve(next.value)
.then(v => step(() => gen.next(v)))
}
step(() => gen.next(undefined))
})
}
定义一个函数接收一个参数这个参数是Generator函数
return new promise 接收一个函数函数两个参数(resolve, reject)定义一个变量接收这个Generator函数
在定义一个函数这个函数是Generator函数里面的next方法,返回这个next方法这个next方法是一个对象
里面有两个值一个value:promise返回值 一个 done:布尔值 然后判断这个next.done
如果返回true 直接返回一个promise 如果返回 false那就继续递归调用该函数函数
* 原型链 prototype
创建一个函数 或者 class 类, js会自动为函数添加一个 prototype 属性, 默认包含2个属性
constructor 和 __proto__, constructor 指向当前类, __proto__ 指向上一级 prototype
这就形成了原型链
怎么找:
首先在自己的实例上找,然后没有找到的话就通过_proto往上找,如果没有找到的话就继续向上找
* 需求文档 prd
* 做项目流程 (PM 产品, QA 测试, FE 前端, UI, dev 后台)
1. 项目需求评审 大概2-3次
* 第一次 提很多不合理问题 PM记录 改第二版
* 第二次 提很多不合理问题 PM 继续改
* 第三次 终审
// 敏捷开发: 一个项目 一组固定的人 (QA FE DEV) 一个月迭代2版
// 半个月迭代一次 14 - 4 = 10, 4天 6天
2. UI出图
3. 前端 后台给出具体的确定排期 (UI给图)
4. QA 给出测试排期 (技术评审)
5. 提测改bug
6. 发布上线, 跟踪线上问题
* apply:
Function.prototype.apply = function (context, args) {
// 不传默认是全局, window
context = context || window
// args不传时默认是空数组, 防止下面用spread操作符时报错
args = args ? args : []
// 把this存到context.fn, 这里的this是调用的函数
context.fn = this
// 执行调用的函数, this指向context, 参数用spread操作符扩展
const res = context.fn(...args)
// 删除, 不污染context
delete context.fn
// 返回res
return res
}
call:
Function.prototype.call = function (context, ...args) {
// 不传默认是全局, window
context = context || window
// args不传时默认是空数组, 防止下面用spread操作符时报错
args = args ? args : []
// 把this存到context.fn, 这里的this是调用的函数
context.fn = this
// 执行调用的函数, this指向context, 参数用spread操作符扩展
const res = context.fn(...args)
// 删除, 不污染context
delete context.fn
// 返回res
return res
}
* 从输入一个URL到浏览器页面展现到底发生了什么:
输入网址
DNS解析
建立TCP/IP链接(三次握手四次挥手)
发送HTTP请求
服务器处理请求
服务器返回HTTP响应
浏览器渲染页面并展现(结合html渲染详细说)
断开连接
* 怎么设置git 不上传某些文件:
设置 .gitignore
* 为什么会有跨域:
因为浏览器的同源策略(CORS) 即协议, 域名, 端口 只要有一个不同 就会产生跨域
* 怎么解决跨域:
jsonp
后台返回一个函数调用方法 例如 abc(数据)
前端在js里设置一个 abc 方法, 后台调用 前端的abc方法传递数据
node代理
node 请求后台接口(node请求后台接口不走浏览器所以不会跨域), 前端请求node的接口
export default {
//设置key值
dev: {
'/dev': {
// 代理的后台接口地址
target: config.localhostUrl[ENV],
changeOrigin: true,
pathRewrite: {
'^/dev': ''
},
},
},
}
后台设置请求头
response.setHeader("Access-Control-Allow-Origin", "*")
response.setHeader("Access-Control-Allow-Methods", "*")
response.setHeader("Access-Control-Max-Age", "3600")
response.setHeader("Access-Control-Allow-Headers", "*")
response.setHeader("Access-Control-Allow-Credentials", "true")
* 上线后怎么解决跨域
设置 nginx
* 跨域的token在那里:
登录验证有: session 是后台的 他会把token存到cookie里面 (很低级)
好处:用户点击登录 ->请求后台接口->后台往前端种一个cookie(携带token)
我们再请求其他接口的时候,带token的cookie就会自动给后台,不需要我们带
稍微好一点的公司用:
用户点击登录 ->请求后台接口->接口返回token
head传的话 把这个token在axios请求拦截里面 判断
把token拼接到payload里面
通过请求头给带过去 head
jwt 令牌:
登陆->后台给令牌->后台通过令牌生成token,前端把token发送给后台
* 配代理:
首先配置 target
配一个前缀
target就是我的代理地址
* 心跳检测:
检测前端和后台链接是不是还存在, 如果已经断开 通知后台, 后台关闭连接
实现: 每隔一段时间调用 send()
* 怎么看依赖包文件版本:
pageage.json
* hash history 区别:
1. hash 带 #, history 不带 #
2. history 上线后刷新页面后会展示404 找不到页面(设置nginx可以解决这个问题), hash刷新正常展示
【React】
* 高阶组件(HOC)
1. 定义: 高阶组件是参数为组件, 返回值为新组件的函数
2. 都用过哪些高阶组件: connect, withRoute
// 高阶组件 HOC 接收一个组件 返回一个新组件的一个函数
// WrappedComponent 传进来的组件
function Hoc(WrappedComponent) {
return function (props) {
const [xy, setXy] = useState({
x: 0,
y: 0
})
useEffect(() => {
const fn = ({ clientX, clientY }) => {
setXy({
x: clientX,
y: clientY
})
}
document.addEventListener('mousemove', fn)
return () => document.addEventListener('mousemove', fn)
}, [])
return (
)
}
}
export default Hoc(Abc)
* setState 是同步还是异步
setState 有同步也有异步
异步: react 原生事件里的 setState, 写在生命周期里的 setState
同步: 原生js事件, setTimeout, setInterval, ajax
* memo: 16.8 引入
1.memo 不写第二个参数 自动比较 上一次的 props 和 下一次的 props 的值,基础类型
直接比较值 引用类型比较指针
memo(函数组件,(prevProps,nextProps)=>{
return ture 不渲染
})
const isEqual = require('react-fast-compare')
//比较对象的值是否一致,一致返回ture
export default memo(C,(prevProps,nextProps)=>{
return isEqual(prevProps,nextProps)
})
function C(props){
log(1111)
return(
)
}
// 可以简写为
memo(C,isEqual)
* 展示组件:
公共组件 不包含 redux, dva 等具体状态, 大部分参数是父组件传入
* 容器组件:
父组件 包含 redux, dva 等状态, 传递数据给展示组件
ant样式修改:
在config.js里面theme里面修改全局样式
* React采用的是单向数据流的原因在于: 1. 数据流向清晰:React中数据只能从父组件传递给子组件,子组件不能直接修改父组件的数据。这种单向数据流的设计使得数据流向清晰,易于理解和维护。 2. 组件独立性:React中每个组件都是独立的,组件之间不会相互干扰。如果允许子组件直接修改父组件的数据,那么就会破坏组件的独立性,导致组件之间相互依赖,难以维护。 3. 引入状态管理工具:如果需要在多个组件之间共享数据,可以使用状态管理工具(如Redux、MobX等),将数据存储在一个中央数据仓库中,通过派发事件的方式来更新数据。这样可以实现多个组件之间的数据共享,同时也不会破坏单向数据流的原则。 总之,React采用单向数据流的设计,旨在提高组件的独立性和可维护性,同时也为引入状态管理工具提供了方便。
* Hook 使用
* useState:
export default () => {
// 异步
const [x1, setX1] = useState(1)
const [x2, setX2] = useState((prev) => {
log(prev) underfined
// ajax
if (true) {
return 3
} else {
return 2
}
})
const onClick = opt => {
// 异步 (等一小会)
setX1(x1 + 1)
// prevState 上一次的值
setX1(prevState => {
console.log(prevState, 'prevState');
// return 出去的值就是 x1 的值
return prevState
})
console.log(x1, 'x1');
}
return (
{x1}
)
};
* setState:
export default class Login extends React.PureComponent {
constructor(props) {
super()
this.state = {
user: '小花'
}
}
componentDidMount() {
this.setState({
user: '小兰'// 生命周期中 异步
}, () => {
可以拿到同步值
})
this.setState(pre => {
console.log('pre', pre);//同步的值
// pre是整个的state
return pre
})
}
render() {
return (
class
)
}
}
useState为什么是异步的:浪费性能
* useRef, createRef 区别:
// 1. createRef 只要组件重新渲染 createRef 就会重新重新执行
export default () => {
const [x1, setX1] = useState(() => {
return 1
})
// 特性: useRef 页面渲染的时候只执行一次
// 特性: 只有 current 读写
// 返回值: { current: undefined } 内存地址 abc
// 作用1. 获取DOM
// 作用2. 存储上一次的值 指针不变所以可以储存上一次的值
const ref = useRef()
const ref2 = createRef()
const onClick = opt => {
// ref.current === 1
ref.current = x1
ref2.current = x1
// 异步
setX1(x1 + 1)
}
return (
{x1}
小花
小蓝
)
}
* useCallback:
用途: 父组件刷新 子组件不刷新
返回一个新函数 如果依赖是空 新函数的指针永远不变
依赖是空 useCallback 永远只执行一次
const fn = useCallback(() => {
}, [])
// 如果依赖改变了 重新返回指针变了的新函数
const fn = useCallback(() => {
}, [x])
*/
export default function UseCallback () {
const [x, setX] = useState(0)
// console.log('我是父组件,我执行了');
// fn 保存的 123指针 -> () => console.log(1)
// 第一次渲染 fn 123
// 第二次 直接把 123 指针 给 fn
// 第三次 直接把 123 指针 给 fn
const fn = useCallback(() => {
// console.log(1)
}, [])
return (
<>
setX(x + 1)}>x: {x}
>
)
}
* useMemo:
特性:
1. 有一个返回值 缓存回调函数里 retrun 的值
2. useMemo 立刻执行的
const fn = useMemo(() => {
return 123
return () => {
}
}, [])
*/
export default connect(({ loading }) => {
return {
loading: !!loading.effects['upload/fetch'],
}
})(UseCallback)
function UseCallback (props) {
const { dispatch, loading } = props
const [form] = Form.useForm()
const [fileList, setFileList] = useState([])
const [x, setX] = useState(20000)
const [y, setY] = useState(20000)
// 第一次刷新 x === 20000
// 第二次 x === 20001
const x1 = useMemo(() => {
console.log('我执行了');
let sum = 0
for (let i = 0; i < x; i++) {
sum += i
}
return sum
}, [x])
return (
x: {x1}
y: {y}
setX(x + 1)}>x: {x}
setY(y + 1)}>y: {y}
)
}
* useCentext:
定义一个公共文件
import React from "react";
const ThemeContext = React.createContext(默认值)
export default ThemeContext
父组件
如果不用ThemeContext.Provider包裹子组件 子组件的a是默认值
import React from 'react'
import { Select, Button } from 'antd'
import QuseCallback from './components/QuseCallback'
import ThemeContext from './c.jsx'
// useContext
export default function Hmo(props) {
return (
)
}
子组件
import React, {useContext } from 'react'
import { Select, Button } from 'antd'
import { connect } from 'dva'
import ThemeContext from '../c'
export default function QuseCallback(props) {
const a = useContext(ThemeContext)
console.log('a', a);
return (
)
}
* Fiber:
React Fiber是react执行渲染时的一种新的调度策略 JavaScript是单线程的 一旦组件开始更新
主线程就一直被React控制 这个时候如果再次执行交互操作 就会卡顿 在render函数中创建的React
Element树在第一次渲染的时候会创建一颗结构一模一样的的Fiber节点树 Fiber在update的时候
会从原来的Fiber clone出一个新的Fiber 俩个Fiber diff出的变化 在更新结束后会取代之前的
Fiber节点树渲染过程采用切片的方式 每执行一会儿 就歇一会儿 如果有优先级更高的任务 就会先去执行
降低页面发生卡顿的可能性, Fiber分片优先级分同步 异步 NoWork sync async
Fiber 更新任务分成俩个阶段 调和阶段 和 交付阶段, 调和阶段 找出要做的更新工作 是一个计算阶段
可以被打断, 例如 setState useState 交付阶段需要提交所有更新并渲染 被设置为不能打断(然后说一下
协调的三种diff算法),fiber是个链表 有child和sibing属性 指向第一个子节点和相邻的兄弟节点 从而构
成fiber tree
* JSX:
是一个包含 type, props, children的对象
* class 生命周期
(react 16.4 之前)
三个阶段: 加载阶段 更新阶段 卸载阶段
加载阶段:
constructor
render
componentDidMount
更新阶段:
componentWillReceiveProps(props)
shouldComponentUpdate(nextProps, nextState): nextProps && this.props(旧的)
render
componentDidUpdate
卸载阶段:
componentWillUnmount
(react 16.4 之后)
三个阶段: 加载阶段 更新阶段 卸载阶段
加载阶段:
constructor
// getDerivedStateFromProps:
// 1. 里面没有 this
// 2. return 的值 是改变 state, 如果你不想改变 state 就返回 return null
getDerivedStateFromProps(nextProps, state)
render
componentDidMount
更新阶段:
getDerivedStateFromProps(nextProps, state)
shouldComponentUpdate(nextProps, nextState)
render
getSnapshotBeforeUpdate(prevProps, prevState)
componentDidUpdate
卸载阶段:
componentWillUnmount
=-
* PureComponent:
优化子组件渲染, 自动判断基础类型数据, 引用类型数据根据指针是否变化判断子组件是否渲染
* redux 工作流程:
view(视图) -> action -> reduser修改state -> 重新渲染视图
redux react-redux redux-actions redux-persist redux-promise redux-thunk
redux-persist(数据持久化)
redux-promise redux-thunk(中间键)
createStore applyMiddleware combineReducers
属性:
createStore
创建一个store仓库 因为redux是单store
第一个参数是reduse 第二个参数是中间键
applyMiddleware
加载我的中间键
combineReducers
//传入一个renducers管理组, 返回的是一个renducer
合并reduse
我有很多的function 但是store只要一个function
把多个function合并为一个function
store有那些属性
getState 获取所有的状态
dispatch
发布订阅
* 虚拟DOM:
虚拟DOM是一个对象, 包含type表示节点类型, props属性, props下包含children属性, 子节点又包含
type属性, props 属性 children属性, js通过使用 document.createElement, document.craeteTextNode
递归循环这个对象, 创建DOM树, 然后用这个DOM树和真实DOM进行比较, 这颗DOM树叫做虚拟DOM, react diff算法有
三种方式, 1. 最外层节点不同, 重新渲染全部节点, 最外层节点相同则不重新渲染全部节点 2. 相同节点的属性不同, 只
渲染不同的属性, 不重新渲染节点 3. key相同不重新渲染节点, key不同重新渲染该节点
* react18: 主要更新的是 Concurrent 并发 (高优先级[不能打断], 低优先级[可以打断])
1. startTransition [startTransition(() => { })]: 不用 isPending 直接使用 这个方法
2. const [isPending, startTransition] = useTransition [startTransition(() => {})]
3. useDeferredValue(值): 你不能改父组件 父组件传了一个值给子组件 在子组件里把这个值变成低优先级
4. useId(): 生成一个 id
5. useInsertionEffect(() => {}, []) // DOM变更前同步触发 主要用来加载 css in js
6. ReactDOM.createRoot, root.render
7.
* 不使用 antd 封装 Modal 组件
使用 ReactDOM.createPortal 把 Modal 插入到body下面和root同级
(为什么要和root同级, 如果不同级 放在 root内, 在页面里某个div如果有overflow: hidden, Modal 可能无法
做全屏遮罩)
import React, { memo } from "react"
import ReactDOM from 'react-dom'
function A(props) {
console.log('document.body', document.body);
return (
ReactDOM.createPortal(
啊啊啊我不行了
,
document.body
)
)
}
export default memo(A)
* Context 旧的使用方式
{
value => {
// value 父组件注入的值
}
}
* 多页面应用 单页面应用
1. 单页应用(SPA)
1) 只有一个 html 文件, 通过切换路由展示不同页面
2) 页面局部刷新
3) 不利于 SEO
4) 不需要重复加载 css js, 所以页面切换后渲染快
5) 可以使用 hash 也可以使用 history 模式(history模式上线后, 刷新浏览器后页面会找不到, 所以需要配置 nginx)
2. 多页面应用
1) 多个html页面
2) 切换页面 整个页面全部重新加载 用户体验差
3) SEO实现容易
* 什么是seo:
搜索引擎的优化
seo做的越好 在被搜索的时候就可以越靠前
* react 实现 keep-alive缓存:
react-activation
【CSS部分】
* CSS 盒模型
box-sizing: content-box; // 标准盒模型: padding border 都会累加到 元素的宽高里
box-sizing: border-box; // 怪异盒模型: padding border 不会都会累加到 元素的宽高里
* css 权重
!important(10000) > style(1000) > id(100) > class, 伪类选择器(10) > 标签选择器(1)
> 通用选择器(*), 子选择器(>), 相邻选择器(+)同胞选择器(~), 权重值为(0)
【VUE2部分】
* v-if v-show 区别:
v-show隐藏则是为该元素添加display: none, v-if是将dom元素整个添加或删除
* watch 怎么对对象做深度监听
deep: true
* watch computed 区别:
computed 可以缓存数据, watch 不能缓存数据
* vue 生命周期:
beforeCreate: 在实例初始化之后,进行数据侦听和事件
created: 在实例创建完成后被立即同步调用
beforeMount
mounted: 实例被挂载后调用
beforeUpdate
updated: 在数据更改导致的虚拟 DOM 重新渲染和更新完毕之后被调用
activated: 被 keep-alive 缓存的组件激活时调用
deactivated: 被 keep-alive 缓存的组件失活时调用
beforeDestroy
destroyed: 实例销毁后调用
errorCaptured: 在捕获一个来自后代组件的错误时被调用
* vue 父子组件传值方式:
props(包括父组件给子组件传递函数)
$emit
ref
provide / inject
vuex
eventBus 定义一个事件总线 使用$on 绑定 $emit 触发
* MVVM:
vue是采用数据劫持配合发布者-订阅者模式的方式 vue2通过Object.definerProperty(), vue3通过 Proxy来劫持各个属性的setter和gettter
在数据变动时, 发布消息给依赖收集器, 去通知观察者, 做出对应的回调函数, 去更新视图, MVVM作为绑定的入口
整合Observer, Compile和Watcher三者, 通过Observer来监听model数据变化表, 通过Compile来解析编译模板指令
最终利用Watcher搭起Observer, Compile之间的通信桥梁, 达到数据变化 => 视图更新;视图交互变化 => 数据model
变更的双向绑定效果
* vue 指令:
v-if, v-show, v-bind, v-on, v-html, v-model, v-text
* vuex:
视图 -> action -> mutations 修改state -> 渲染视图
namespaced
state
mutations
actions
modules
【TS】
* 优势:
1. TS 是强类型语言 实时报错
2. 划过实时展示 api
* 怎么解决 css 命名冲突
1. css-module
2. css in js
3. react-css-modules / styleName(我们用的)
* 怎么让一个元素 上下左右居中 (3种)
1. flex
display: flex; // 设置 flex 必须要设置父元素
justify-content: center; // x 轴居中
align-items: center; // y 轴居中
1. position: absolute; top, letf, bottom, right 都设置成 0
1. margin: 50% 0 0 50%; tranfrom: translate(-50%, -50%)
* 错误边界
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
errorInfo: null
};
}
static getDerivedStateFromError (error) {
console.log(error, 'error2222222');
// 更新 state 使下一次渲染可以显示降级 UI
return { errorInfo: true }
}
// 报错
componentDidCatch(error, errorInfo) {
// 请求后台接口 把错误上报
console.log(errorInfo, 'errorInfo');
console.log(error, 'error');
}
render() {
if (this.state.errorInfo) {
return (
错误替代展示
);
}
return this.props.children;
}
}
* useEffect 可以模拟哪些生命周期
1. componentDidMount // 加载完成的
2. componentDidUpdate // 更新阶段
3. componentWillUnmount // 卸载阶段
return一个回调函数 return的这个函数就可以模拟卸载的生命周期
触发 组件重新渲染了 组件跳转到其他路由了 销毁了就会触发
可以模拟更新的
但是有问题 首次渲染的时候就会执行一次
* setInterval, setTimeout 特性
const [time, setTime] = useState(3)
useEffect(() => {
// setInterval, setTimeout 会形成闭包, 会保存 time 的复制值, 该值与外面的 time
// 不是同一个值
setInterval(() => {
setTime(time - 1)
// 始终输出 3
console.log(time, 'xxx');
}, 1000)
}, [])
* hook 规则
* hook 不要在循环, 条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层以及任何 return 之前调用他们
* hook 只能在函数组件里调用 (包括自定义 hook), 不能用在 普通函数 或者 类组件里
* hook 为什么必须要放到最顶层?
hook 必须按照一定的顺序执行, (举个例子) 否则就会报错, 所以必须放在最顶层
* react 常用hook
useState, useEffect, useRef, useCallback, useMemo, useContext, useImperativeHandle
useState 2种用法
useState(初始值)
useState(() => {
return 值
})
useImperativeHandle + forwardRef 实现父组件调用子组件里的方法
* html语义化
ol: 有序列表
dl dt dd: 定义列表
p: 段落
h1 - h6: 标题
em: 强调(弱一点)
strong: 强调(强一点)
header: 定义页眉
footer: 定义页脚
article: 文档内的文章
* HTML5 新特性
canvas, svg, localStorage, sessionStorage, WebSocket, FormData, Worker,
pushState, replaceStat, audio, video
* 说说 title 和 alt 属性
1. 两个属性都是当鼠标滑动到元素上的时候显示
2. alt是img的特有属性, 是图片内容的等价描述, 图片无法正常显示时候的替代文字
* CSS 怎么清楚 float 浮动
1. 清除内浮动: zoom: 1; overflow: hidden
2. 清除外浮动: clear: both
* BFC 渲染规则
1. BFC垂直方向的距离重叠
2. BFC是一个独立的容器, 外面的元素不会影响里面的元素
* BFC 触发条件
1. 浮动元素 (元素的 float 不是 none)
2. 绝对定位元素 (元素的 position 为 absolute 或 fixed)
3. 行内块元素 (元素的 display 为 inline-block)
4. overflow 值不为 visible 的块元素 -弹性元素 (display为 flex 或 inline-flex元素的直接子元素)
* javascript 数据类型
boolean, null, undefined, number, string, symbol, object
* 0.1 + 0.2为什么不等于0.3 ?
因为计算机的浮点运算
实现方式: (0.1 * 100 + 0.2 * 100) / 100
* typeof 是否能正确判断类型 ?
1. 不能正确判断
2. 使用 toString.call(对象) 获取对象类型
3. is_js插件
* == 和 ===有什么区别
== 比较值, === 比较值 和 类型
* 闭包:
可以访问函数内变量的函数叫做闭包
因为全局变量指向了这个函数的指针,所以这个函数就是全局变量
全局变量不会被释放
释放方法:
接收闭包的变量=null
* 数组8种循环
forEach, filter, map, find, findIndex, reduce, some, every
forEach:
接收三个参数(item,index,array) 可以循环对象,不允许写return 不会改变原数组
filter:
有return (item,index,array)
会过滤掉数组中不满足条件的元素, 把满足条件的元素放到一个新数组中, 不改变原数组
map:
有return (item, index, array)
遍历数组, 会返回一个新数组, 不会改变原来数组里的内容
find:
有return (item,index,arr)
会返回数组中符合条件的第一个值,在数组中找到的话则不会往下执行
如果数组中没有符合条件的值则返回undefined
findIndex:
有return(item,index,arr)
返回满足条件的数组下标,没找到则返回-1
reduce:
有return(prev, cur, index, arr)
pre表示的是上一次回调时的返回值,或者是初始值init , cur当前正在处理的元素
不加默认值 cur从第二个值开始,加了则第一个
不加下标从1开始 加了下标从0开始
some:
循环查找数组中任意符合条件的元素并返回boolean值,
当数组中有任意元素符合条件就返回 true 否则返回 fasle
有 return 后面跟条件
(item,index,arr)
every:
循环查找数组中所有符合条件的元素并返回boolean值,
只有当数组中有所有元素都符合条件才返回 true 否则返回 fasle
有 return 后面跟条件
(item,index,arr)
* 普通函数 this定义:
this 代表当前正在执行的对象
* 箭头函数 this定义:
箭头函数没有自己的 this, 是在定义的时候获取上下文的 this
* JS中浅拷贝 和 深拷贝:
深拷贝: 递归 和 JSON.stringify, 其他都是浅拷贝, JSON.stringify 会过滤掉空值 一般不用
递归:
_.cloneDeep
浅拷贝方法: Object.assign, ...扩展运算符, Object.create,map
深拷贝:
深拷贝是指在拷贝对象时,创建一个新的对象,它的值和原始对象的值相同,但它们是独立的,修改其中一个对象的值不会影响另一个对象。深拷贝通常用于拷贝复杂对象,包括嵌套对象和引用对象。 在 JavaScript 中,深拷贝可以通过递归遍历对象的所有属性和子属性来实现。可以使用 JSON 对象的 stringify 和 parse 方法来实现深拷贝,也可以使用第三方库如 lodash、jQuery 等来实现深拷贝。
浅拷贝:
浅拷贝是指在拷贝对象时,只拷贝对象的引用,而不是对象本身。因此,原始对象和拷贝对象共享同一个引用,修改其中一个对象的值,会影响另一个对象的值。浅拷贝通常用于拷贝简单对象,比如数组、字符串等。
* js 事件循环机制:
基础任务, 宏任务, 微任务, 先执行基础任务, 然后执行 微任务, 再执行宏任务
微任务: promise, async, await
宏任务: setTimeout, setInterval, I/O
* 防抖, 节流:
防抖是让你多次触发, 只生效最后一次 适用于只需要一次触发生效的场景
function debounce(fn, delay){
let timer = null;
return function(){
clearTimeout(timer);
timer = setTimeout(()=> {
fn.apply(this, arguments);
}, delay)
}
}
节流是让你的操作, 每隔一段时间触发一次。适用于多次触发要多次生效的场景。
function throttle(fn, delay){
let valid = true;
return function(){
if(valid) {
setTimeout(()=> {
fn.apply(this, arguments);
valid = true;
}, delay)
valid = false;
}
}
}
* 如何在页面上实现一个圆形点击区域:
border-radius
* viewport
width 设置viewport宽度, 为⼀个正整数, 或字符串‘device-width’
device-width 设备宽度
height 设置viewport⾼度, ⼀般设置了宽度, 会⾃动解析出⾼度, 可以不⽤设置
initial-scale 默认缩放⽐例(初始缩放⽐例), 为⼀个数字, 可以带⼩数
minimum-scale 允许⽤户最⼩缩放⽐例, 为⼀个数字, 可以带⼩数
maximum-scale 允许⽤户最⼤缩放⽐例, 为⼀个数字, 可以带⼩数
user-scalable
* 浏览器内核
IE: trident 内核
Firefox: gecko 内核
Safari: webkit 内核
Opera: 以前是 presto 内核, Opera 现已改⽤Google - Chrome 的 Blink 内核
Chrome: Blink (基于 webkit, Google与Opera Software共同开发)
* 图片优化:
懒加载 雪碧图(怎么更改) icon base64 webp
* 请求报文
1. 请求协议 HTTP 请求地址
2. 请求方法 post
3. 请求头部
# 响应报文
1. HTTP响应报文也由三部分组成: 响应行、响应头、响应体
* display: none; visibility: hidden 区别:
none 完全不可见, hidden 元素不可见 但占用着空间
* css3 有哪些新特性:
transfrom, transition, animation, border-radius, box-shadow, flex,
will-change, ::before, ::after, columns
* css3 新增伪类
::after, ::before, :disabled, :focus, :checked :root
*:after :befor
使用方法: 元素后面加:after
p:after{
content:要插入的元素
设置元素属性
}
after可以清除浮动
* css3 动画:
1. transform: translate(移动) rotate(旋转) scale(缩放)
translate(x, y) 移动
translateX(x)
translateY(y)
translate3D(x, y, z)
2. transition:
css属性 执行时间 动画效果 延迟几秒执行
3. animation:
@keyframes 名称 {
0% {
margin-left: 100px;
width:100px;
}
40% {
margin-left: 0;
width:200px;
}
100% {
margin-left: 0;
width:200px;
}
}
animation:
名称 执行时间 动画 延迟执行时间 执行次数 direction : alternate
*animation和transition区别:
transition是过渡属性,强调过渡,他的实现需要触发一个事件(比如鼠标移动上去,焦点,点击等)才执行动画,过渡只有一组(两个:开始-结束)关键帧.
animation是动画属性,他的实现不需要触发事件,设定好时间之后可以自己执行,且可以循环一个动画(设置多个关键帧).
* 如何美化 checkbox:
-webkit-appearance: none
*
transform仅描述元素的静态样式,常常配合transition和animation使用
transition通常和hover等事件配合使用,animation是自发的,立即播放
animation可设置循环次数
animation可设置每一帧的样式和时间,transition只能设置头尾
transition可与js配合使用,js设定要变化的样式,transition负责动画效果
* rgba 和 opacity 区别:
rgba 只作用于当前元素
opacity 作用于所有元素
* 如何使用CSS实现硬件加速, GPU渲染
transfrom: translate3D(100, 0, 0): 写上Z轴 会使用伪 GPU渲染
will-change: 绝对的GPU渲染
* bind apply call 区别:
bind: 函数.bind(this, 参数) 返回一个绑定了this的新函数
// bind
const fn = function (a) {
console.log("a", a); //小鸡鸡
console.log("user", this.user); //我怕啊
};
const x3 = fn.bind({ user: "我怕啊" }, "小鸡鸡");
x3();
apply: 函数.apply(对象, [参数]) 改变 this 指针
call: 函数.apply(对象, 参数1, 参数2) 改变 this 指针
* 箭头函数的特点:
1. 箭头函数没有自己的this
2. 箭头函数不能当构造器使用
3. 箭头函数没有 arguments
4. 箭头函数在 new Person() 的时候 this指向当前实例
* in hasOwnProperty 区别:
in 操作符用来判断某个属性属于某个对象 可以是对象的直接属性 也可以是通过 prototype 继承的属性
hasOwnProperty 当前属性必须是 直接属性
* cookie localstorage session 区别:
1. cookie 是⽹站为了标示⽤户身份⽽储存在⽤户本地终端(Client Side)上的数据(通常 经过加密)
2. 请求接口会自动带上 cookie
3. sessionStorage 和 localStorage 不会⾃动把数据发给服务器, 仅在本地保存
4. cookie 数据⼤⼩不能超过4k
5. sessionStorage 和 localStorage 虽然也有存储⼤⼩的限制, 但⽐ cookie ⼤得 多, 可以达到5M或更⼤
6. localStorage 存储持久数据, 浏览器关闭后数据不丢失除⾮主动删除数据
7. sessionStorage 数据在当前浏览器窗⼝关闭后⾃动删除
8. cookie 设置的 cookie 过期时间之前⼀直有效, 即使窗⼝或浏览器关闭
* 浏览器缓存:
浏览器缓存分为强缓存和协商缓存
强缓存:
Expires (http1.0规范)
其值为服务器返回该请求结果缓存的到期时间,即再次发起该请求时,如果客户端的时间小于Expires的值时,直接使用缓存结果
Cache-Control:max-age
max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
协商缓存:
Last-Modified (值为资源最后更新时间, 随服务器response返回)
If-Modified-Since (通过⽐较两个时间来判断资源在两次请求期间是否有过修改, 如果没有修改, 则命中协商缓存)
ETag (表示资源内容的唯⼀标识, 随服务器 response 返回)
If-None-Match (服务器通过⽐较请求头部的 If-None-Match 与当前资源的 ETag 是 否⼀致来判断资源是否在两次请求之间有过修改, 如果没有修改, 则命中协商缓存)
什么是强缓存,什么是协商缓存?
浏览器缓存是指浏览器在第一次请求资源时,将资源的副本保存在本地存储器中,下次请求时直接从本地存储器中获取,避免了重复请求和下载,从而提高了网页的加载速度和用户体验。浏览器缓存分为强缓存和协商缓存两种方式,强缓存是指浏览器在本地缓存中查找资源,如果存在且未过期,则直接使用本地缓存,不再向服务器发送请求,否则向服务器发送请求;协商缓存是指浏览器向服务器发送请求时,服务器会返回资源的相关信息(如最后修改时间、ETag等),浏览器根据这些信息判断是否需要使用本地缓存,如果需要则发送请求,否则直接使用本地缓存。
* react 可不可以用map循环的index当做key:
可以, 但可能会有问题, 例如以前讲的小花, 小蓝, 小白那个表单例子, 所以最好使用唯一 id 或者给唯一 key
const [arr, setArr] = useState([1, 2, 3]);
const onClick = () => {
setArr(arr.filter((dt) => dt !== 2));
};
/*
删除前
{1}
{2}
{3}
删除后
{1}
{3}
index:
为什么会串行
定义一个数组
arr = [1,2,3]
循环遍历这个数组
return一个div 里面渲染dt和input 用index当key值
点击一个按钮删除第二个数据
虚拟dom和真实dom
进行diff算法
对比key 最外层不会重新渲染
里面变量判断 是否要渲染
input要进行判断,input 没有key 所以直接保留了
*/
return (
{arr.map((dt) => {
return (
{dt}
);
})}
);
不可以用时间戳当key值,因为react计算速度很快,会重复
不可以用随机数当key值,react的diff算法失去了意义
* react 在⽣命周期中的哪⼀步你应该发起 AJAX 请求:
useEffect 或者 componentDidMount
* shouldComponentUpdate 作用:
优化子组件是否渲染
return一个boolean值 如果为真则不渲染子组件,如果为假,则重新渲染子组件
* 页面埋点 PV, UV:
自定义一个调用方法 例如 sendPv 像如下传递参数
sendPv({
'baidu_sousuo_images': 'x1'
})
* 状态码:
200 表示从客户端发来的请求在服务器端被正确处理
204 No content 表示请求成功 但响应报⽂不含实体的主体部分
301 moved permanently 永久性重定向 表示资源已被分配了新的 URL
302 found 临时性重定向 表示资源临时被分配了新的 URL
304 not modified 表示使用本地缓存的资源
400 bad request 请求报⽂存在语法错误
401 unauthorized 表示发送的请求需要有通过 HTTP 认证的认证信息
403 forbidden 表示对请求资源的访问被服务器拒绝
404 not found 表示在服务器上没有找到请求的资源
500 internal sever error 表示服务器端在执⾏请求时发⽣了错误
501 Not Implemented 表示服务器不⽀持当前请求所需要的某个功能
503 service unavailable 表明服务器暂时处于超负载或正在停机维护 ⽆法处理请求
* RESTful规范
1. GET: 从服务器取出资源(一项或多项)
2. POST: 在服务器新建一个资源)
3. PUT: 在服务器更新资源(客户端提供改变后的完整资源)
5. DELETE: 从服务器删除资源
* 进公司之后 git 的配置
* git config --global user.name "git账号是公司给你新开的"
* git config --global user.email git右上角的名称
* 配置 公钥 私钥
ssh-keygen -t rsa -C "公司给你的登录账号"
cat ~/.ssh/id_rsa.pub // 打开公钥, 拷贝所有内容
* git clone: 拷贝 git 项目到本地
* git status: 查看本地文件状态
* git log: 查看提交日志
* git tig: 查看提交历史和分支结构
* git reflog: 查看所有日志,任何操作
* git add .: 跟踪文件 把代码保存到缓冲区
* git commit -m '描述文字(有意义的)': 把项目提交到本地仓库
* git push origin 分支名: 提交 (当前在哪个分支下面 就只能往当前这个分支 push)
* git branch -v: 查看本地分支, *号表示当前在哪个分支上
* git branch -a: 查看本地和远程的分支
* git checkout -b 分支名: 基于本地分支创建自己本地的分支
* git checkout 分支名: 切换分支 (只有当前分支上没有任何修改了 才能切换分支)
* git checkout -b 分支名 origin/分支名: 基于远程分支创建自己本地的分支
* git pull origin 分支名: 拉取最新代码
* git fetch: 同步远程分支
* git diff: 比较代码
* git reset --hard commit哈希值: 回滚代码
* git stash save '描述': 缓存 stash
* git stash list: 查看存储的栈列表
* git stash apply stash@{1}: 回到某一个存储上 从0开始
* git stash apply: 回到最近储藏
* git reset --hard commit(哈希值) : 查看提交历史和分支结构 (可能会把同事的代码弄没)
* git reset --mixed HEAD~1: 回到操作之前的状态
* 如果reset的时候把同事的代码弄没了怎么办
1. 重新从远程拉取代码
2. 使用git reflog 查看你覆盖内步的操作,然后通过reset撤回
* git 提交规范
* master: 主分支(上线)
* hotfix: 线上有bug 修改bug的分支
* release: 预发布
* develop: 开发分支
* feature 项目类型 + 时间: feature/项目名0530
一个项目下来 基于 master 创建一个 feature/项目名0530, 如果多人开发 基于 feature/项目名0530 创建自己的分支
* feat: 新功能 新特性 (git commit -m 'feat: 描述文字') 1
fix: 修改 bug
perf: 更改代码 以提高性能(在不影响代码内部行为的前提下 对程序性能进行优化)
refactor: 代码重构(重构 在不影响代码内部行为 功能下的代码修改)
docs: 文档修改
master 上线分支
release -> master
release <- develop
* react vue 区别:
1. 响应式原理不同
vue: vue会遍历data数据对象, 使用Object.definedProperty 将每个属性都转换为getter和setter
每个Vue组件实例都有一个对应的watcher实例, 在组件初次渲染的时候会记录组件用到了那些数据, 当数据发生改变的时候,
会触发setter方法, 并通知所有依赖这个数据的watcher实例调用update方法去触发组件的compile渲染方法, 进行渲染数据
react: React主要是通过setState()方法来更新状态, 状态更新之后, 组件也会重新渲染
2. 监听数据变化的实现原理不同
vue: Vue通过 getter/setter以及一些函数的劫持, 能精确知道数据变化
react: React默认是通过比较引用的方式(diff)进行的
3. Diff算法不同
vue和react的diff算法都是进行同层次的比较, 主要有以下两点不同:
vue对比节点, 如果节点元素类型相同, 但是className不同, 认为是不同类型的元素, 会进行删除重建, 但是react则会认为是
同类型的节点, 只会修改节点属性
vue的列表比对采用的是首尾指针法, 而react采用的是从左到右依次比对的方式, 当一个集合只是把最后一个节点移动到了第一个,
react会把前面的节点依次移动, 而vue只会把最后一个节点移动到最后一个, 从这点上来说vue的对比方式更加高效
* 设计模式:
观察者模式, 策略模式, 单例 多例模式, 迭代器模式, 工厂模式
* dva的使用方式:
namespace, state, reducers, effects, 具体的参数使用方法也要背出来
* flex:
flex-direction: 设置主轴方向
row 默认 从左到右
row-reverse 从右到左
column 从上到下
column-reverse 从下到上
justify-content: 伸缩项目在主轴上的对齐方式
flex-start 默认 向伸缩容器的起始位置对齐
flex-end 向伸缩容器的终点位置对齐
center 向伸缩容器的中间位置对齐
space-between 伸缩项目平均分布 两端对齐
space-around 伸缩项目平均分布 两端保留一半空间
align-items: 伸缩项目在侧轴上的对齐方式(对单行对齐进行控制)
flex-start 测轴的起始位置
flex-end 测轴的结束位置
center 测轴中心位置
baseline 基线对齐
stretch 默认 没设置高度 伸缩项目默认填充整个容器
* columns: 列数和列宽
column-count: 列数
column-width: 宽度(宽度和列数都有的情况下以列数为准)
column-gap: 列间距(类似margin)
column-rule: 设置列之间的样式
* 如何截取多行文字
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
* Promise
Promise: 解决回调地狱
三种状态: 进行中, 已成功, 已失败, 状态一旦固定了 状态就永远不会再变了
Promise.reject 立刻拿到一个 已失败的 promise
Promise.resolve 立刻拿到一个 已成功的 promise
Promise.all([p1, p2, p3]) 返回一个 promise 实例
可以确定所有请求都成功了,但是只要有一个请求失败,它就会报错,而不管另外的请求是否结束。
Promise.race([p1, p2, p3])
只要有一个状态率先改变 那么race返回的状态就跟着改变
Promise.prototype.finally()
不管成功失败都执行到finally里面
Promise.allSettled([a,b,c])
用来确定一组异步操作是否都结束了(不管成功或失败)
Promise.any()
接收一个数组,只要数组中有一个promise成功了,就变为成功,都失败才变成失败
* position有哪些属性:
absolute, sticky(粘性定位), fixed, relative
* 同一个项目在不同浏览器 tab 间同步信息:
window.addEventListener('storage', () => {
// 执行逻辑
})
* 如何实现单点登录:
方法1: 设置cookie domian
方法2: 通过使用 postMessage 和 iframe实现
* 移动端如何做手机适配:
可以使用 vh 或者 rem, 引入一个阿里js, 在html上自己计算一个 font-size
* 移动端如何做绝对一像素:
方案1: 设置 meta viewport 属性 整个页面 initial-scale: 0.5
方案2: 单独设置当前元素 tranform: scale(0.5);
* 重绘和回流
重绘: DOM树没有元素增加或删除, 只是样式的改变, 针对浏览器对某一元素进行单独的渲染, 这个过程就叫做重绘
回流: DOM树中的元素被增加或者删除, 导致浏览器需要重新的去渲染整个DOM树, 回流比重绘更消耗性能, 发生回流必定重绘, 重绘不一定会导致回流
引起回流
添加或者删除可见的DOM元素
元素的位置发生变化
元素的尺寸发生变化(包括外边距、内边距、边框大小、高度和宽度等)
内容发生变化 文本或者图片被另一个不同尺寸的图片所代替
页面开始渲染的时候
浏览器的窗口尺寸变化(回流是根据视口的大小来计算元素的位置和大小)
引起重绘
color
border-style
visibility
background
text-decoration
background-image
background-position
background-repeat
outline-color
outline
outline-style
border-radius
outline-width
box-shadow
background-size
* 怎么减少重绘 回流
1. css
1). 不要使用 table 布局,可能很小的一个改动会造成整个 table 的重新布局
2). 集中改变样式className
3). 使用 position: absolute / fixed; 脱离文档流
4). 利用 transform translate 去代替 left top
5). 避免使用CSS表达式 例如: calc()
* js
1). 动态插入多个节点时,可以使用文档碎片(DocumnetFragment),创建后一次插入,避免多次的渲染性能
2). 使用 resize 事件时,做防抖和节流处理
3). 可以先为元素设置为不可见: display: none, 操作结束后再把它显示出来。
* React 父子组件传值方式:
1. props
2. Context
3. redux
4. 发布订阅
5. useImperativeHandle + forwardRef
* 发布订阅:
// 发布订阅
const login = {
list: {},
// 发布
publish(key) {
console.log('a', this.list[key]);
this.list[key].map(dt => {
dt()
})
},
// 订阅
ding(key, value) {
if (!this.list[key]) {
this.list[key] = []
}
this.list[key].push(value)
}
}
// 张波
function Xx() {
function abc() {
console.log('abc');
}
function xxx() {
console.log('xxx');
}
// 订阅
login.ding('pt', abc)
login.ding('pt', xxx)
}
Xx()
export default function Issue(props) {
const zhang = () => {
// 发布
login.publish('pt')
}
return (
)
}
* 前端权限: 静态权限, 动态权限
1. 静态权限实现方案:
前端先记录一个路由权限数组, 例如
const obj = [
pt: ['/a1', '/a2'],
vip: ['/vip1', '/vip2'],
]
然后登录以后后台返回一个该用户的权限值, 例如 pt, 然后前段通过 obj 匹配该用户能访问的路由列表, 如果能匹配到值则
用户访问该路由, 否则不能访问该路由
2. 动态路由实现方案:
前端不记录权限数组, 后台直接返回一个 Menu 列表, 前端递归解析列表数据, 展示 menu菜单
* redux 原理
let createStore = (reducer) => {
let state;
//获取状态对象
//存放所有的监听函数
let listeners = [];
let getState = () => state;
//提供一个方法供外部调用派发action
let dispath = (action) => {
//调用管理员reducer得到新的state
state = reducer(state, action);
//执行所有的监听函数
listeners.forEach((l) => l())
}
//订阅状态变化事件,当状态改变发生之后执行监听函数
let subscribe = (listener) => {
listeners.push(listener);
}
dispath();
return {
getState,
dispath,
subscribe
}
}
let combineReducers = (renducers)=>{
return function(state={},action={}){
let newState={};
for(var attr in renducers){
newState[attr]=renducers[attr](state[attr],action)
}
return newState;
}
}
export { createStore, combineReducers };
* CSS 命名冲突解决方案:
1. css-module
将样式文件引入style里面 使用方法: style.title 会将title编译为一个哈希值
2. css in js
需要定义一个js文件 抛出css样式 在要用的文件里引入 以组件包裹的方式应用
3. react-css-modules
* Websocket: 长链接
const ws = new WebSocket('ws://地址')
wss 加密地址
事件
open: ws.onopen 连接建立时触发
message: ws.onmessage 客户端接收服务端数据时触发
error: ws.onerror 通信发生错误时触发
close: ws.onclose 连接关闭时触发
ws.onopen = function () {
// Web Socket 已连接上,使用 send() 方法发送数据
ws.send("发送数据");
alert("数据发送中...");
}
ws.onmessage = function (evt) {
var received_msg = evt.data;
alert("数据已接收...");
}
ws.onclose = function () {
// 关闭 websocket
alert("连接已关闭...");
}
* 心跳检测:
检测前端和后台的链接是不是还存在,如果已经断开 通知后台,后台关闭连接
实现:每隔一段时间调用 send()
* 前台路由 后台路由区别
前台路由是页面路由
后台路由是接口
* XSS漏洞:
用户使用表单提交的方式 提交恶意的 javascript 代码
* 做项目流程
1. 项目评审 大概2-3次
2. UI出图
3. 前端 后台给出具体的确定排期
4. QA 给出测试排期
5. 提测改bug
6. 发布上线, 跟踪线上问题
* 浏览器渲染html的过程
https://www.cnblogs.com/whalesea/p/10980849.html
1、解析html
2、构建dom树
3、dom树结合css文件,构建呈现树
4、布局
5、绘制
* 链表:
单向链表, 双向链表, 循环链表
* 用过哪些e6:
* 对象 e6 新属性:
Ocject.keys(obj) 输出所有key的数组 [user,age]
Ocject.values(obj) 输出所有值的数组 [1,2]
Object.entries(obj) 输出[[user,1],[age,2]
Object.defineProperties(obj, props)
例:
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true, // 值
writable: true // 是否可读写
},
'property2': {
value: 'Hello',
writable: false
}
});
* async:
async function fn () {
const x1 = await 方法()
const x2 = await 方法()
}
await 相当于then
如果后面跟的方法返回的是报错,就不会执行下一步
trycatch方法
async原理:
function spawn(genF) {
return new Promise(function(resolve, reject) {
const gen = genF();
function step(nextF) {
let next;
try {
next = nextF();
} catch(e) {
return reject(e);
}
if(next.done) {
return resolve(next.value);
}
Promise.resolve(next.value).then(function(v) {
step(function() { return gen.next(v); });
}, function(e) {
step(function() { return gen.throw(e); });
});
}
step(function() { return gen.next(undefined); });
});
}
* react 脚手架:
1. umi + Dva
2. create-react-app
3. next.js
* react 状态管理工具:
1. mobx
2. Dva
3. redux
4. redux-saga
* mobx 与 redux 的区别:
mobx,dva,redux区别:
mobx:
1. 多store
2. 可观察数据
dav redux 单store 不可观察
dva:底层是 redux-saga
写法:
redux:
actions
reducers
dav:
namespace
state 定义数据
reduce 修改state
effect 用Generator写
* 项目上传
使用 阿里云
* add(1)(2)(3)
function add (a) {
return b => {
return c => {
return a + b + c
}
}
}
* fetch axios 区别:
fetch 是浏览器自带的
fetch只对网络请求报错 对400 500都当做成功的请求
fetch默认不会带cookie
fetch不支持 abort 不支持超时控制
axios 体积小 没有fetch的这些问题
* :root用法: 自定义属性
:root {
--名字
}
// 引用
var(--名字)
* css3动画(怎么说):
transform transition animation @keyframes, transform一般是和transition联用,
transform 包括 translate translateX translateY translate3D, 我们平时用 translate3D(0, 0, 0)
translate3D 有伪GPU渲染, rotate, scale, transition css属性 执行时间 执行动画 延迟的执行时间.
animation 和 @keyframes联用, @keyframes 名字 里面是从0%开始一直设置到100%, animation: 名字 执行时间
执行动画 延迟时间 执行次数 正反是否都有动画, transform 需要事件触发, animation自动执行
div {
transform: translate3D(x, y, z);
transition: transform ....
}
div:hover {
transform: translate3D(x, y, z);
}
* css插件:
使用 normalize.css(normalize.css 解决浏览器的 css 兼容问题), 不用 reset.css
* umi4 && umi3区别
* umi4 只能通过 plugin.ts 配置
* useLocation, useParams, useSearchParams
* 支持 vue
* 默认集成 react18, router6
* 支持 vite webpack 2种构建方式
* children 改成了
* 构建速度更快
* axios特点:
基于promise的异步ajax请求库
浏览器端/node端都可以使用
支持请求/响应拦截器
支持请求取消
请求/响应数据转换
批量发送多个请求
* git merge, git rebase 区别
git merge:
记录下合并动作,很多时候这种合并动作是垃圾信息
不会修改原 commit ID
冲突只解决一次
分支看着不大整洁,但是能看出合并的先后顺序
记录了真实的 commit 情况,包括每个分支的详情
git rebase:
改变当前分支 branch out 的位置
得到更简洁的项目历史
每个 commit 都需要解决冲突
修改所有 commit ID
* 反问:
hr:
1. 上下班时间
2. 五险一金
3. 一年是多少薪
技术:
1. 技术栈
2. 公司有多少前端
3. 如果我有幸入职,会负责那些项目,项目的技术栈
4. 大概多久会给我反馈
* nginx 配置反向代理:
server {
listen 80;
server_name 192.168.17.129;
location / {
// nginx 监听 server_name 转到proxy_pass配置的对应服务器上
proxy_pass http://127.0.0.1:8080
}
}
* ToB ToC
ToB即面向企业
ToC即面向普通用户
BtoB: (企业面向企业) 阿里巴巴
BtoC: (企业面向用户) 抖音 小程序
CtoC: (用户面相用户) 淘宝店铺
* 移动端基准 720 x 1280
* CSS 的优化
1. umi 异步加载 css 拆包
2. 通过 webpack 的 CommonsChunkPlugin 拆包
3. css3
4. 解决冲突3个插件
5. 减少回流与重绘
6. 不适用 expression
* 为什么JS是单线程的还能够执行异步操作:
因为浏览器是多线程的, Ajax请求确实是异步的 这请求是由浏览器新开一个线程请求 所以不会阻塞js
* 面相对象编程: 设计模式的单一职能原则, 把最小的功能封装成函数 进行复用
* undefinde null x
1. null == undefined // true
null === undefined // false
2. typeof undefined // undefined
typeof null // object
* 浅比较: === 是浅比较
深比较: 深比较也称原值相等 深比较是指检查两个对象的所有属性是否都相等, 深比较需要以递归的方式遍历两个对象的所有属性
*
pushState : 将当前URL和history.state加入到 history 中 并用新的state和URL替换当前
state : 与要跳转到的URL对应的状态信息
title : 目前没有浏览器支持 可以留空
url : 要跳转的url地址 不能跨域
history.pushState('a=1&b=2', '', '/xxx/login');
// onpopstate : 回退 前进触发该事件
window.onpopstate = function (e){
if (e === '/xxx/login') {
setX(
}
if (e === '/index') {
setX(
}
};
* Worker: 创建一个新线程 (大量的计算)
new Worker(加载一个js文件), 在js文件里执行逻辑
worker.onmessage = function (e){
e.data // 获取数据
}
* canvas svg:
1. canvas 可以兼容全部浏览器 主要做位图 (jpg, webp)
2. svg 不兼容低版本浏览器, 矢量图
* 高阶函数 (高阶函数是指至少满足下列条件之一的函数):
1. 函数可以作为参数被传递
2. 函数可以作为返回值输出
* 自定义指令
directives: {
focus: {
// inserted: 被绑定元素插入父节点时调用
inserted: function (el) {
el.focus()
},
// 只调用一次,指令第一次绑定到元素时调用
bind: function () {
},
// 所在组件的 VNode 更新时调用
update: function () {
}
}
}
* 线上js代码执行出错, 怎么捕获这个错误进行其他操作
1. chrome sources 打断点
2. 写错误边界
3. 第三方的错误监听网站 例如 fundebug:
用户行为记录: 用户怎么操作的产生了错误
Source Map: 报错定位到 react 具体哪行
* forEach怎么停止循环:
1. break
2. throw new Error() 抛出异常
* js的垃圾回收机制:
1. 标记清除: 是当变量进入环境时 将这个变量标记为"进入环境" 当变量离开环境时 则将其标记为"离开环境" 标记"离开环境"的就回收内存
2. 引用计数: 跟踪记录每个值被引用的次数
声明了一个变量并将一个引用类型的值赋值给这个变量 这个引用类型值的引用次数就是1
同一个值又被赋值给另一个变量 这个引用类型值的引用次数加1
当包含这个引用类型值的变量又被赋值成另一个值了 那么这个引用类型值的引用次数减1
当引用次数变成0时 说明没办法访问这个值了
当垃圾收集器下一次运行时 它就会释放引用次数是0的值所占的内存
// { } 123
const x1 = {} // 引用次数 1
const x2 = x1 // 引用次数 2
x1 = 小花 // 引用次数减一