JS
ES6新特性
1. let const (let const var 区别)
2. promise (promise与async await的区别)
3.箭头函数 (与普通函数的区别)
4.解构赋值
5.模板字符串
6.set set 与map的区别
①set:数组去重、集合、值的集合
②map:数据存储、字典、键值对的集合,可用get获取值
③两者无论是键还是值都可以是任意数据类型,都可以用for..of遍历
map与对象的区别
①键值设置类型方面
对象的键只能是字符串或者是symbol,其他类型也会被强制转换成字符串
map的键值对可以为任何类型
②初始化
对象可以直接使用字面量进行初始化
map需要使用map()构造函数进行初始化
③迭代方面
对象不可以使用for..of..迭代
map可以使用for..of..,或者用Map.prototype.forEach可以进行迭代
④序列化
对象可以使用JSON进行序列化,map不可以
⑤性能
Map对象在涉及频繁删除,添加键值对的过程中表现的会更好,
普通对象没什么优化
7.迭代器 iterator
String Array Map Set Dom元素是所有内置的可迭代对象 可以用for..of..进行遍历
8.扩展运算符 ...
可以实现浅拷贝
9.新增模块化概念 import export
10.class 类
for...in... for...of.. map forEach的区别
for..in.. for..of..区别
for...in.. 获取的是数组的下标,可以遍历普通对象和可迭代对象
for...of.. 获取的是可迭代对象的值。
let arr = [1, 2, 3] let obj = { name: 'Lucky', age: 18, hobby: ['swimming', 'running', 'ball'] } for (let i in arr) { console.log(i); //0,1,2 } for (let i in obj) { console.log(i); //name,age,hobby } for (let i of arr) { console.log(i) //1,2,3 } for (let i of obj) { console.log(i); //Uncaught TypeError: obj is not iterable }
forEach 与 map的区别
map会返回一个新的数组,不会修改原数组,一般用于需要修改数据的场景
forEach没有返回值,一般用于你并不打算改变数据,只是想用数据做一些事情,比如将数据存储,或者打印。
let arr = [1, 2, 3] arr.forEach((item, index, arr) => { return arr[index] = item * 2 }); console.log(arr); //[2,4,6] let arr = [1, 2, 3] let newArr = arr.map((item, index, arr) => { return item * 2 }) console.log(arr); //[1,2,3] console.log(newArr);//[2,4,6]
事件
文档与浏览器发生交互的瞬间,就会发生事件
分为两种:事件捕获,事件冒泡
事件冒泡:IE公司提出,从目标事件向外一层一层触发(从最明确到最不明确),事件委托 就是利用了这个,将事件绑定在父元素身上,如果子元素不想触发可以直接阻止
event.stopPropagation()
.stop
addEventListener('click',函数名,false/ture)
事件捕获:网景公司提出,由外向内
事件流:就是事件执行的顺序
执行顺序:事件捕获 事件流 事件冒泡
作用域与作用域链
作用域:一块独立的区域,设置的变量不会泄露,不同作用域下的相同变量互不干扰。
分为:全局作用域:在外层函数 、变量 ;赋值但是未被定义的变量;window上的属性
函数作用域
块级作用域(es6新增),通过let const实现 {}
作用域链:当我们访问一个变量时,会从当前作用域中进行查找,如果没有向父级作用域进 行查找,最终查找到全局作用域上。这一层一层的查找关系就是作用域链。
js数据类型
基础类型:Number String Boolean Null Undefined Symbol Bigint
引用类型:Object Array Function Date RegExp..
如何判断是哪种?
typeof
intanceof
constructor
Object.propetype.toString.call()
各个数据类型之间的转换,隐式转换规则
防抖节流实现原理
防抖:事件被频繁的触发只执行最后一次,上一次的执行会被清空重新执行
function debounce(fn,delay){ let timer = null return function(){ clearTimeout(timer) timer = setInterval(()=>{ fn.call(this) },delay) } }
节流:设置n秒时间,n秒内只执行一次。
function throttle(fn, delay) { let timer = null; return function () { if (!timer) { timer = setTimeout(() => { fn.call(this); timer = null; }, delay); } }; }
深浅拷贝
浅拷贝:基础类型直接赋值,引用类型复制的是内存地址
深拷贝:开辟一块新的内存地址存放数据,两者互不干扰
举个例子吧
let obj1 = {a:1} let obj2 = obj1 obj1.a = 2 浅拷贝 console.log(obj1.a) //2 console.log(obj2.a) //2 深拷贝 console.log(obj1.a) //2 console.log(obj2.a) //1
如何实现深浅拷贝:
浅拷贝:...扩展运算符
Object.assign()
深拷贝:JSON.parse(JSON.stringify()) 但是日期,正则不能正确转换
Jquery.extend()
手写cloneDeep
function deepClone(obj) { if (typeof obj !== "object" || obj == null) { return obj; } let result; if (obj instanceof Array) { result = []; } else { result = {}; } for (let key in obj) { //对象原型上的数据不需要进行拷贝 if (obj.hasOwnProperty(key)) { result[key] = deepClone(obj[key]); } } return result; }
call、apply、bind的区别
都是用来改变this指向的
call与apply类似,只是传参方式不同, call用扩展运算符来传参就可以把apply来代替了
call,apply定义完是直接调用的
bind是不会立即执行的 而是传回一个已经改变this指向的函数,可继续传参,需要()调用
函数柯里化
是将一个多参数的函数转换为一个参数的方法,
传递一个参数,并返回一个函数,让返回的函数处理其余的参数
利用了闭包特点
我觉得好处就是不需要将所有需要用到的参数在最开始就要传进去,可以根据自己的逻辑逐渐将参数传递,那样更加清晰明了
举例
let add = function (x, y) { return x + y } add(1, 2) let add1 = function (x) { return function (y) { return x + y } } add1(1)(2)
高阶函数
其实就是将函数作为参数,返回值也是一个函数
function hFunction(param,callback){ return callback(param) }
Js运行机制
单线程
为了防止阻塞分为同步任务,异步任务(微任务,宏任务)
执行顺序 同步任务>微任务>宏任务
微任务:promise.then.. async await.. process.nextTick(Node.js环境) 它是执行在所有异 步任务最前面的
宏任务:定时器,ajax,script整体代码,Dom事件
Promise
异步编程的解决方案
其自身有race、all、resolve、reject方法
原型上有then,catch方法
有三种状态 pedding、fulfilied、rejected 不可逆
可解决低于回调地域的问题
本质就是用链式调用的方式执行回调函数
Promise.all()使用场景多个异步操作必须成功才会执行后续操作
Promise.race() 可以设置异步操作的超时时间
.then会返回一个promise对象,以保证then可以继续进行链式调用
Promise.all如果有一个请求失败了,如何能得到其余的正确结果
Promise.all([ Promise.reject({ code: 500, mag: "服务器异常" }), Promise.resolve({ code: 200, list: [] }), Promise.resolve({ code: 200, list: [] }) ].map(p => p.catch(e => e)) ) .then(res => { console.log("res=>", res); } ) .catch(error => { console.log(error); }) //核心就是.map(p => p.catch(e => e)),map的每一项都是promise,catch返回的结果都会被promise.resolve进行包裹
async await
同步写法,执行异步操作
函数前面有async关键字,说明该函数内部有异步操作,调用该函数时,会返回一个promise对象。
使用场景:第一步执行得到的结果返给第二部使用
使用ajax获取第一个接口返回的数据,第二次接口调用依赖这个数据进行调用
clientWidth、offsetWidth,scrollWidth区别
都是元素视图的属性
clientWidth:元素内容可视区宽度 padding+content(width)
offsetWidth:元素的实际宽度 padding + content + border
scrollWidth:元素内容实际宽度 如果没有滚动条的话 = clientWidth 如果有,加上滚动条的宽度
vite和webpack的区别
Webpack基于commonjs,先打包合并然后请求服务器,更改一个模块,其他有依赖关系的模块都会重新打包(成为一个大的bundle文件);
webpack从一开始dev server的时候,就会进入入口文件,找到找到整个项目中所有依赖文件,然后对这写文件进行编译,打包到boundle文件中,项目越大,启动就会越慢
Vite基于es6 module,自动向依赖的module发请求,服务端按需编译返回,改动一个模块仅仅会重新请求该模块;有利于http2的缓存和压缩
vite启动的时候是不需要打包的,也就是说不会对模块的依赖进行拆分编译,只有当浏览器对某个模块发送请求的时候,才会对该模块进行编译,实现的是按需编译,所以启动速度会比webpack快
axios怎么取消上次请求
最近在项目中遇到一个问题,在连续发送同一请求时,如果第二次请求比第一次请求快,那么实际显示的是第一次请求的数据,这就会造成数据和我选择的内容不一致的问题。解决的方案:在后续发送请求时,判断之前的请求是否完成(同一个接口),如果未完成则立即取消。然后在发送新的请求。
①可以使用CancelToken.source工厂方法创建cancel token
var CancelToken = axios.CancelToken; var source = CancelToken.source(); axios.get('/user/12345', { cancelToken: source.token }).catch(function(thrown) { if (axios.isCancel(thrown)) { console.log('Request canceled', thrown.message); } else { // 处理错误 } }); // 取消请求(message 参数是可选的) source.cancel('Operation canceled by the user.');
② 还可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:
var CancelToken = axios.CancelToken; var cancel; axios.get('/user/12345', { cancelToken: new CancelToken(function executor(c) { // executor 函数接收一个 cancel 函数作为参数 cancel = c; }) }); // 取消请求 cancel();
js如何封装动画函数
(1).获得盒子当前位置
(2).让盒子在当前位置加上1个移动距离
(3).利用定时器不断重复这个操作
(4).加一个结束定时器的条件
(5)..注意此元素需要添加定位,才能使用element.style.left
div { position: absolute; left: 0; width: 100px; height: 100px; background-color: aqua; } <div></div> //实现步骤: 1.获得盒子当前位置 2.让盒子在当前位置加上1个移动距离 3.利用定时器不断重复这个操作 4.加一个结束定时器的条件 5.注意此元素需要添加定位,才能使用element.style.left --> <script> var div = document.querySelector('div'); var animation = setInterval(function(){ //停止动画本质是停止定时器 if (div.offsetLeft>=400) { clearInterval(animation); } div.style.left = div.offsetLeft + 5 + 'px'; },30) </script>
VUE
vuex开启模块化命名空间后有两个模块AB怎么在B模块的actions中拿到A模块的内容
1.state
//B模块 const actions = { async ['shop'](store, config = {}) { const { commit, dispatch, state, rootState } = store ... //rootState 通过根state就会获得A模块中的state数据 } }
2.actions
const actions = { async ['shop'](store, config = {}) { const { commit, dispatch, state, rootState } = store ... dispatch('xxxx', {}, {root: true}) // 调用其他模块的 actions } //dispach 三个参数 第一个"xxx"为A模块的异步操作的路径 // 第二个是穿给actions的数据,如果没有数据就写成{} // 第三个配置选项 必须写 声明此actions不是当前模块的
3.mutations
const actions = { async ['shop'](store, config = {}) { const { commit, dispatch, state, rootState } = store ... commit('xxxx', {}, {root: true}) // 调用其他模块的 mutations } //dispach 三个参数 第一个"xxx"为A模块的异步操作的路径 // 第二个是穿给actions的数据,如果没有数据就写成{} // 第三个配置选项 必须写 声明此actions不是当前模块的
4.getters
//B模块 const actions = { async ['shop'](store, config = {}) { const { commit, dispatch, state, rootState ,rootGetters} = store ... //rootGetters 通过根state就会获得A模块中的getters数据 rootGetters['gettersAxxx'] } }
算法
求出数组的最大值最小值
let arr = [1, 3, 5, 4, 9, 7] // 1.借助es6的扩展运算符 console.log(Math.max(...arr)); console.log(Math.min(...arr)); // 2. 数组的sort的方法进行排序 let sortArr = arr.sort((a, b) => a - b) //sort会改变原数组 console.log(sortArr[0]); console.log(sortArr[sortArr.length - 1]); // 3.借助reduce在原型上添加方法 Array.prototype.max = function () { return this.reduce((pre, next) => { return pre < next ? next : pre }) } Array.prototype.min = function () { return this.reduce((pre, next) => { return pre < next ? pre : next }) } console.log(arr.max()); console.log(arr.min()); // 4.在原型上通过for循环将前后两个值进行比较 Array.prototype.max = function () { let max = arr[0] let len = arr.length for (let i = 1; i < len; i++) { if (arr[i] > max) max = arr[i] } return max } Array.prototype.min = function () { let min = arr[0] let len = arr.length for (let i = 1; i < len; i++) { if (arr[i] < min) min = arr[i] } return min } console.log(arr.max()); console.log(arr.min());
求两个数组的交集
// 求出两个数组的交集 let arr1 = [1, 2, 3, 4, 5, 3, 3] let arr2 = [3, 4, 5, 6, 7] // 1.双重for循环 先将两数组去重 let arrCoin = [] arr1 = [...new Set(arr1)] arr2 = [...new Set(arr2)] let len1 = arr1.length let len2 = arr2.length for (let i = 0; i < len1; i++) { for (let j = 0; j < len2; j++) { if (arr1[i] == arr2[j]) { arrCoin.push(arr1[i]) } } } console.log(arrCoin); // 2.for循环+includes let arrCoin = [] arr1 = [...new Set(arr1)] arr2 = [...new Set(arr2)] let len1 = arr1.length for (let i = 0; i < len1; i++) { if (arr2.includes(arr1[i])) { arrCoin.push(arr1[i]) } } console.log(arrCoin); // 3.filter + includes let arr3 = arr1.filter((i) => { return arr2.includes(i) }) console.log(arr3);
求出两个数组的差集
// 求出两个数组中不一样的值 let arr1 = [1, 2, 3, 4, 5, 3, 3] let arr2 = [3, 4, 5, 6, 7] // 1.合并去重 - 交集 // 合集 let arr3 = [...new Set(arr1.concat(arr2))] // 交集 let arr4 = [...new Set(arr1.filter((i) => { return arr2.includes(i) }))] let arr5 = arr3.filter((i) => { ... })