我不知道的js
整理一些没用过的 api
语法篇
Array.flat 💋
扁平化遍历数组
1 | [23, [4,5], [4, [3, 4, 5]]].flat() |
参数代表了要遍历的深度
迭代器💋
Symbol.iterator是迭代器属性
以下数据类型有迭代器属性: Array
Set
Map
String
arguments
1
2
3
4const it = [1,2,3][Symbol.itertaor]
it.next() // {value:1, done: false}
it.next() // {value:2, done: false}
it.next() // {value:3, done: false}
也可以用 for...of
来遍历
我想遍历对象怎么办?💋
以下都返回一个迭代器对象1
2
3Object.keys() // key
Object.values() // value
Object.entries() //[key, value]
生成器💋
其实就是 generator
函数啦。1
2
3
4
5
6
7
8
9
10
11// 生成器
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// 生成器能像正规函数那样被调用,但会返回一个迭代器
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3
惊不惊喜,意不意外,跟迭代器对象调用如此之像,它也可以被迭代。1
for(let a of createIterator) { console.log(a) }
它还是异步解决方案的一种,遇到 yield 时,会中止函数的执行,此时可以执行相关回调。但由于执行它太麻烦,要有一个允许 gen 方法执行的 chunk 函数。
Set结构💋
类似于数组,但其内部成员是不可重复的,可以用来去重(或比较两个数字,NaN在它这里是相等的)1
2Array.form(new Set([2,3,4,4,4,4]))
// [2,3,4]
方法有 add\has\delete\clear
set.size
可以得到 length
Array.from
和 ...
可以将其转为 数组。
它可以遍历
weakSet💋
绝大多数 GC 机制都采取标记清除的方式,简单来说当变量被设置为 null 或者其所处的函数的生命周期结束时,会被 GC 回收掉。而 weakSet 储存一个对象时,不会被标记引用。比如以下代码
1 | var obj = {} |
当 Set 储存值时,被 GC 机制标记引用,即使将值设置为 null,但 set 中嗨保存一份 “副本”,值仍然存在。
而 weakMap 储存值时,GC 机制不会标记该值的引用,当值设置为 null 时,理所当然的被回收了。
Map 结构 💋
与 Set
不同,Map
储存健值对
api 是 `set\get\has\delete\clear
Map 的健值可以是对象,其他也没有啥好说的
weakMap 对象💋
跟 weakSet 相同,不需要赘述了
双向绑定的两种实现方法💋
Object.definePrototype
Proxy
Reflect💋
为什么要引入 Reflect
- 将Object 的方法和属性移植过来
- 将部分操作由报错变为返回一个 bool 值,Reflect.definePorperty
- 将命令式语句改为方法调用,key in obj -> Reflect.has(obj, key)
- 确保对象的原生行为能准确运行。比如Vue 3.0中 Reflect.set
API
Reflect.set(target, key, val, receiver)
receiver 是Proxy 的实例,会触发 defineProperty 钩子Reflect.get(target, key ,val)
Reflect.has(target, key)
会从原型链找Reflect.deleteProperty(obj, key)
删除属性Reflect.construct(target, [args])
实例化 target ->new target(args)
Reflect.getPrototypeOf(obj)
得到原型链Reflect.setPrototypeOf(obj, key ,val)
设置原型链Reflect.apply(fn, this, args)
对应fn.apply(this, args)
Reflect.ownKeys(obj)
返回对象的属性,包括 Symbol 作为健值,不包括原型链,Proxy
Array.prototype.sort 的回调参数
回调函数返回值小于 0,从小到大,大于0,从大到小,等于0,不变Promise 实现原理
async await 实现原理
0.1+0.2===0.3吗💋
不等于,js的浮点数用分数表示,比如 0.5 可以用 1 / 2^1 表示,但 0.1 和 0.2 表示不了,只能近似相等,0.30000000000000004。观察者模式 订阅模式 中介者模式
观察者模式💋
1
2
3
4
5
6
7
8
9
10
11
12
13const beObserve = {
name: 'duhao'
}
let name = ''
Object.definePorperty(beObserve, 'name', {
set(val) {
observe(beObserve, name, val)
beObserve.name = name = val
}
})
function observe(beObserve, oldVal, name) {
// do something
}
发布订阅模式💋
1 | class EventEmiter { |
中介者模式 💋
举个例子就好了,比如枪战游戏,每个角色在打出一枪后,其他角色要校验自身是否中枪,这样比较耦合,现在,设置一个中心,由他来判断谁开枪了,谁中枪了。
ParseInt
ParseInt 有两个参数,第一个参数是字符串,第二个参数是由 2 - 16 的整数。
第二个参数是可选的,但如果不在 2 - 36之间,会返回NAN。如果第一个参数的首位字符串大于第二个参数,也会返回NAN,因为其不能被第二个参数所表示。parseInt(10, 2)
这表示着 1 * Math.pow(2, 1) + 0 * Math.pow(2, 0)
浏览器原理篇
路由的history
内存泄漏 💋
- 未关闭的定时器
- 循环引用
- alert(‘dfsf’.length)
- dom 节点未删除
- 闭包内不用的变量
Rem 物理像素 css像素
高清屏解决方案 💋
在高清屏手机上,常常多个物理像素代表一个 css 像素,造成了 border: 1px 看起来很粗,过不了设计师这一关,可以通过伪元素设置 1px,然后transform: scale(.5),然后居中解决;
浏览器缓存策略
网络篇
网络模型 💋
- 应用层 HTTP/FTP
- 表现层
- 会话层
- 传输层 TCP/UPD
- 网络层 IP
- 数据链路层 以太网
- 物理层 光纤 网线
HTTP Keep-Alive 💋
HTTP 一次链接是昂贵的,TCP 三次握手,四次挥手、冗长的请求头。如果能复用一个 TCP 通道,能节省更多资源,在请求头和返回头中 加入 Connection: Keep-Alive
,使 TCP 通道不会关闭。多个请求可以复用一个TCP链接。但必须是有顺序的。
缺点:1,请求的返回遵循队列原则,如果第一个请求响应慢了,后面的请求会阻塞。2,服务端压力变大。
http2的多路复用 💋
http1.0的问题
- 1,相同域名下的不同资源,要发多次请求,每次请求都要经过TCP三次握手,浪费时间。(虽然Keep-alive可以解决这个问题,)
- 2,请求头过大
- 3,没有服务端推送
http2 引入流的概念,同一域名只建立一个http请求。压缩了请求头,引入了服务端推送。
https 💋
第一步,爱丽丝给出协议版本号、一个客户端生成的随机数(Client random),以及客户端支持的加密方法。
第二步,鲍勃确认双方使用的加密方法,并给出数字证书、以及一个服务器生成的随机数(Server random)。
第三步,爱丽丝确认数字证书有效,然后生成一个新的随机数(Premaster secret),并使用数字证书中的公钥,加密这个随机数,发给鲍勃。
第四步,鲍勃使用自己的私钥,获取爱丽丝发来的随机数(即Premaster secret)。
第五步,爱丽丝和鲍勃根据约定的加密方法,使用前面的三个随机数,生成”对话密钥”(session key),用来加密接下来的整个对话过程。
HTTPS 握手过程中,客户端如何验证证书的合法性 💋
浏览器会内置大多数证书(伪造证书来进行中间人攻击)
https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/142
https://www.cnblogs.com/evan-blog/p/9867561.html
三次握手 四次挥手 💋
三次握手
假设只有两次握手。
- 客户端:在吗,我要发消息啦
- 服务端:OK,你发吧。
这样看起来很正常,但如果客户端在第一次挥手之后,由于网络的波动,数据迟迟到达不到服务端,客户端挂掉了,而服务端还在傻傻等待,造成了资源的浪费。
因此还需要客户端说:我开始发了!。
四次挥手
为什么是四次呢,其实客户端和服务端都有两个状态:发送和接受。
- 客户端:我没有东西要发给你了 (第一次挥手)
- 服务端:好的,我关掉了 接受 态。(第二次挥手)。
- 服务端:(检查后发现自己也没有数据要发了),我也没有东西发给你了,拜拜(第三次挥手)
- 客户端:(关掉接受态),拜拜了您嘞~
常见状态码
1 | 常见状态码 |
框架篇
React声明周期及自己的理解
Redux数据流的流程
Redux如何实现多个组件之间的通信,多个组件使用相同状态如何进行管理
使用过的Redux中间件
redux-thunk
redux-logger
动态路由的两种方案
require.ensure
import()
如何配置React-Router
React 和 Vue 的 diff 时间复杂度从 O(n^3) 优化到 O(n) ,那么 O(n^3) 和 O(n) 是如何计算出来的?
N^3 首先,第一棵树的每一个节点,都要和第二棵数的每一个节点进行对比,这是O(n^2),其次,要计算树的最小转化路径。
React 认为,Dom运算很少会出现跨层级别的移动,因此只将树按层进行对比。它还做了优化:不同的节点类型直接进行替换、key……
介绍下前端加密的常见场景和方法
sessionId
vue 在 v-for 时给每项元素绑定事件需要用事件代理吗?为什么
需要,虽然大多数情况都会给每项绑定同样的回调事件,但还是会创建多个监听器。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### React Vue 原理 diff算法
// https://juejin.im/post/5d8a49d26fb9a04ddf2c25d6
### React中Fibber是什么
### webpack 打包原理
- 找到entry文件,并分析其使用的模块化方案
- 根据对应的模块化方案加载模块
- 拿到模块代码后使用对应的loader操作代码
- 打包进一个bundle 文件,模块被分割成一个个函数,并有自己对应的id,webpack按照正确的加载顺序调用它。
### webpack plugin 插件开发
### vue-loader
### React-Router
### webpack css-loader 和 style-loader 和 postcss
### 虚拟 Dom 如何实现
## typescript 篇
### 装饰器 💋
先认识一个设计模式:装饰器模式:
> 装饰器模式:给现有对象或方法添加额外的属性,并且不改变其原有结构。
举个例子。
```typescript
class person {
static skill = ['fly', 'run']
}
function derWrite(target, name, desc) {
target.skill.push('walk')
target.prototype.walk = function() {
console.log('i can walk')
}
return (...arguments) => new target(...arguments)
}
const p = derWrite(person)
p.skill // ['fly', 'run', 'walk']
p.walk // ['fly', 'run', 'walk']
以上,derWrite 就是 类 person 的装饰器,它使 person 有了 walk 的能力。Person 不需要 知道 derWrite 是如何实现的,它只需调用即可。当下次 Car 类也需要 walk 时, derWrite(Car) 即可。
上面就是装饰器模式,记得有个大神这么说过,设计模式的出现表示了语言设计的缺陷。对于装饰器来说 js 弥补了这个缺陷,引入了 装饰器 的概念,当仍在提案中……
但你可以使用 typescript 提前体验。让我们用装饰器重新实现以上例子。1
2
3
4
5
6
7
8
9
10
11
12
13 ();
class person {
static skill = ['fly', 'run']
}
function derWrite(target, name, desc) {
target.skill.push('walk')
target.prototype.walk = function() {
console.log('i can walk')
}
return target
}
new person().skill // ['fly', 'run', 'walk']
new person().walk // ['fly', 'run', 'walk']
可以看到,代码非常简洁,没什么好赘述的。
node 篇
介绍下 npm 模块安装机制,为什么输入 npm install 就可以自动安装对应的模块?
KOA2
Redis
事件循环机制
https://github.com/qqqdu/dxy-node-race/blob/master/eventLoop/README.md
正则篇💋
trim 函数
算法篇
介绍下深度优先遍历和广度优先遍历,如何实现?
请分别用深度优先思想和广度优先思想实现一个拷贝函数?
二叉树遍历
二叉树路径总和
参考
https://www.jianshu.com/p/f871c4c0663d
https://juejin.im/post/5b94d8965188255c5a0cdc02#heading-86
https://juejin.im/post/5b94d8965188255c5a0cdc02#heading-21
https://github.com/yygmind/blog/issues/43