js
JS由哪三部分组成
ECMAScript、BOM、DOM
内置对象
String、Number、Boolean、Array、Date、RegExp、Object、Math、JSON、Error
数组的常用方法
forEach、map、filter、reduce、reduceRight、some、every、indexOf、lastIndexOf、concat、slice、splice、join、sort、reverse、push、pop、shift、unshift
数据类型检测
- typeof
- instanceof
- Object.prototype.toString.call
闭包
在函数内部,可以访问函数外的变量
- 重复利用变量
- 不会全局污染
- 存在内存当中,提升性能
function fn(x) {
return function () {
console.log(' =====', x)
}
}
const y = fn('abcd')
内存泄露
已经分配地址的对象,长时间占用或者无法清除导致
事件委托
利用事件冒泡实现,把子元素的事件委托给父元素,减少事件监听,提升性能
阻止事件冒泡,event.stopPropagation()
基本、引用数据类型(存放堆栈的不同)
- Number、String、Boolean、Null、undefined、Symbol
- Object、Array、Function
原型链
构造函数的实例共享属性和方法
class Person {
sayName = function () {
console.log('this is function sayName')
}
}
const p = new Person()
console.log(' =====', p.__proto__ === Person.prototype)
__proto__可以理解成一个指针(实例对象当中的一个属性),指向原型对象(构造函数的原型prototype)
一个实例对象在调用属性/方法的时候,执行过程:实例本身--> 构造函数的原型 --> 原型的原型
new做了什么
- 创建空对象
- 空对象的构造函数通过原型链进行连接
- 把构造函数的this绑定到空对象
- 根据构造函数返回类型判断
- 值类型 --> 返回对象
- 引用类型 --> 返回该引用类型
function newFun(Fun, ...args) {
let newObj = {}
newObj.__proto__ = Fun.prototype
const result = Fun.apply(newObj, args)
return result instanceof Object ? result : newObj
}
function Person(name) {
this.name = name
}
Person.prototype.sayName = function () {
console.log(this.name)
}
const p = newFun(Person, 'abc')
p.sayName()
console.log(' =====', p)
继承
- 原型链
- 构造函数
- 组合式
- class
js设计原理
- js引擎(V8引擎)
- 运行上下文
- 调用栈
- 事件循环
- 回调
this指向
- 全局this、普通函数、匿名函数都指向window
- apply、call、bind改变了的this指向
- 箭头函数看外层是否改变了this,否则指向window
- 非箭头函数,this指向最后调用它的对象
- new改变this的指向
script标签 async defer区别
未指定直接运行js
- async 加载DOM树的时候,同时执行js
- defer 加载DOM树的时候,等DOM树加载完毕后,再执行js
setTimeout、setInterval最小执行时间
- 4ms
- 10ms
ES新特性
- 块级作用域
- class
- set/map
- 解构
- async/await
- 数组的新API
- 扩展运算符
- 模块化
- Promise
- 箭头函数
- 函数参数默认值
apply、call、bind区别
都是用来改变this指向和函数调用
- call 传一个参数列表,call方法和apply方法调用一致,只是传参不同,其中call的性能更好,
- apply 传一个数组
- bind 传参不会立即执行,会返回一个改变this指向的函数,这个函数还可以继续传参
bind()()
递归当中的问题
在递归当中,需要指定对应的终止条件(return)避免栈溢出
深拷贝
- JSON.parse(JSON.stringify(obj))
- 扩展运算符
- 递归+遍历
事件循环
- 主线程
- 执行栈
- 任务队列
- 宏任务
- 微任务
主线程执行同步任务,然后执行任务队列当中的任务(并且在这里微任务会在宏任务之前执行),循环反复
Ajax
- 创建XmlHttpRequest对象
- xhr.open()建立连接
- xhr.send()发送请求
- 接收响应
- 渲染
get、post区别
- 安全性
- 获取/提交
- 缓存方式
- 请求退回,get无影响,post会重新提交
- 浏览记录
- get参数只能url编码、post可以传文件等其他格式
Promise内部原理
Promise是用来解决回调地狱问题的
pendding
初始化fulfilled
成功rejected
失败
其中当使用了Promise之后,是无法取消的,如果没有给Promise设置回调,那么其内部的错误无法反馈到外部
Promise、async、await区别
都是用于处理异步请求,分别在ES6和ES7被加入,其中async、await也是基于Promise进行实现的
- Promise通过then、catch捕获异常、并且Promise是链式调用、不方便维护
- async和await是通过try、catch捕获异常,让异步代码看起来和同步一样,易于维护
Promise 的方法
reject resole catch all
- allSettled在其中一个promise返回错误时还可以继续等待结果
- race 接收一个数组 得到最快返回的 这是一个新的promise
- any 只要有一个reject就会得到一个失败的promise,但是会等全部promise执行完
游览器的存储方式
- cookie
- 兼容好,请求头会自动携带,
- 存储小,使用麻烦
- localStorage
- 操作方便,永久存储,兼容好
- 值的类型被限定,并且在隐私模式下不可读取,不能进行爬虫
- sessionStorage
- 会话级的,页面关闭后失效
- indexedDB
- 键值存储,可快速读取
token存localStorage、cookie的区别
- localStorage 后续请求发送都需要手动添加token
- cookie 会自动发送token,不能跨域
token登录流程
- 请求登录
- 服务端验证,下发token
- 前端存储token
- 后续请求携带token
- 服务端验证token
- 响应
页面渲染流程
- DNS解析
- 建立TCP连接
- 发送HTTP请求
- 服务器响应
- 页面渲染
- 获取HTML、CSS
- 把HTML解析成DOM树、把CSS解析成样式表CSSOM树
- DOM+CSSOM树生成渲染树
- 布局 把渲染树进行渲染
- 断开TCP连接
DOM树和渲染树的区别
- DOM树和HTML标签一一对应,包含了head和隐藏元素
- 渲染树不包含head和隐藏元素
精灵图与Base64
- 精灵图:把图片整合到一张图片中,减少HTTP请求次数,提升性能
- Base64:将图片转换成字符串,然后通过url的形式进行展示
svg (Xml语法格式的图像)
- 可直接插入页面,是DOM树的一部分
- 可作为文件进行引入
<img src="xxx.svg" />
- 可转成base64引入
JWT
json web token
- 获取后端响应的JWT(token)携带了用户信息
- HTTP请求头携带Authorization
- 后端解析token校验
- 解析出用户信息做后续逻辑操作
npm底层环境原理
node project manager
- 网站
npmjs.com
- 注册表 用来管理所有的包
- 命令行工具
HTTP请求头与响应头的区别
请求头
- Accept 支持的类型
- Host 主机地址
- User-Agent 浏览器信息
- Referer 来源
- Cookie 认证信息
- Date 时间
- connection 连接方式
- x-request-with 与服务器通信的协议
响应头
- Content-Type 内容类型
- Server 服务器信息
- Location 服务器地址
- Refresh 重定向
缓存类型
- 强缓存(本地缓存)不发送请求,直接从缓存中读取
- 弱缓存(协商缓存)发送请求判断是否使用缓存,服务器返回304,从缓存中读取
同源策略
协议+域名+端口(一致表示同源)
其中:img、link、script标签是允许跨域的
解决跨域的方案
- JSONP
- CORS 后端允许跨域
- nginx反向代理
- webSocket
防抖、节流
- 防抖:在 n 时间以后触发函数,若时间未到再次被触发,则会重置执行函数的倒计时。(多用于搜索框优化)
- 节流:在 n 时间内无论触发多少次函数,只会执行第一次触发。从而稀释出发频率。 (多用于按钮,以及页面滚动)
后端接口无数据响应
- 填充默认数据
- if判断数据是否为空
无感登录(无感刷新token)
在token过期的时候,不需要用户操作,后台自动刷新token
- 在响应器当中拦截,判断token返回过期之后,重新调用获取token
- 后端返回过期时间,前端根据超时时间判断是否过期,何时发送请求获取token
- 前端定时请求获取token
大文件上传
- 分片上传
- 断点续传
- 服务端返回,从哪里重新开始上传,在浏览器端判断
函数中定义变量,返回一个立即执行函数,外部怎么修改这个变量
可以通过返回一个对象,该对象包含一个用于修改变量的方法
function myFunction() {
let myVar = 0;
return {
getVar: function () {
return myVar;
},
setVar: function (value) {
myVar = value;
}
};
}
const obj = myFunction();
obj.setVar(10);
实现const
- object.freeze({})
- Object.defineProperty
Object.defineProperty(obj, 'value', {
value: value,
writable: false,
enumerable: true,
configurable: false
});
实现instanceof
function myInstanceOf(obj, constructor) {
let prototype = Object.getPrototypeOf(obj);
while (prototype !== null) {
if (prototype === constructor.prototype) {
return true;
}
prototype = Object.getPrototypeOf(prototype);
}
return false
}