【跳槽月】2月完结
跳槽月:把自己当做 30 岁来活,30 岁的自己会感谢 24 岁的你,加油 🆙
# 2.28
# ts学习
# 类型判断
- typeof 基本类型, 注意 null 返回 object,因为 null 是 000000,object 前几位也全是 0
- instanceof 原型链判断, 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型。比如通过 new String 出来的字符串和直接写的字符串''
- Object.prototype.toString, 最准确。甚至可以把 document 和 window 都区分开来。
Object.prototype.toString.call(document); //"[object HTMLDocument]"
Object.prototype.toString.call(window); //"[object Window]"
2
# 2.27
找房子去了,和各个前端大佬聚了一波。
# 2.26
# ts学习
# 2.25
# 工作交接
很尴尬的是,都没人想接
# 实习生面试
感觉妹子和我有一拼,答非所问,罗里吧嗦。。。。
# 2.24
# react render中跳转
<Redirect to='/login'></Redirect>
# 项目完成首页布局搭建
慢慢的感觉react还是很香的
# 工作交接
公司的hp笔记本重置交回去了,24寸1080显示器也还回去了。接下来就用ipad的随航了
谁都没想到,公司居然把我背了近三年的书包要回去了,hhh,nbplus
# 2.23
# 学习react hooks
总结性的单独拉一篇,不能都在日记写,日记写总结性东西。先了解下,等写多了再深入
- useState, 创建与修改变量
- useEffect, 监听某些变量,类似与vue watch
- useContext,创建上下文,可以用于传值,类似与vue provide和inject
- useReducer,状态管理,state和reducer,通过dispatch触发对应的修改,和vuex相似
- useCallback,类似与函数柯里化,返回带有缓存的函数,依赖项发生变化才触发
- useMemo 和上一个相同,不过做了优化
- useRef 获取dom,不过可以变化的那种
# 项目练习
zent和antd写法不同,先练习下
# 2.22
# react + zent
项目搭建,写了个登录页面。写的时候磕磕碰碰,之前学的 react,忘的差不多了,晚上复习一波;
# react 引入图片
import imgURL from './../images/photo.png';
<img src={imgURL } />
// 或者
<img src={require('./../images/photo.png')} />
2
3
4
# created-react-app
- 创建 ts 应用:
npx create-react-app appName --template typescript
- 暴露默认配置(不可逆):
npm run eject
- 默认支持 scss,less 需要按照 scss 的配置加一下
# react-router 配置
import { BrowserRouter, Route, Switch } from "react-router-dom";
class App extends React.Component {
render() {
return (
<BrowserRouter>
<Switch>
<Route path="/" component={Login}></Route>
<Route path="/login" component={Login}></Route>
<Route path="/home" component={Home}></Route>
</Switch>
</BrowserRouter>
);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# react-router 跳转
import { useHistory } from "react-router-dom";
function HomeButton() {
let history = useHistory();
function handleClick() {
history.push("/home");
}
return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 2.21
早上十点到杭州,下午睡了一觉,晚上出去逛了一趟~~~, 没了
# 2.20
# 回杭州
# react 学习
# 2.19
# 交接文档梳理
# react
# 2.18
# 爷爷最后一场事,办完就结束了
# 2.17
# js 类
- 构造器 constructor,不是必须的
- 如果 A 类继承了 B 类,且 A 类中写了构造器 constructor,那么 A 的构造器中 super 必写,不然报错
- 类定义的方法都是放在原型链上的,继承也是借助原型链查找实现的。可在子类中重写方法,原型链查找不会找到父类的方法,达到覆盖的目的
# 有赞面经
终于写完了,hhh。明天忙家里事情了,加油!!!!
# 2.13 - 2.16
- 2.13 约了朋友去宋城玩,本来晚上 7 点的演出。4 点接到爷爷病危的通知,就感觉回家了,晚上九点多的火车
- 2.14 弟弟开车来火车站接我,早上六点多到家,开始处理后事。
- 2.15 守夜
- 2.16 出棺,晚上早点回来了写了写交接文档。
# 2.12
# 面经总结
主要听之前的录音,做了部分面经总结,明天晚上继续。白天去宋城逛逛
# 学习计划
分配的部门应该是 toB,用 react,得好好练习下
准备用 React + TS + Zent(有赞 reactUI 库)+ Zan-Proxy(提前熟悉下) 做做项目
# 2.11 (除夕)
领导同意了离职,确认了时间
没学习,没回老家,和女朋友玩了一天
# 2.10
# 浏览器的并发请求限制?为什么
- 浏览器的并发请求数目限制是针对同一域名的,如果想要突破这个限制,换成不同域名即可。比如图片资源放在不同的域名下
- 如果不限制,多个请求一起发,线程开销比较大
- 服务器接收多个请求可能也会有性能问题,尽管可以负载均衡 参考文章:浏览器同域名请求的最大并发数限制 (opens new window)
# 浏览器 http 请求的并发性是如何体现的?并发请求的数量有没有限制?
页面资源请求时,浏览器会同时和服务器建立多个 TCP 连接,在同一个 TCP 连接上顺序处理多个 HTTP 请求。所以浏览器的并发性就体现在可以建立多个 TCP 连接,来支持多个 http 同时请求。
Chrome 浏览器最多允许对同一个域名 Host 建立 6 个 TCP 连接,不同的浏览器有所区别。
# 一个 TCP 连接可以同时发送几个 HTTP 请求?
- HTTP/1.1 中,单个 TCP 连接,在同一时间只能处理一个 http 请求,虽然存在 Pipelining 技术支持多个请求同时发送,但由于实践中存在很多问题无法解决,所以浏览器默认是关闭,所以可以认为是不支持同时多个请求。
- HTTP2 提供了多路传输功能,多个 http 请求,可以同时在同一个 TCP 连接中进行传输。
# 二叉树的几种遍历
- 前序遍历:先访问根节点——左子树——右子树
- 中序遍历:先左子树——根节点——右子树
- 后序遍历:先左子树——右子树——根节点
# 基础排序
- 冒泡排序:双层遍历,对比前后两个节点,如果满足条件,位置互换,直到遍历结束。
- 快速排序:去数组中间的那一个数,然后遍历所有数,小于该数的 push 到一个数组,大于该数的 push 到另外一个数组,然后递归去排序这两个数组,最后将所有结果连接起来。
- 选择排序:声明一个数组,每次去输入数组里面找数组中的最大值或者最小值,取出来后 push 到声明的数组中,直到输入数组为空。
# 2.9
# git rebase
- 合并多次 commit 记录
git rebase -i HEAD~4
注意不要合并先前提交的东西,也就是已经提交远程分支的纪录 - 合并分支
git rebase master
,相比较git merge master
会去除一些 merge 记录,分支记录更干净 git rebase —abort
分支会回到 rebase 开始前的状态- 将某一段 commit 粘贴到另一个分支上
git rebase [startpoint] [endpoint] --onto [branchName]
- git rebase 是一个危险命令,可能会丢失记录
git-rebase
存在的价值是:对一个分支做「变基」操作
# nginx 负载均衡策略
- 轮询(默认)
- 权重 weight
- ip_hash( IP 绑定)
- fair(第三方插件)
- url_hash(第三方插件)
# 2.8
# vue3 的一些变化
- 原来是通过 new Vue 的方法来初始化 Vue,在 Vue3.0 中,修改为了通过 createApp 的方式
createApp(App).mount('#app')
- vite 冷启动技术无敌,利用浏览器原生属性 type='module',真正的按需编译
- 生命周期变化: setup(props, context)代替 beforeCreate 和 created,其他生命周期都加了前缀 on, destroyed 换成了 onUnmounted
- 很多写法和 react 相似
# vue router
import { createRouter, createWebHashHistory } from "vue-router";
// 在 Vue-router新版本中,需要使用createRouter来创建路由
export default createRouter({
// 指定路由的模式,此处使用的是hash模式
history: createWebHashHistory(),
// 路由地址
routes: [],
});
2
3
4
5
6
7
8
# vueX
import { createStore } from "vuex";
interface State {
userName: string;
}
export default createStore({
state(): State {
return {
userName: "俊劫",
};
},
});
2
3
4
5
6
7
8
9
10
11
12
参考文章:学习 Vue3.0,先从搭建环境开始 (opens new window)
# sum(2, 3)实现 sum(2)(3)的效果
1、闭包,无法处理 sum(2)(3)(4)
function sum(x) {
let res = 0;
res = res + x;
return function(y) {
res = res + y;
return res;
};
}
sum(2)(3); // 5
2
3
4
5
6
7
8
9
2、利用 arguments,判断参数输入,如果没有参数输入的话,就返回总和,而不是返回函数。确定需要执行空()
function sum(x) {
let res = 0;
res = res + x;
return function temp(y) {
if (arguments.length === 0) {
return res;
} else {
res = res + y;
return temp;
}
};
}
sum(2)(3)(4)();
2
3
4
5
6
7
8
9
10
11
12
13
3、重写 sum 函数的 toString 和 valueOf 方法
function sum(x) {
let res = 0;
res = res + x;
var temp = function(y) {
res = res + y;
return temp;
};
temp.toString = temp.valueOf = function() {
return res;
};
return temp;
}
sum(1)(2)(3); // 6
2
3
4
5
6
7
8
9
10
11
12
13
# 2.7
# POST,PUT 和 PATCH 的区别
POST 和 PUT 的区别容易被简单地误认为“POST 表示创建资源,PUT 表示更新资源.但实际上两者都可以用来创建或是更新数据.单从技术上来说,他们并没有什么区别.
POST 是非幂等的,多次调用会产生不同的结果
PUT 是幂等的,调用一次和 N 次对系统产生的副作用是相同的
PATCH 一般是用来局部更新资源的
# 暂时性死区
- ES6 规定,let/const 命令会使区块形成封闭的作用域。若在声明之前使用变量,就会报错。
- 总之,在代码块内,使用 let 命令声明变量之前,该变量都是不可用的。
- 这在语法上,称为 “暂时性死区”( temporal dead zone,简称 TDZ)。
var num = 1;
if (true) {
num = "a"; // Error: Uncaught ReferenceError: num is not defined
let num;
}
2
3
4
5
因为在 if 中声明了一个局部变量 num , 导致暂时性死区,if 里的 num 则与这个块级作用域绑定,不再受全局变量 num 影响,同时 let 不存在变量提升,所以在 let 前赋值的 num 是非法的。const 与之同理。
# 浅拷贝
- object.assign
- 扩展运算符方式
- concat 拷贝数组
- arr.slice() 拷贝数组
let target = {};
let source = { a: { b: 1 } };
Object.assign(target, source);
console.log(target); // { a: { b: 5 } };
// 修改已有属性会相互影响
source.a.b = 5;
console.log(source); // { a: { b: 5 } ,c: 1};
console.log(target); // { a: { b: 5 } };‘
// 增加属性互补影响
source.c = 1;
console.log(source); // { a: { b: 5 } ,c: 1};
console.log(target); // { a: { b: 5 } };
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# JS 高精度 计时器
var start = new Date().getTime();
var count = 0;
//占用线程事件
setInterval(function() {
var j = 0;
while (j++ < 100000000);
}, 0);
//定时器测试
setInterval(function() {
count++;
console.log(new Date().getTime() - (start + count * 1000));
}, 1000);
2
3
4
5
6
7
8
9
10
11
12
13
14
由于加了很占线程的阻塞事件,导致定时器事件每次执行延迟越来越严重,实际输出 200 - 3000 不等.
由于实际项目中,执行计时器的同时,会有很多其他异步阻塞事件,会导致倒计时功能不精确。
解决思路:通过引入计数器,判断计时器延迟执行的时间来调整,尽量让误差缩小,不同浏览器不同时间段打开页面倒计时误差可控制在 1s 以内。
var start = new Date().getTime(),
time = 0,
elapsed = "0.0";
function instance() {
time += 100;
elapsed = Math.floor(time / 100) / 10;
if (Math.round(elapsed) == elapsed) {
elapsed += ".0";
}
document.title = elapsed;
var diff = new Date().getTime() - start - time;
window.setTimeout(instance, 100 - diff);
}
window.setTimeout(instance, 100);
2
3
4
5
6
7
8
9
10
11
12
13
14
参考文章:
# 2.6
买了门课, 【JavaScript 核心原理精讲】看一波
# http 协议中 301 和 302 的区别
- 301 代表资源的永久重定向,302 代表资源的临时重定向
- 很多的第三方授权,授权过后的回跳地址经常会使用 301 形式,改变浏览器的回跳地址。
# 单个 input enter 会刷新页面
- 写一个隐藏的 input
- el-form @submit.native.prevent
- 屏蔽回车键,比较 low
# 正则表达式符号,老是忘
- ^以什么为开始
- \s 匹配任意的空白符
- _只匹配出现 0 次及以上 _ 前的字符
- ()分组 []匹配方括号内的任意字符
- ?之前字符可选
- \d 匹配数字
- +只匹配出现 1 次及以上 + 前的字符 .匹配任意字符除了换行符和回车符(贪婪匹配)
# 2.5
# lodash _get()实现
访问 a.b.c.d.e 报错处理,最新的语法可以写:a?.b?.c?.d?.e 来访问,但是语义不明确,兼容性要求较高。
使用 lodash get 较好
function get(source, path, defaultValue) {
const paths = path.replace(/\[(\d+)\]/g, ".$1").split(".");
let result = source;
for (const p of paths) {
result = Object(result)[p];
if (!result) {
return defaultValue;
}
}
return result;
}
2
3
4
5
6
7
8
9
10
11
# 计算时区
迷迷糊糊
// 将一天24小时按每半小划分成48段,我们用一个位图表示选中的时间区间,
// 例如`110000000000000000000000000000000000000000000000`,
// 表示第一个半小时和第二个半小时被选中了,其余时间段都没有被选中,
// 也就是对应00:00~01:00这个时间区间。一个位图中可能有多个不连续的
// 时间区间被选中,例如`110010000000000000000000000000000000000000000000`,
// 表示00:00-1:00和02:00-02:30这两个时间区间被选中了。
// 要求:写一个函数timeBitmapToRanges,将上述规则描述的时间位图转换成一个选中时间区间的数组。
// 示例输入:`"110010000000000000000000000000000000000000000000"`
// 示例输出:`["00:00~01:00", "02:00~02:30"]`
function format(start, end) {
let endHour = (end / 2).toFixed(1);
let startHour = (start / 2).toFixed(1);
let reg = /(\d+)\.(\d+)/;
const endRes = endHour.match(reg);
const startRes = startHour.match(reg);
return (
addZero(startRes[1]) +
":" +
addZero(startRes[2]) +
"~" +
addZero(endRes[1]) +
":" +
addZero(endRes[2])
);
}
function addZero(num) {
num = num === "5" ? "30" : num;
return num.length > 1 ? num : "0" + num;
}
function timeBitmapToRanges(timeBitmap) {
let timeArr = timeBitmap.split("").map((v) => +v);
const res = [];
let range = {};
let start = 0;
for (let i = 0; i <= timeArr.length; i++) {
if (timeArr[i]) {
start++;
}
if (!timeArr[i] && timeArr[i - 1]) {
range[i] = start;
start = 0;
}
}
for (let j in range) {
res.push(format(parseInt(j - range[j]), parseInt(j)));
}
return res;
}
console.log(
timeBitmapToRanges("110010000000000000001110000000000000000000000111")
);
// [ '00:00~01:00', '02:00~02:30', '10:00~11:30', '22:30~24:00' ]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 实现 getValue 函数来获取 path 对应的值
var object = { a: [{ b: { c: 3 } }] }; // path: 'a[0].b.c'
var array = [{ a: { b: [1] } }]; // path: '[0].a.b[0]'
function getValue(target, valuePath, defaultValue) {
let res = "";
if (Object.prototype.toString.call(target) === "[object Object]") {
let pathArr = valuePath.split("."); // [a[0],b,c]
pathArr.forEach((item) => {
if (item.includes("[")) {
let iItem = 0;
item.match(/[0-9]/g, function($0) {
iItem = $0;
});
let key = item.split("[")[0];
res = target[key][iItem];
} else {
res = res[item];
}
});
}
// 数组处理有点问题。后面再想想
// if(Array.isArray(target)) {
// target.forEach(item => {
// getValue(item)
// })
// };
return res || defaultValue;
}
console.log(getValue(object, "a[0].b.c", 0)); // 输出3
// console.log(getValue(array, '[0].a.b[0]', 12)); // 输出 1
// console.log(getValue(array, '[0].a.b[0].c', 12)); // 输出 12
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 2.4
# 提醒自己保持学习
# lodash 源码加入学习计划
# 天天开会太忙了,年后都安排满了,周六恶补一下
# 实现 isEqual 函数 思路
要考虑的情况很多,可以参考 lodash 的实现
- +0 -0 ,NaN, null undefined 都可以用 Object.is 判断
- 对象 Object.prototype.toString.call === [object Object] 注意第二个 Object O 大写
只考虑对象和数组,基本就是递归的思想
function isEqual(a, b) {
// 只考虑对象,或者数组
if (areArrays) {
length = a.length;
if (length !== b.length) return false;
while (length--) {
if (!eq(a[length], b[length])) return false;
}
} else {
var keys = Object.keys(a),
key;
length = keys.length;
if (Object.keys(b).length !== length) return false;
while (length--) {
key = keys[length];
if (!(b.hasOwnProperty(key) && eq(a[key], b[key]))) return false;
}
}
return true;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 2.3
# 页面白屏 loading
spa 应用可以直接在容器里面写,当 vue、react 挂载阶段完成以后,会替换掉其中的内容,自动移除掉 loading 了。
<div id="app">
<div id="loadding"></div>
</div>
2
3
# vite 真的 nb,得系统学习一波,产出一篇文章试试
# 2.2
# Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 proxy handlers 的方法相同。Reflect 不是一个函数对象,因此它是不可构造的。
Reflect 的所有属性和方法都是静态的,该对象提供了与 Proxy handler 对象相关的 13 个方法。这里只列举以下 5 个常用的方法:
- Reflect.get(target, propertyKey[, receiver]):获取对象身上某个属性的值,类似于 target[name]。
- Reflect.set(target, propertyKey, value[, receiver]):将值赋值给属性的函数。返回一个布尔值,如果更新成功,则返回 true。
- Reflect.deleteProperty(target, propertyKey):删除 target 对象的指定属性,相当于执行 delete target[name]。
- Reflect.has(target, propertyKey):判断一个对象是否存在某个属性,和 in 运算符的功能完全相同。
- Reflect.ownKeys(target):返回一个包含所有自身属性(不包含继承属性)的数组
# 让文字的显示变为垂直方向
作用与父元素:writing-mode: vertical-lr;
注意兼容性
# grid 垂直居中
.wrapper {
width: 300px;
height: 300px;
border: 1px solid #ccc;
display: grid;
}
.wrapper > p {
align-self: center;
justify-self: center;
}
2
3
4
5
6
7
8
9
10
11
12
# 行内元素的 margin 和 padding
- 水平方向:水平方向上,都有效;
- 垂直方向:垂直方向上,都无效;(padding-top 和 padding-bottom 会显示出效果,但是高度不会撑开,不会对周围元素有影响)
# 什么是 CSP?
- CSP(Content-Security-Policy)指的是内容安全策略,它的本质是建立一个白名单,告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截由浏览器自己来实现。
- 通常有两种方式来开启 CSP,一种是设置 HTTP 首部中的 Content-Security-Policy,一种是设置 meta 标签的方式
- CSP 也是解决 XSS 攻击的一个强力手段。
# 什么是尾调用?
尾调用指的是函数的最后一步调用另一个函数。我们代码执行是基于执行栈的,所以当我们在一个函数里调用另一个函数时,我们会保留当前的执行上下文,然后再新建另外一个执行上下文加入栈中。使用尾调用的话,因为已经是函数的最后一步,所以这个时候我们可以不必再保留当前的执行上下文,从而节省了内存,这就是尾调用优化。ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。
# 打印背景,浏览器默认不勾选
# 1、css
@media print {
body{
-webkit-print-color-adjust:exact;
-moz-print-color-adjust:exact;
-ms-print-color-adjust:exact;
print-color-adjust:exact;
}
}
2
3
4
5
6
7
8
# 2、js 基本就是写背景图
# apply 实现 bind
// bind没有立即执行函数
Function.prototype.Mybind = function(context) {
let _me = this;
return function() {
return _me.apply(context);
};
};
2
3
4
5
6
7
# 2.1
# react hooks
- useState: 用来声明状态 state,修改值需要手动合并
- useEffect: 用来替换类组件中的生命周期函数,简化重复的操作
- useContext: 全局共享状态,解决祖先/子孙组件之间的传参问题
- useReducer: useState 的替换方案,将操作和更新解绑,配合 useContxet 可以实现简易 redux
- useCallback: 对函数进行缓存,优化性能
- useMemo: 对值进行缓存,优化性能
- useRef:获取 DOM 节点或组件实例, 保存变量
# vite
当浏览器识别 type="module"引入 js 文件的时候,内部的 import 就会发起一个网络请求,尝试去获取这个文件
vite 主要是是开发时做到了真正的动态加载,打包还是需要借助于 rollup
- 01
- 2023/02/08 00:00:00
- 02
- 2023/01/03 00:00:00
- 03
- 2022/12/21 00:00:00