1.var和let const 的区别
var是ES5语法,let const 是ES6语法; var有变量提升
var和let是变量,可修改;const是常量,不可修改;
let const有块级作用域,var没有
2.typeof 返回哪些类型
undefined string number boolean symbol——值类型
object(注意,typeof null === ‘object’)——引用类型
function——函数
3.列举强制类型转换和隐式类型转换
强制:parseInt parseFloat toString等
隐式:if 逻辑运算、 == 、+ 拼接字符串
4.手写深度比较,模拟lodash isEqual
function isEqual(obj1,obj2){
// 1.判断两个元素是否全等,全等直接返回true
if(obj1 === obj2) return true
// 2.判断是否对象或数组,不是对象或数组直接返回false
if([...arguments].some(v => v.typeof !=='object' || v == null )) return false
// 3.先获取两个元素的keys,长度不相等,直接返回keys
const objKeys1 = Object.keys(obj1)
const objKeys2 = Object.keys(obj2)
if(objKeys1.length !== objKeys2.length) return false
// 4.递归比较
return objKeys1.every(v => isEqual(obj[v],obj2[v]))
}
5.split() 和 join() 的区别
'1-2-3'.split('-') // [1,2,3]
[1,2,3].join('-')//'1-2-3'
6.数组的 pop push unshift shift 分别做什么
// pop:去除数组的最后一个元素,返回去除的元素
const arr = [10,20,30]
const popRes = arr.pop()
console.log(popRes,arr)
// 30 (2) [10, 20]
// push: 在原数组的后面增加一项,返回的是目前数组的长度
const arr = [10,20,30]
const pushRes = arr.push(50)
console.log(pushRes,arr)
// 4 (4) [10, 20, 30, 50]
// unshift : 在原数组的前面增加一个元素,返回是目前数组的长度
const arr = [10,20,30]
const unshiftRes = arr.unshift(5)
console.log(unshiftRes,arr)
// 4 (4) [5, 10, 20, 30]
// shift: 去除原数组的前面第一个元素,返回去除的元素
const arr = [10,20,30]
const shiftRes = arr.shift()
console.log(shiftRes,arr)
// 10 (2) [20, 30]
总结知识点
纯函数:1.不改变原数组的元素状态,2 返回的是一个数组
纯函数:concat map filter slice
非纯函数:forEach pop push unshift shift some every reduce
7.数组slice和splice的区别
slice(start,end) start,end都是index
slice() 是深拷贝的意思 返回原数组
const arr = [10,20,30,40]
console.log(arr.slice()) //[10,20,30,40]
slice(1):是从下标为1的开始截取到数组的最后一个 返回一个数组
slice(-1):截取数组的最后一个元素,返回一个数组
const arr = [10,20,30,40]
console.log(arr.slice(1)) //[20,30,40]
console.log(arr.slice(-1)) //[40]
slice(1,3):是从下标为1的开始到下标3之间的元素 返回一个数组
const arr = [10,20,30,40]
console.log(arr.slice(1,3)) //[20,30]
splice: 剪切替换的意思 (非纯函数)
const arr = [10,20,30,40]
const spliceRes = arr.slice(1,3)
console.log(spliceRes,arr)
// [20,30] (4) [10, 'a', 'b', 40]
8.网红面试题 [10,20,30].map(parseInt)
[10,20,30].map((num,index) =>{
return parseInt(num,index)
})//[10,NaN,NaN]
9.ajax请求get和post的区别
1.get 一般用于查询操作; post 一般用于用户提交数据操作
2.get 传参是拼接在url上,post 参数是放在请求体内
3.安全性:post易于防止CSRF
名词解释CSRF:跨站请求攻击,你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账……造成的问题包括:个人隐私泄露以及财产安全
10.函数call和apply 的区别
fn.call(this, p1,p2,p3)
fn.apply(this,arguments)
总结:传参方式不同
11.事件代理(委托)是什么?
https://blog.csdn.net/weixin_49549509/article/details/116202304
12.闭包是什么,有什么特性,有什么负面影响?
(1) 闭包是指有权访问另一个函数作用域中的变量的函数。(这与当函数被调用是会创建一个执行函数和相应的作用域链。作用域链本质上是指向变量对象的指针列表,只引用,不实际包含变量对象)。作用域链中,函数内部变量对象优先级最高,然后,由最近的外部函数依次向后排。
(2) 封闭性:外界无法访问闭包内部的数据,如果在闭包内声明变量,外界是无法访问的,除非闭包主动向外界提供访问接口; 持久性:一般的函数,调用完毕之后,系统自动注销函数,而对于闭包来说,在外部函数被调用之后,闭包结构依然保存在。
(3) 缺点:由于闭包携带包含它函数的作用域,因此比其他函数占用的内存更多。
优点:减少创建全局变量 减少传递给函数的参数量 封闭性
(4)闭包可以读取函数内部的局部变量;这些变量的值始终保存在内存中
函数执行后,函数执行环境的作用域会被销毁,但是活动对象不会销毁,只有将匿名函数销毁后才可以销毁活动对象。可以将保存函数的变量赋值为null,将可销毁匿名函数作用域。
常见创建闭包方法:在一个函数内部创建另一个函数。
13.阻止事件冒泡和默认行为
event.stopPropagation()
event.preventDefault()
14.查找、添加、删除、移动DOM节点
查找:
document.getElementById
document.getElementsByTagName
document.getElementsByClassName
document.querySelectorAll
添加&移动:appendChild
删除:removeChild
15.如何减少DOM操作
1.缓存DOM查询结果
2.多次DOM操作,合并到一次插入
const list = document.getElementById('list')
//创建一个文档片段,此时还没有插入到DOM结构中
const frag = document.createDocumentFragment()
for(let i = 0;i<20;i++){
const li = document.createElement('li')
li.innerHTML = ` List item ${i}`
frag.appendChild(li)
}
//都完成之后,在统一插入到DOM结构中
list.appendChild(frag)
16.解释jsonp 原理,为何不是真正的Ajax
1、ajax和jsonp这两种技术在调用方式上看起来很像,目的也一样,都是请求一个url,然后把服务器返回的数据进行处理,因此jQuery把jsonp作为ajax的一种形式进行了封装。
2、但ajax和jsonp其实本质上是不同的东西,ajax的核心是通过XmlHttpRequest获取非本业内容,而jsonp的核心则是动态添加。
17.document load 和 ready 的区别
document load:页面的全部资源加载完才会执行的(包括DOM文档树,css文件,js文件,图片资源等)
缺点:如果图片资源较多,加载时间较长,onload后等待执行的函数需要等待较长时间,所以一些效果可能受到影响
window.addEventListener(‘load’,function(){
// XXXXX
})
ready:DOM渲染完即可执行,此时图片视频还可能没有加载完
document.addEventListener(‘DOMContentLoaded’,function(){
// XXXXX
})
18.==
和===
的区别
==
会尝试类型转换===
严格相等
19.函数声明和函数表达式的区别
函数声明:function fn() {…}
函数表达式 const fn = function () {…}
函数声明会在代码执行前预加载,而函数表达式不会
20.new Object 和Object.create() 区别
- {}等同于 new Object (), 原型 Object.prototype
- Object.create(null)没有原型
- Object.create({…})可指定原型
21.关于this的场景题
const User = {
count:1,
getCount: function(){
return this.count
}
}
console.log(User.getCount()) //1 this就是User函数本身
const func = User.getCount
console.log(func()) //undefinded 此时this指向window
//this只有在执行的时候才能确定指向,定义的时候是不知道的
22.手写字符串trim保证浏览器兼容
String.prototype.trim = function () {
return this.replace(/^\s+/,'').replace(/\s+$/,'')
}
23.获取数字中的最大值
function max(){
const nums = Array.prototype.slice.call(arguments)
let max = 0
nums.forEach(n => {
if(n > max ){
max = n
}
})
returm max
}
//第二种方法: Math.max()
24.如何捕获js中的异常?
//第一种方法:
try{
//todo
}catch(ex){
console.log(ex) // 手动捕获 catch
} finally{
//todo
}
//自动捕获
window.onerror = function (message,source,lineNum,colNum,error){
//第一,对跨域的js ,如CDN 的,不会有详细的报错信息
//第二,对于压缩的js,还要配合 sourceMap 反查到未压缩代码的行列
}
25.什么是JSON?
1.json 是一种数据格式,本质是一段字符串
2.jsco 格式和Js对象结构一致,对JS语言更友好
3.window.JSON 是一个全局对象;JSON.stringjfy JSON.parse
26.获取当前页面Url参数
//https://tmanager.moushikeji.com/subject_namage/app_course/course_list/course_set/?courseId=89&appTag=1
function query (name){
const search = location.search.substr(1)//类似array.slice(1)
console.log(search)
const reg = new RegExp(`(^|&$){name}=([^&]*)(&|$)`,'i')
const res = search.match(reg)
if(res===null){
return null
}
return res[2]
}
query('courseId')
//第二种方法:
function query (name){
const search = location.search
const p = new URLSearchParams(search)
return p.get(name)
}
console.log(query('courseId'))
27.将url 参数解析为js对象
function queryToObj(){
const res = {}
const search = location.search.substr(1) // 去掉前面的‘?’
search.split('&').forEach(paramStr => {
const arr = paramStr.split('=')
const key = arr[0]
const value= arr[1]
res[key] = value
})
return res
}
//第二种 使用URLSearchParams
function queryToObj(){
const res = {}
const pList = new URLSearchParams(location.search)
pList.forEach((val,key)=>{
res[key] = val
})
return res
}
28.手写flater
function flat(arr){
const isDeep = arr.some(item => item instanceof Array)
if(!isDeep){
return arr
}
const res = Array.prototype.concat.apply([],arr)
return flat(res)
}
const bb = flat([1,2,[3,4,[5,6]]])
console.log(bb)//[1,2,3,4,5,6]
29.数组去重
数组去重方法集锦https://blog.csdn.net/weixin_44191250/article/details/125405164?spm=1001.2014.3001.5501
30.手写深拷贝
手写深拷贝https://blog.csdn.net/weixin_44191250/article/details/125376000?spm=1001.2014.3001.5501
注意:Object.assign()并不是深拷贝,它针对拷贝一级的没问题,更深层级的会改变原数据
31.介绍RAF requestAnimateFrame