杂
3 ** 2 === Math.pow(3,2)
~~123.12 === Math.floor(123.12)
数字计算浮点数判断:
x = 0.2;
y = 0.3;
z = 0.1;
equal = (Math.abs(x - y + z) < Number.EPSILON);
在旧的浏览器中 NaN
x = NaN
x !== x // true
解决 typeof null === 'object' 判断 用 `null instanceof Object`
prototype原型是不允许被重新定义的
数组扁平化 flat(Infinity)
获取数组最大值 Math.max(...arr) || arr.sort().reverse()
来源:蚂蚁金服
1.深拷贝与浅拷贝(赋值)
首先从数据类型开始讲起,分为基本数据类型和引用数据类型;
基本数据类型 number/string/undefined/boolean/null/symbol 这些数据存储在栈内存当中;
引用数据类型 function/array/object 这些数据会存储在堆内存中
栈内存空间保存指针(地址),堆内存空间保存实际的对象,我们通过变量访问对象时,实际上访问的是对象的引用(地址);
赋值(=)
--- 基本赋值 赋值操作简单数据类型 不受影响;
--- 引用赋值 赋值操作一个指向 赋值的变量会和引用的地址相互影响;
浅拷贝(object.assign)
--- 拷贝复杂数据类型中的第一层关系 如果存在引用的属性 会被引用地址所影响 基础数据类型不受影响;
深拷贝(JSON.parse(JSON.stringify()))
--- 拷贝对象中的所有属性,生成独立的一份不受任何影响
2.原型与原型链、继承
原型链是为了让这些引用数据类型相互的关联起来
每一个对象都会有一个( __proto__ )隐式原型 的私有属性, 这个属性指向 ta的构造函数的( prototype )显式原型, 每一个原型里面都有一个自己的原型这个原型会一层一层往上直到 `null`
obj.__proto__ === obj.constructor.prototype
继承是获取父级所拥有为自己所能用
3.new做了什么
创建一个空的js对象 --> 将构造函数的原型拷贝一份 --> this指向自己 --> 返回一个新对象
4.闭包和递归(尾递归优化)
闭包 --- 能让内部函数访问外部函数作用域的叫闭包
优点 私有性(把内部函数隐藏起来)
缺点 在内部的引用属性不会被回收,可能会导致内存泄漏(GC回收---当引用数据类型没有存在被引用的关系会被回收)
递归 --- 递归结构=>树结构一样 根据我们的条件往下面一层一层的去找则不会展开其他的节点 但是当嵌套的层级很深的时候会出现栈溢出的情况,这时候就需要用到(尾递归优化);
尾递归 --- 在函数最末尾处调用自身(在js的严格模式下使用es6的函数默认值实现函数柯里化)
函数调用会在内存形成一个"调用记录",又称"调用帧"(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用记录上方,还会形成一个B的调用记录。等到B运行结束,将结果返回到A,B的调用记录才会消失。如果函数B内部还调用函数C,那就还有一个C的调用记录栈,以此类推。所有的调用记录,就形成一个"调用栈"<https://segmentfault.com/a/1190000010360316>(call stack)。
http://www.ruanyifeng.com/blog/2015/04/tail-call.html
5.函数防抖和节流
函数防抖是在一段时间内只触发一次,函数节流是事件被触发多次(时间间隔在等待时间之内),只有一次能生效
防抖和节流的区别主要是一个在开始的时候加上限制条件一个在结束的时候加上限制条件
6.设计模式
工厂模式 工厂函数就是做一个对象创建的封装,并将创建的对象return出去
观察者模式 又称发布订阅者模式,经典案例:事件监听,一个元素同时监听多个同类型事件,元素对象即为发布者,每一个事件处理函数即为订阅者。
策略模式 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换,从而避免很多if语句
var obj = {
"A": function(salary) {
return salary * 4;
},
"B" : function(salary) {
return salary * 3;
},
"C" : function(salary) {
return salary * 2;
}
};
代理模式 为其他对象提供一种代理以控制对这个对象的访问,为了不暴露执行对象的部分代码
7.even loop
执行顺序从上到下碰到 微/宏任务 时先给他存起来 继续往下执行执行完 再去执行微任务 最后执行宏任务
宏任务: setTimeout setInterval
微任务: promise process.nextTick(callback)
8.async/await是什么?
async 函数,就是 Generator 函数的语法糖,它建⽴在Promises上,并且与所有现有的基于Promise的API兼容。
1. Async—声明⼀个异步函数(async function someName(){...})
2. ⾃动将常规函数转换成Promise,返回值也是⼀个Promise对象
3. 只有async函数内部的异步操作执⾏完,才会执⾏then⽅法指定的回调函数
4. 异步函数内部可以使⽤await
1. Await—暂停异步的功能执⾏(var result = await someAsyncCall();)
2. 放置在Promise调⽤之前,await强制其他代码等待,直到Promise完成并返回结果
3. 只能与Promise⼀起使⽤,不适⽤与回调
4. 只能在async函数内部使⽤
9.async/await相⽐于Promise的优势
```
1.代码读起来更加同步
2.Promise虽然摆脱了回调地狱,但是then的链式调⽤也会带来额外的阅读负担 Promise传递中间值⾮常麻烦
3.async/await⼏乎是同步的写法,⾮常优雅 错误处理友好
4.async/await可以⽤成熟的try/catch,Promise的错误捕获⾮常冗余调试友好,
Promise的调试很差,由于没有代码块,你不能在⼀个返回表达式的箭头函数中设置断点,
如果你在⼀ 个.then代码块中使⽤调试器的步进(step-over)功能,
调试器并不会进⼊后续的.then代码块,因为调试器只能跟踪 同步代码的 每一步 。
```
10.WebSocket (长连接)
1.创建一个websocket实例
const socket = new WebSocket("wss://echo.websocket.org")
2.配置开启函数
function openSocket(socket){
socket.onopen=(option)=>{
//开启连接触发
heartCheck.reset()
};
socket.onmessage=(option)=>{
//服务器传参触发
};
socket.onclose=(option)=>{
//关闭连接触发
if (evnt.code != 4500) {
//4500为服务端在打开多tab时主动关闭返回的编码
reconnect();//重连
}
}
}
3.配置心跳包
const heartCheck = {
time:60000,
timeFunc:null,
start:function(){
this.timeFunc = setInterval(function()=>{
if(socket.readyState == 1){
socket.send("HeartBeat")
}else{
socket.close()
}
})
},
reset:funtion(){
clearInterval(this.timeFunc);
this.start()
}
}
4.配置重连函数
function reconnect(){
openSocket(socket)
}
require 和 import
zhuanlan.zhihu.com/p/121770261
1.require/exports 是运行时动态加载,import/export 是静态编译
2.require/exports 输出的是一个值的拷贝,import/export 模块输出的是值的引用
ajax
onloadstart 获取开始
onprogress 数据传输进行中
onabort 获取操作终止
onerror 获取失败
onload 获取成功
ontimeout 获取操作在用户规定的时间内未完成
onloadend 获取完成(不论成功与否)