TCP (传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议
HTTP(超文本传输协议)是利用TCP在两台电脑(通常是Web服务器和客户端)之间传输信息的协议
TCP协议对应于传输层,而HTTP协议对应于应用层,Http会通过TCP建立起一个到服务器的连接通道, 当本次请求需要的数据完毕后,Http会立即将TCP连接断开,这个过程是很短的。所以Http连接是一种短连接,是一种无状态的连接。从HTTP/1.1起, 默认开启Connection: keep-alive,保持长连接特性,但依然是无状态连接。
闭包
1. 在实践开发中,有一种优化手段叫做记忆函数。
当我们使用useMemo/useCallback时,由于新增了对于闭包的使用,新增了对于依赖项的比较逻辑,因此,盲目使用它们,甚至可能会让你的组件变得更慢。
2. 防抖:(闭包举例)
/*****************************简化后的分割线 ******************************/
function debounce(fn,delay){
let timer = null //借助闭包
return function() {
if(timer){
clearTimeout(timer)
}
timer = setTimeout(fn,delay) // 简化写法
}
}
// 然后是旧代码
function showTop () {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
window.onscroll = debounce(showTop,1000) // 为了方便观察效果我们取个大点的间断值,实际使用根据需要来配置"
此时会发现,必须在停止滚动1秒以后,才会打印出滚动条位置。到这里,已经把防抖实现了,现在给出定义:
防抖:对于短时间内连续触发的事件(上面的滚动事件),防抖的含义就是让某个时间期限(如上面的1000毫秒)内,事件处理函数只执行一次。
节流:其实很简单:我们可以设计一种类似控制阀门一样定期开放的函数,也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活(类似于技能冷却时间)。
this 指向
在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。如果调用者函数被某一个对象所拥有, 那么该函数在调用时,内部的this指向该对象。如果函数独立调用,那么该函数内部的this,则指向undefined。但是在非严格模式中,当this指向undefined时,它会被自动指向全局对象。
new的创建过程
function _new(fn, ...arg) {
const obj = Object.create(fn.prototype);
const ret = fn.apply(obj, arg);
return ret instanceof Object ? ret : obj;
}
function _new(fn , ...args){
const obj={}
const Constructor = fn
obj.__proto__ = Constructor.prototype
const result = Constructor.call(obj , ...args)
return typeof result === "object" ? result : obj
}
- 首先创建一个空的对象,空对象的__proto__属性指向构造函数的原型对象
- 执行构造函数,修改this指向
- 如果构造函数返回一个非基本类型的值,则返回这个值,否则上面创建的对象
子类续承父类
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
自己实现一个instanceof
检查一个对象的的原型链上有没有这个类的,
JS中面向对象以及 __proto__,ptototype 和 constructor juejin.cn/post/684490…
function myInstanceof(targetObj, targetClass) {
// 参数检查
if(!targetObj || !targetClass || !targetObj.__proto__ || !targetClass.prototype){
return false;
}
let current = targetObj;
while(current) { // 一直往原型链上面找
if(current.__proto__ === targetClass.prototype) {
return true; // 找到了返回true
}
current = current.__proto__;
}
return false; // 没找到返回false
}
// 用我们前面的继承实验下
function Parent() {}
function Child() {}
Child.prototype.__proto__ = Parent.prototype;
const obj = new Child();
console.log(myInstanceof(obj, Child) ); // true
console.log(myInstanceof(obj, Parent) ); // true
console.log(myInstanceof({}, Parent) ); // false作者:蒋鹏飞链接:https://juejin.cn/post/6844904069887164423来源:掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Generator 函数
next方法的作用是分阶段执行Generator函数。每次调用next方法,会返回一个对象,表示当前阶段的信息(value属性和done属性)。value属性是yield语句后面表达式的值,表示当前阶段的值;done属性是一个布尔值,表示 Generator 函数是否执行完毕,即是否还有下一个阶段。
function* gen(x) {
var y = yield x + 2;
return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }
async函数它就是 Generator 函数的语法糖,就是将 Generator 函数的星号(*)替换成async,将yield替换成await
async function gen(x) {
var y = await x + 2;
return y;
};
详细:es6.ruanyifeng.com/#docs/async
vue 你怎么理解vue中的diff算法?
源码分析1:必要性,lifecycle.js - mountComponent()
组件中可能存在很多个data中的key使用
源码分析2:执行方式,patch.js - patchVnode()
patchVnode是diff发生的地方,整体策略:深度优先,同层比较 源码分析
3:高效性,patch.js - updateChildren()
1.diff算法是虚拟DOM技术的必然产物:通过新旧虚拟DOM作对比(即diff),将变化的地方更新在真 实DOM上;另外,也需要diff高效的执行对比过程,从而降低时间复杂度为O(n)。
2.vue 2.x中为了降低Watcher粒度,每个组件只有一个Watcher与之对应,只有引入diff才能精确找到 发生变化的地方。
3.vue中diff执行的时刻是组件实例执行其更新函数时,它会比对上一次渲染结果oldVnode和新的渲染 结果newVnode,此过程称为patch。
4.diff过程整体遵循深度优先、同层比较的策略;两个节点之间比较会根据它们是否拥有子节点或者文 本节点做不同操作;比较两组子节点是算法的重点,首先假设头尾节点可能相同做4次比对尝试,如果 没有找到相同节点才按照通用方式遍历查找,查找结束再按情况处理剩下的节点;借助key通常可以非 常精确找到相同节点,因此整个patch过程非常高效。
vue extend/$mount/el
//Vue构造器var MyComponent = Vue.extend({
template: '<div>Hello!</div>'
})
// 1. 创建并挂载到 #app (会替换 #app)
new MyComponent().$mount('#app')
// 2. 同上
new MyComponent({ el: '#app' })
// 3. 在文档之外渲染并且随后挂载
var component = new MyComponent().$mount()
document.getElementById('app').appendChild(component.$el)
React虚拟dom
虚拟DOM:js对象来描述真实的DOM,编程概念,以最低的DOM操作的成本,新旧对比,达到最少的DOM操作量,最少更新
diff虚拟DOM对象,批量的最小化的操作dom
为什么用Jsx :原理:babel-loader会预编译JSX为React.createElement(...)
React.createElement:创建虚拟DOM
React.Component:实现自定义组件
ReactDOM.render:渲染真实DOM
pureComponent内置了shouldComponetUpdate
React 生命周期:
1. 挂载卸载过程
- constructor()
- getDerivedStateFromProps
- render()
- componentDidmount ()
2. 更新过程
- getDerivedStateFromProps(nextProps, prevState) 代替componentWillReceiveProps()
- shouldComponentUpdate(nextProps,nextState)
- render()
- getSnapshotBeforeUpdate(prevProps, prevState) 代替componentWillUpdate。
- componentDidUpdate(prevProps,prevState)
3.卸载
- componentWillUnmount ()
4.错误处理
- static getDerivedStateFromError()
- componentDidCatch();
react优化
-
使用 memo 来缓存组件
-
使用 useMemo 缓存大量计算
-
使用 PureComponent、shouldComponentUpdate
-
避免使用内联对象
-
避免使用匿名函数
-
延迟加载不是立即需要的组件:通过利用 React.lazy 和 React.Suspense 可以轻松完成按需加载
-
调整 CSS 而不是强制组件加载和卸载
浅拷贝的实现
1.简单的引用复制
2.Object.assign()
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
var x = {
a: 1,
b: { f: { g: 1 } },
c: [ 1, 2, 3 ]
};
var y = Object.assign({}, x);
console.log(y.b.f === x.b.f); // true
深拷贝
1.JSON对象的parse和stringify
对于正则表达式类型、函数类型等无法进行深拷贝(而且会直接丢失相应的值)。同时如果对象中存在循环引用的情况也无法正确处理。
2.还有一种实现深拷贝的方法 就是 lodash里面的 _.cloneDeep
3.手动实现
function cloneDeep(obj) {
// 处理3中简单类型 null or undefined or function
if (obj== null || typeof obj != "object") return obj;
// 处理 Date
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// 处理 Array or Object
if (obj instanceof Array | obj instanceof Object) {
var copy = (obj instanceof Array)?[]:{};
for (var attr in obj) {
if (obj.hasOwnProperty(attr))
copy[attr] = cloneDeep(obj[attr]); }
return copy;
}
throw new Error("Unable to clone obj! Its type isn't supported.");
}
实现 Promise.all 方法
总结 promise.all 的特点
1、接收一个 Promise 实例的数组,
2、如果元素不是 Promise 对象,则使用 Promise.resolve 转成 Promise 对象
3、如果全部成功,状态变为 resolved,返回值将组成一个数组传给回调
4、只要有一个失败,状态就变为 rejected,返回值将直接传递给回调all() 的返回值也是新的 Promise 对象
Promise.myAll = function(iterators) {
const promises = Array.from(iterators)
const num = promises.length
let count = 0
let resolvedValue = new Array(num)
return new Promise((resolve, reject) => {
for(let item of promises){
Promise.resolve(item)
.then(data => {
// 保存这个promise实例的value
resolvedValue[count++] = data
// 通过计数器,标记是否所有实例均 fulfilled
if(count === num){
resolve(resolvedValue)
}
})
.catch(err => reject(err))
}
})
}
Promise.myAll([promise1, promise2, promise3]).then(function(values) {
console.log(values);
});
数组拍平
Array.prototype.flatt = function(){
let arr = [];
this.forEach(item => {
if(item instanceof Array){
arr = arr.concat(item.flatt());
}else{
arr.push(item);
}
})
return arr;
}
const arr = [2,[2,3,4,[5,6]]];
console.log(arr.flatt());
数组去重写法
- [...new Set([2,"12",2,12,1,2,1,6,12,13,6])] //[2, "12", 12, 1, 6, 13] es6的新特性
- Array.from(new Set([1, 1, 2, 2]))