loading

【跳槽月】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]"
1
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')} />
1
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>
    );
  }
}
1
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>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 2.21

早上十点到杭州,下午睡了一觉,晚上出去逛了一趟~~~, 没了

# 2.20

# 回杭州

# react 学习

# 2.19

# 交接文档梳理

交接文档梳理 (opens new window)

# 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: [],
});
1
2
3
4
5
6
7
8

# vueX

import { createStore } from "vuex";

interface State {
  userName: string;
}
export default createStore({
  state(): State {
    return {
      userName: "俊劫",
    };
  },
});
1
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
1
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)();
1
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
1
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;
}
1
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 } };
1
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);
1
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);
1
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;
}
1
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' ]
1
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
1
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;
}
1
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>
1
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;
}
1
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;
    }
}
1
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);
  };
};
1
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

最近更新时间: 2021/05/01 17:06:28
最近更新
01
2023/02/08 00:00:00
02
2023/01/03 00:00:00
03
2022/12/21 00:00:00