JavaScript面试题整理汇总
1、面试官:说说JavaScript中的数据类型?存储上的差别?
在JavaScript中,我们可以分成两种类型:基本类型和复杂类型。
两种类型的区别是:存储位置不同
基本类型主要为以下6种:
Number | String | Boolean | Undefined | null | symbol |
ES11中还多了BigInt,它们在内存中占据固定大小,保存在栈内存中
复杂数据类型:
复杂类型统称为Object,主要有Object Array Function
复杂类型的值是对象 保存在堆内存中,栈内存存储的是对象的变量标识符以及对象在堆内存中的存储地址。
2、面试官:数组的常用方法有哪些?
数组基本操作可以归纳为 增、删、改、查
2.1 增
push() | unshift() | splice() | concat() |
添加到数组末尾 | 添加到数组开头 | 三个参数,开始位置、0、插入元素 | 添加到数组末尾 |
返回数组最新长度 | 返回数组最新长度 | 返回空数组 | 返回新构建的数组 |
2.2 删
pop() | shift() | splice() | slice() |
删除数组最后一项 | 删除数组的第一项 | 两个参数,开始位置,删除数量 | 开始位置,结束位置 |
返回被删除的项 | 返回被删除的项 | 返回包含删除元素的数组 | 返回新构建的数组 |
2.3 改
splice()
传入三个参数,分别是开始位置,要删除元素的数量,要插入的任意多个元素,返回删除元素的数组,对原数组产生影响
2.4 查
indexOf() | includes() | find() |
返回查找元素在数组中的位置 | 返回查找元素在数组中的位置 | 返回第一个匹配的元素 |
没找到则返回 -1 | 找到返回true,否则false |
|
数组的排序方法
reverse() | sort() |
将数组元素方向反转 | 排序,接受比较函数,判断值如何排序 |
数组的转换方法
join()
join() 方法接收一个参数,即字符串分隔符,返回包含所有项的字符串
数组的迭代方法
forEach() | map() | filter() | some() | every() |
遍历数组 | 数组每一项都运行传入的函数 | 数组每一项都运行传入的函数 | 每一项都运行传入的测试函数 | 每一项都运行传入的测试函数 |
没有返回值 | 返回调用结果构成的数组 | true 的项会组成数组返回 | 有1个元素为 true就返回 true | 所有元素为 true就返回 true |
3、面试官:谈谈 JavaScript 中的类型转换机制
JS中有六种简单数据类型和复杂数据类型,变量的数据类型在声明时是不确定的,但是各种运算符对数据类型是有要求的,如果运算子的类型与预期不符合,就会触发类型转换机制。
常见的类型转换有:显示转换和隐式转换
3.1 显示转换,即我们很清楚可以看到这里发生了类型的转变,常见的方法有
Number() | parseInt() | String() | Boolean() |
3.2 隐式转换
1、在需要布尔值的地方,就会将非布尔值的参数自动转为布尔值,系统内部会调用Boolean函数
2、遇到预期为字符串的地方,就会将非字符串的值自动转为字符串,常发生在+运算中
3、除了+有可能把运算子转为字符串,其他运算符都会把运算子自动转成数值
(null转为数值时,值为0 。undefined转为数值时,值为NaN)
4、面试官:== 和 ===区别,分别在什么情况使用
等于操作符用两个等于号( == )表示,如果操作数相等,则会返回 true
等于操作符(==)在比较中会先进行类型转换,再确定操作数是否相等
特殊例子:null 和undefined 相等 存在 NaN 则返回 false
全等操作符由 3 个等于号( === )表示,只有两个操作数在不转换的前提下相等才返回 true。即类型相同,值也需相同
案例:undefined 和 null与自身严格相等 null 和 undefined 比较为false
5、面试官:深拷贝浅拷贝的区别?如何实现一个深拷贝?
5.1 浅拷贝
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址,即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址
下面简单实现一个浅拷贝
<body><script>function shallowCopy(obj) {const newObj = {};//prop是属性名for (let prop in obj) {//hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。if (obj.hasOwnProperty(prop)) { //newObj[prop] = obj[prop];}}return newObj}var obj = {id: '1',name: 'andy'};console.log(shallowCopy(obj));</script>
</body>
newObj= Object.assign({ }, Obj); //语法糖,简单实现,不让手写时可以使用
还可以使用拓展运算符
5.2 深拷贝
深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
常见的深拷贝方式有:
_.cloneDeep() | jQuery.extend() | JSON.stringify() | 手写循环递归 |
1、const obj2 = _.cloneDeep(obj1)
2、obj2 = $.extend(true, {}, obj1)
3、obj2=JSON.parse(JSON.stringify(obj1));
手写深拷贝
<body><script>let arr = [5, 4, 9, 8];let obj1 = {name: 'xxx',sex: '男',like: ['红色', '蓝色'],book: {title: 'js程序',price: '88'}};//手写深拷贝function deepClone(obj) {// 查看要拷贝的是数组还是对象,如果数组创建空数组,是对象创建空对象const newObj = obj instanceof Array ? [] : {};for (let k in obj) {//K属性名 obj[k]值//判断当前每个元素是否是对象或者数组 //如果还是对象,继续递归拷贝//是值,直接添加到新创建的对象或者数组里if (typeof obj[k] === 'object') {//实现一个递归拷贝newObj[k] = deepClone(obj[k])} else { //否则是值, 直接添加到新建的 newObj中newObj[k] = obj[k];}} return newObj;}console.log(deepClone(obj1));</script>
</body>
6、面试官:说说你对闭包的理解?闭包使用场景
闭包指有权访问另一个函数作用域中变量的函数。
简单理解就是一个函数和对其周围状态的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure)
闭包使用场景
1、创建私有变量 2、延长变量的生命周期
一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的
闭包柯里化
柯里化的目的在于避免频繁调用具有相同参数函数的同时,又能够轻松的重用
假设我们有一个求长方形面积的函数,如果我们碰到的长方形的宽老是10,我们可以使用闭包柯里化这个计算面积的函数,之后碰到宽度为10的长方形就可以这样计算面积
而且如果遇到宽度偶尔变化也可以轻松复用
7、面试官:说说你对作用域链的理解
作用域,即变量和函数生效的区域或集合。作用域决定了代码区块中变量和其他资源的可见性
我们一般将作用域分成:1、全局作用域 2、函数作用域 3、块级作用域
全局作用域:任何不在函数中或是大括号中声明的变量,都是在全局作用域下,全局作用域下声明的变量可以在程序的任意位置访问
函数作用域也叫局部作用域:如果一个变量是在函数内部声明的它就在一个函数作用域下面。这些变量只能在函数内部访问,不能在函数以外去访问
块级作用域:ES6引入了let和const关键字,和var关键字不同,在大括号中使用let和const声明的变量存在于块级作用域中。在大括号之外不能访问这些变量
作用域链:当在Javascript中使用一个变量的时候,首先Javascript引擎会尝试在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域。如果在全局作用域里仍然找不到该变量,它就会在全局范围内隐式声明该变量(非严格模式下)或是直接报错
8、面试官:JavaScript原型,原型链 ? 有什么特点?
说起原型链就要先说一下构造函数,什么是构造函数呢,它可以用来创建对象实例,当我们new了构造函数就会创建一个实例,但是构造函数有一个问题就是里面存放的函数方法每new一次就会多开辟一份内存空间,为了解决这个问题构造函数里面有一个属性叫prototype原型对象,专门存放公有的方法,实例对象怎么调用这个方法呢,因为所有对象身上都有对象原型__proto__,就可以通过它来调用,同时对象身上都有一个constructor 属性可以指回构造函数本身,原型链其实就是一个查找的过程,当我们想要查找对象实例身上的属性时先在本身找,找不到再用对象原型__proto__去原型对象prototype上找,再找不到再去原型对象的prototype上找,最终找不到返回最终指向null
9、面试官:Javascript如何实现继承?
继承可以使得子类具有父类别的各种属性和方法,而不需要再次编写相同的代码,在子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。使用extends 关键字实现类的继承。
classSon extends Father
常见的继承方式还有原型链继承、构造函数继承(借助 call调用Parent函数)。
10、面试官:谈谈this对象的理解
1、作为普通函数执行时,this指向window。
2、当函数作为对象的方法被调用时,this就会指向该对象。
3、构造器调用,this指向返回的这个对象。
4、箭头函数 箭头函数的this绑定看的是this所在函数定义在哪个对象下,就绑定哪个对象。如果有嵌套的情况,则this绑定到最近的一层对象上。
5、基于Function.prototype上的 apply 、 call 和 bind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。apply接收参数的是数组,call接受参数列表,`` bind方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this指向除了使用new `时会被改变,其他情况下都不会改变。若为空默认是指向全局对象window。
11、面试官:JavaScript中执行上下文和执行栈是什么?
简单的来说,执行上下文是一种对Javascript代码执行环境的抽象概念,也就是说只要有Javascript代码运行,那么它就一定是运行在执行上下文中
执行上下文的类型分为三种:
1、全局执行上下文:只有一个,浏览器中的全局对象就是 window对象,this 指向这个全局对象
2、函数执行上下文:存在无数个,只有在函数被调用的时候才会被创建,每次调用函数都会创建一个新的执行上下文
3、Eval函数执行上下文: 指的是运行在eval 函数中的代码,很少用而且不建议使用
执行上下文的生命周期包括三个阶段:创建阶段 → 执行阶段 → 回收阶段
创建阶段即当函数被调用,但未执行任何其内部代码之前,主要确定 this 的值
执行阶段:在这阶段,执行变量赋值、代码执行
如果 Javascript 引擎在源代码中声明的实际位置找不到变量的值,那么将为其分配 undefined 值
回收阶段:执行上下文出栈等待虚拟机回收执行上下文
二、执行栈
执行栈,也叫调用栈,具有后进先出结构,用于存储在代码执行期间创建的所有执行上下文
当Javascript引擎开始执行你第一行脚本代码的时候,它就会创建一个全局执行上下文然后将它压到执行栈中
每当引擎碰到一个函数的时候,它就会创建一个函数执行上下文,然后将这个执行上下文压到执行栈中
引擎会执行位于执行栈栈顶的执行上下文(一般是函数执行上下文),当该函数执行结束后,对应的执行上下文就会被弹出,然后控制流程到达执行栈的下一个执行上下文
12、面试官:说说JavaScript中的事件模型
一、事件与事件流
由于DOM是一个树结构,如果在父子节点绑定事件时候,当触发子节点的时候,就存在一个顺序问题,这就涉及到了事件流的概念,事件流都会经历三个阶段:
1、事件捕获阶段 2、处于目标阶段 3、事件冒泡阶段
事件冒泡是一种从下往上的传播方式,由最具体的元素(触发节点)然后逐渐向上传播到最不具体的那个节点,也就是DOM中最高层的父节点
事件捕获与事件冒泡相反,事件最开始由不太具体的节点最早接受事件, 而最具体的节点(触发节点)最后接受事件
二、事件模型
事件模型可以分为三种:
1、原始事件模型(DOM0级)2、标准事件模型(DOM2级)3、IE事件模型(基本不用)
原始事件模型:事件绑定监听函数比较简单,document.getElementById('.btn')
特性:绑定速度快、只支持冒泡,不支持捕获、一个类型的事件只能绑定一次
标准事件模型:事件绑定监听函数的方式 addEventListener(eventType, handler,useCapture)
特性:可以在一个DOM元素上绑定多个事件处理器,各自并不会冲突
执行时机:当第三个参数(useCapture)设置为true就在捕获过程中执行,反之在冒泡过程中执行处理函数
IE事件模型:attachEvent(eventType,handler)
13、面试官:typeof与 instanceof 区别
举个例子:
typeof 1 // 'number'
console.log(1instanceof Number); // false
typeof与instanceof都是判断数据类型的方法,区别如下:
1、typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值
2、instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型
3、而typeof 也存在弊端,它虽然可以快速判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断
如果需要通用检测数据类型,可以采用Object.prototype.toString,调用该方法,统一返回格式“[object Xxx]”的字符串
14、面试官:解释下什么是事件代理?应用场景?
事件代理,简单来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素,而事件委托在冒泡阶段完成。
当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数
应用场景:点击列表项的时候响应一个事件,可以把点击事件绑定在父级元素ul上面,然后执行事件的时候再去匹配目标元素
优点:1、减少整个页面所需的内存,提升整体性能 2、动态绑定,减少重复工作
但如focus、blur等事件没有事件冒泡机制,就无法进行事件委托。
15、面试官:说说new操作符具体干了什么?
1、首先创建了一个新的空对象
2、将对象与构建函数通过原型链连接起来
3、让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)
4、判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
16、面试官:ajax原理是什么?如何实现?
AJAX即异步的JavaScript 和XML,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页
Ajax的原理简单来说通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面
实现过程
实现 Ajax异步交互需要服务器逻辑进行配合,需要完成以下步骤:
1、创建 Ajax的核心对象XMLHttpRequest对象
2、通过 XMLHttpRequest 对象的 open() 方法与服务端建立连接
3、构建请求所需的数据内容,并通过XMLHttpRequest 对象的 send() 方法发送给服务器端
4、通过 XMLHttpRequest 对象提供的 onreadystatechange 事件监听服务器端你的通信状态
5、接受并处理服务端向客户端响应的数据结果
6、将处理结果更新到 HTML页面中
17、面试官:bind、call、apply区别?
apply、call、bind三者的区别在于:
1、三者都可以改变函数的this对象指向
2、三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window
3、三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入
4、bind是返回绑定this之后的函数,不会立即执行,apply、call则是立即执行
18、面试官:说说你对正则表达式的理解?应用场景?
正则表达式是一种用来匹配字符串的工具
它的设计思想是用一种描述性的语言定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的
它可由字面量或调用RegExp对象的构造函数来构建。
常见的校验规则如:
^匹配输入的开始 | $匹配输入的结束 | {n}匹配前面字符刚好出现了 n 次 | g 全局搜索 |
应用场景如验证QQ合法性、校验用户账号合法性、将url参数解析为对象等
19、面试官:说说你对事件循环的理解
JS是单线程的,为了防止一个函数执行时间过长阻塞后面的代码,所以会先将同步代码压入执行栈中,依次执行,将异步代码推入异步队列,异步队列又分为宏任务队列和微任务队列,因为宏任务队列的执行时间较长,所以微任务队列要优先于宏任务队列。微任务队列的代表就是,Promise.then,MutationObserver,宏任务的话就是setImmediate setTimeout setInterval
当主程结束,先执行准备好微任务,然后再执行准备好的宏任务,一个轮询结束。
事件循环可以简单的描述为以下四个步骤:
1、函数入栈,当Stack中执行到异步任务的时候,就将他丢给WebAPIs,接着执行同步任务,直到Stack为空;
2、此期间WebAPIs完成这个事件,把回调函数放入队列中等待执行(微任务放到微任务队列,宏任务放到宏任务队列)
3、执行栈为空时,Event Loop把微任务队列执行清空;
4、微任务队列清空后,进入宏任务队列,取队列的第一项任务放入Stack(栈)中执行,执行完成后,查看微任务队列是否有任务,有的话,清空微任务队列。重复4,继续从宏任务中取任务执行,执行完成之后,继续清空微任务,如此反复循环,直至清空所有的任务。
20、面试官:DOM常见的操作有哪些?
DOM常见的操作,主要分为:
1、创建节点2、查询节点3、更新节点4、添加节点5、删除节点
创建节点 | 获取节点 | 更新节点 | 添加节点 | 删除节点 |
createElement | querySelector | innerHTML(危险) innerText(安全) | appendChild,insertBefore | removeChild |
21、面试官:说说你对BOM的理解,常见的BOM对象你了解哪些?
BOM(Browser Object Model),浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象。其作用就是跟浏览器做一些交互效果,比如如何进行页面的后退,前进,刷新,浏览器的窗口发生变化,滚动条的滚动,以及获取客户的一些信息如:浏览器品牌版本,屏幕分辨率。
常见的BOM对象:
1、window
Bom的核心对象是window,它表示浏览器的一个实例
在浏览器中,window对象有双重角色,即是浏览器窗口的一个接口,又是全局对象
2、location
location属性描述如下
href | search | port | hostname |
完整url | url的查询字符串,通常为?后面的内容 | url的端口号,没有则为空 | 域名,不带端口号 |
3、navigator
navigator对象主要用来获取浏览器的属性,区分浏览器类型。属性较多,且兼容性比较复杂
如navigator.userAgent 返回浏览器的用户代理字符串
4、screen
保存的是浏览器窗口外面的客户端显示器的信息,比如像素宽度和像素高度
5、history
history对象主要用来操作浏览器URL的历史记录,可以通过参数向前,向后,或者向指定URL跳转,如history.go()
22、面试官:举例说明你对尾递归的理解,有哪些应用场景
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数,一般来说,递归需要有边界条件、递归前进阶段和递归返回阶段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
尾递归,即在函数尾位置调用自身
在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,递归次数过多容易造成栈溢出。这时候,我们就可以使用尾递归,即一个函数中所有递归形式的调用都出现在函数的末尾,对于尾递归来说,由于只存在一个调用记录,所以永远不会发生"栈溢出"错误
应用场景:
数组求和以及数组扁平化等
23、面试官:Cookie、sessionStorage、localStorage的区别及应用场景
相同点:存储在客户端
不同点:
1、cookie数据大小不能超过4k;sessionStorage和localStorage的存储比cookie大得多,可以达到5M+
2、cookie设置的过期时间之前一直有效;localStorage永久存储,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage数据在当前浏览器窗口关闭后自动删除
3、cookie的数据会自动的传递到服务器;sessionStorage和localStorage数据保存在本地
应用场景:标记用户与跟踪用户行为的情况,推荐使用cookie。适合长期保存在本地的数据(令牌),推荐使用localStorage。敏感账号一次性登录,推荐使用sessionStorage
24、面试官:说说JS垃圾回收机制
项目中,如果存在大量不被释放的内存(堆/栈/上下文),页面性能会变得很慢。当某些代码操作不能被合理释放,就会造成内存泄漏。我们尽可能减少使用闭包,因为它会消耗内存。
浏览器垃圾回收机制/内存回收机制:
浏览器的Javascript具有自动垃圾回收机制,垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。
1、标记清除:在js中,最常用的垃圾回收机制是标记清除:当变量进入执行环境时,被标记为“进入环境”,当变量离开执行环境时,会被标记为“离开环境”。垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后,它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉。在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存
2、引用计数:当前内存被占用一次,计数累加1次,移除占用就减1,减到0时,浏览器就回收它。
优化手段:内存优化; 手动释放:取消内存的占用即可。
(1)堆内存:fn = null 【null:空指针对象】
(2)栈内存:把上下文中,被外部占用的堆的占用取消即可。
常见内存泄漏:
在 JS 中,常见的内存泄露主要有 4 种,全局变量、闭包、DOM 元素的引用、定时器
25、面试官:说说你对函数式编程的理解?优缺点?
相比命令式编程,函数式编程更加强调程序执行的结果而非执行的过程,倡导利用若干简单的执行单元让计算结果不断渐进,逐层推导复杂的运算,而非设计一个复杂的执行过程。
优点:更简单的复用、更强大的组合性、减少代码量,提高维护性
缺点:性能较差、资源占用、递归陷阱
26、面试官:Javascript中如何实现函数缓存?函数缓存有哪些应用场景?
函数缓存,就是将函数运算过的结果进行缓存,本质上就是用空间(缓存存储)换时间(计算过程),常用于缓存数据计算结果和缓存对象
实现函数缓存主要依靠闭包、柯里化、高阶函数
应用场景:以下几种情况下,适合使用缓存:
1、对于昂贵的函数调用,执行复杂计算的函数
2、对于具有有限且高度重复输入范围的函数
3、对于具有重复输入值的递归函数
4、对于纯函数,即每次使用特定输入调用时返回相同输出的函数
27、面试官:说说Javascript 数字精度丢失的问题,如何解决?
0.1+ 0.2 === 0.3 // false
计算机存储双精度浮点数需要先把十进制数转换为二进制的科学记数法的形式,然后计算机以自己的规则存储二进制的科学记数法。因为存储时有位数限制(64位),并且某些十进制的浮点数在转换为二进制数时会出现无限循环,会造成二进制的舍入操作(0舍1入),当再转换为十进制时就造成了计算误差。
解决方案:可以处理一下得到我们期望的结果。建议使用 toPrecision 凑整并 parseFloat 转
成数字后再显示
28、面试官:什么是防抖和节流?有什么区别?如何实现?
本质上是优化高频率执行代码的一种手段
如:浏览器的 resize、scroll、keypress、mousemove 等事件在触发时,会不断地调用绑定在事件上的回调函数,极大地浪费资源,降低前端性能
为了优化体验,需要对这类事件进行调用次数的限制,对此我们就可以采用防抖(debounce)和节流(throttle)的方式来减少调用频率
防抖: n 秒后执行该事件,若在n 秒内被重复触发,则重新计时
// fn是你要调用的函数,delay是防抖的时间
function debounce(fn, delay) {// timer是一个定时器let timer = null;// 返回一个闭包函数,用闭包保存timer确保其不会销毁,重复点击会清理上一次的定时器return function () {// 保存事件参数,防止fn函数需要事件参数里的数据let arg = arguments;// 调用一次就清除上一次的定时器clearTimeout(timer);// 开启这一次的定时器timer = setTimeout(() => {// 若不改变this指向,则会指向fn定义环境fn.apply(this, arg);}, delay)}
}
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
// 时间戳 & 定时器方法
function throttle(fn, delay) {// 初始化定时器let timer = null;// 上一次调用时间let prev = null;// 返回闭包函数return function () {// 现在触发事件时间let now = Date.now();// 触发间隔是否大于delaylet remaining = delay - (now - prev);// 保存事件参数const args = arguments;// 清除定时器clearTimeout(timer);// 如果间隔时间满足delayif (remaining <= 0) {// 调用fn,并且将现在的时间设置为上一次执行时间fn.apply(this, args);prev = Date.now();} else {// 否则,过了剩余时间执行最后一次fntimer = setTimeout(() => {fn.apply(this, args)}, delay);}}
}
函数防抖关注一定时间连续触发的事件,只在最后执行一次。而函数节流一段时间内只执行一次,频率较高的事件中使用来提高性能
防抖应用场景
搜索框搜索输入,窗口大小resize等
节流应用场景
搜索框,搜索联想功能
29、面试官:如何判断一个元素是否在可视区域中?
可以通过offsetTop、scrollTop判断一个元素是否在可视区域
el.offsetTop- document.documentElement.scrollTop <= viewPortHeight
offsetTop,返回元素相对带有定位父元素上方的偏移
scrollTop,返回被卷去的上侧距离,返回数值不带单位。
根据上述公式计算元素是否在可视区域。
30、面试官:大文件上传如何做断点续传?
断点续传指的是在下载或上传时,将下载或上传任务人为的划分为几个部分
每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载。用户可以节省时间,提高速度
一般实现方式有两种:
1、服务器端返回,告知从哪开始
2、浏览器端自行处理
上传过程中将文件在服务器写为临时文件,等全部写完了(文件上传完),将此临时文件重命名为正式文件即可。
如果中途上传中断过,下次上传的时候根据当前临时文件大小,作为在客户端读取文件的偏移量,从此位置继续读取文件数据块,上传到服务器从此偏移量继续写入文件即可
实现思路:
整体思路比较简单,拿到文件,保存文件唯一性标识,切割文件,分段上传,每次上传一段,根据唯一性标识判断文件上传进度,直到文件的全部片段上传完毕
31、面试官:如何实现上拉加载,下拉刷新?
上拉加载及下拉刷新都依赖于用户交互
上拉加载:
判断页面触底我们需要先了解一下下面几个属性
scrollTop:滚动视窗的高度距离window顶部的距离,它会随着往上滚动而不断增加,初始值是0,它是一个变化的值
clientHeight:它是一个定值,表示屏幕可视区域的高度;
scrollHeight:页面不能滚动时也是存在的,此时scrollHeight等于clientHeight。scrollHeight表示body所有元素的总长度(包括body元素自身的padding)
综上我们得出一个触底公式:
scrollTop+ clientHeight >= scrollHeight
下拉刷新:
下拉刷新的本质是页面本身置于顶部时,用户下拉时需要触发的动作
关于下拉刷新的原生实现,主要分成三步:
1、监听原生touchstart事件,记录其初始位置的值,e.touches[0].pageY;
2、监听原生touchmove事件,记录并计算当前滑动的位置值与初始位置值的差值,大于0表示向下拉动,并借助CSS3的translateY属性使元素跟随手势向下滑动对应的差值,同时也应设置一个允许滑动的最大值;
3、监听原生touchend事件,若此时元素滑动达到最大值,则触发callback,同时将translateY重设为0,元素回到初始位置
32、面试官:什么是单点登录?如何实现?
单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一
SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
SSO一般都需要一个独立的认证中心(passport),子系统的登录均得通过passport,子系统本身将不参与登录操作
当一个系统成功登录以后,passport将会颁发一个令牌给各个子系统,子系统可以拿着令牌会获取各自的受保护资源,为了减少频繁认证,各个子系统在被passport授权以后,会建立一个局部会话,在一定时间内可以无需再次向passport发起认证
如何实现
1、同域名下的单点登录
cookie的domain属性设置为当前域的父域,并且父域的cookie会被子域所共享。path属性默认为web应用的上下文路径。利用 Cookie 的这个特点我们只需要将Cookie的domain属性设置为父域的域名(主域名),同时将 Cookie的path属性设置为根路径,将Session ID(或 Token)保存到父域中。这样所有的子域应用就都可以访问到这个Cookie。
不过这要求应用系统的域名需建立在一个共同的主域名之下,如 tieba.baidu.com 和 map.baidu.com,它们都建立在 baidu.com这个主域名之下,那么它们就可以通过这种方式来实现单点登录
2、不同域名下的单点登录
可以选择将 Session ID (或 Token )保存到浏览器的 LocalStorage 中,让前端在每次向后端发送请求时,主动将LocalStorage的数据传递给服务端
这些都是由前端来控制的,后端需要做的仅仅是在用户登录成功后,将 Session ID(或 Token)放在响应体中传递给前端
单点登录完全可以在前端实现。前端拿到 Session ID(或 Token )后,除了将它写入自己的 LocalStorage 中之外,还可以通过特殊手段将它写入多个其他域下的 LocalStorage 中
还有一种情况就是可以部署一个认证中心,用于专门处理登录请求的独立的 Web服务,但相对复杂。
33、面试官:web常见的攻击方式有哪些?如何防御?
常见的Web攻击方式有
1、XSS (Cross Site Scripting) 跨站脚本攻击
2、CSRF(Cross-siterequest forgery)跨站请求伪造
3、SQL注入攻击
一、XSS
XSS,跨站脚本攻击,允许攻击者将恶意代码植入到提供给其它用户使用的页面中
XSS的攻击目标是为了盗取存储在客户端的cookie或者其他网站用于识别客户端身份的敏感信息。一旦获取到合法用户的信息后,攻击者甚至可以假冒合法用户与网站进行交互
XSS的预防
XSS攻击的两大要素:
1、攻击者提交而恶意代码 2、浏览器执行恶意代码
针对第一个要素,我们在用户输入的过程中,过滤掉用户输入的恶劣代码,然后提交给后端
防止浏览器执行恶意代码
如在使用 .innerHTML、document.write() 时要特别小心,不要把不可信的数据作为 HTML 插到页面上,而应尽量使用 .textContent
二、CSRF
CSRF(Cross-site request forgery)跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求
利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作目的。
CSRF的预防
同源检测、双重Cookie验证等
三、SQL注入
Sql注入攻击,是通过将恶意的 Sql查询或添加语句插入到应用的输入参数中,再在后台 Sql服务器上解析执行进行的攻击
预防方式
1、严格检查输入变量的类型和格式
2、过滤和转义特殊字符
3、对访问数据库的Web应用程序采用Web应用防火墙
34、面试官:JavaScript字符串的常用方法有哪些?
我们也可将字符串常用的操作方法归纳为增、删、改、查
增:concat 用于将一个或多个字符串拼接成一个新字符串
删:举例letstringValue = "hello world"
slice() | substr() | substring() |
stringValue.slice(3) | stringValue.substr(3) | stringValue.substring(3,7) |
"lo world" | "lo world" | "lo w" |
stringValue.slice(3, 7) |
| stringValue.substring(3,7) |
"lo w" | "lo w" |
改:常见的有:
1、trim()、trimLeft()、trimRight() //删除前、后或前后所有空格符,再返回新的字符串
2、repeat() //接收一个参数,表示要将字符串复制多少次
3、toLowerCase()、 toUpperCase() //大小写转化
查:
charAt() //返回给定索引位置的字符,由传给方法的整数参数指定
indexOf() //从字符串开头去搜索传入的字符串,并返回位置(如果没找到,则返回 -1 )
转换方法:
split:把字符串按照指定的分割符,拆分成数组中的每一项
letstr = "12+23+34"
letarr = str.split("+") // [12,23,34]
替换方法:replace()
接收两个参数,第一个参数为匹配的内容,第二个参数为替换的元素(可用函数)
lettext = "cat, bat, sat, fat";
letresult = text.replace("at", "ond");
console.log(result);// "cond, bat, sat, fat"
相关文章:

JavaScript面试题整理汇总
1、面试官:说说JavaScript中的数据类型?存储上的差别?在JavaScript中,我们可以分成两种类型:基本类型和复杂类型。两种类型的区别是:存储位置不同基本类型主要为以下6种:NumberStringBooleanUnd…...

科普| 什么是云原生?
“新冠疫情从根本上改变了商业模式,工作流向在线迁移的速度比以往任何时候都要快。越来越多的公司和消费者依靠电子商务“ B2B”和B2C”,以及网上银行促进创新以满足日益增长的客户需求,云原生技术在其中发挥重要作用,同时也加速了…...

Spring Boot 3.0系列【9】核心特性篇之依赖管理
有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot版本3.0.3 源码地址:https://gitee.com/pearl-organization/study-spring-boot3 文章目录 前言依赖管理1. dependencyManagement、parent2. spring-boot-starter-parent3. spring-boot-dependencies4. 实际开发中的…...

每日算法题
目录 第一题 第二题 第一题 题目描述 小蓝要为一条街的住户制作门牌号。 这条街一共有 20202020 位住户,门牌号从 11 到 20202020 编号。 小蓝制作门牌的方法是先制作 00 到 99 这几个数字字符,最后根据需要将字符粘贴到门牌上,例如门牌…...

xss靶场绕过
目录 第一关 原理 payload 第二关 原理 payload 第三关 原理 payload 第四关 原理 payload 第五关 原理 payload 第六关 原理 payload 第七关 原理 payload 第八关 原理 payload 第九关 原理 payload 第十关 原理 payload 第十一关 原理 payl…...

【数据结构】核心数据结构之二叉堆的原理及实现
1.大顶堆和小顶堆原理 什么是堆 堆(Heap)是计算机科学中一类特殊的数据结构,通常是一个可以被看作一颗完全二叉树的数组对象。 完全二叉树 只有最下面两层节点的度可以小于2,并且最下层的叶节点集中在靠左连续的边界 只允许最后…...

Spring Cloud Alibaba+saas企业架构技术选型+架构全景业务图 + 架构典型部署方案
基于Spring Cloud Alibaba 分布式微服务高并发数据平台化(中台)思想多租户saas设计的企业开发架构,支持源码二次开发、支持其他业务系统集成、集中式应用权限管理、支持拓展其他任意子项目。 一、架构技术选型 核心框架 Spring Boot SOA Spring Cloud …...

RocketMQ-03
1. 高级功能 1.1 消息存储 分布式队列因为有高可靠性的要求,所以数据要进行持久化存储。 消息生成者发送消息MQ收到消息,将消息进行持久化,在存储中新增一条记录返回ACK给生产者MQ push 消息给对应的消费者,然后等待消费者返回A…...

大神教你在 Linux 中查看你的时区
在这篇短文中,我们将向你简单介绍几种 Linux 下查看系统时区的简单方法。在 Linux 机器中,尤其是生产服务器上的时间管理技能,是在系统管理中一个极其重要的方面。Linux 包含多种可用的时间管理工具,比如 date 或 timedatectlcomm…...

Redis持久化策略
Redis有两种持久化方式:快照(snapshotting,或者叫Redis DataBase,RDB)和只追加文件(append-only,AOF)。两种方式可以单独使用,也可以同时使用。 1.RDB模式 RDB:将某时刻所有数据都写入到硬盘里,存储为.rdb快照文件,新的快照文件生成之后会替换旧的快照文件。用户可以将…...

显著性检验【t-test、方差分析、ks检验】
显著性检验【t-test、方差分析、ks检验】 0、目录 1显著性检验基本定义(what?) 2.使用显著性检验的意义(why? ) 3.显著性检验的具体操作流程(how? ) 1、显著性检验基本定义 统计假设检验…...

访问学者在德国访学生活衣食住行攻略
德国因其优质的教育水平、高价值的学制、低廉的访学成本,逐渐成为访学领域的宠儿。对于初次来到德国生活的访问学者,一定不是很熟悉德国的真实生活情况。今天51访学网小编就给大家介绍德国访学学衣食住行,希望可以帮助到即将出国的你。 一、…...

SQL-刷题技巧-删除重复记录
一. 原题呈现 牛客 SQL236. 删除emp_no重复的记录,只保留最小的id对应的记录。 描述: 删除emp_no重复的记录,只保留最小的id对应的记录。 drop table if exists titles_test; CREATE TABLE titles_test (id int(11) not null primary key…...

基于JSP的虚拟账号交易平台
技术:Java、JSP等摘要:随着网络游戏以及各种平台的出现与更新,虚拟账号交易平台正逐渐成为电商的新增长点。当今社会,互联网发发展飞速,游戏产业也渐渐兴起,随之虚拟游戏账号的交易量逐渐增多,但…...

LeetCode201_201. 数字范围按位与
LeetCode201_201. 数字范围按位与 一、描述 给你两个整数 left 和 right ,表示区间 [left, right] ,返回此区间内所有数字 按位与 的结果(包含 left 、right 端点)。 示例 1: 输入:left 5, right 7 输…...

一款好的风险管理软件可以做什么
风险管理软件哪个好?使用Zoho Projects易于使用的项目风险管理软件,最大限度地减少收入损失并快速调整您的投资组合,保护您的项目投资。Zoho Projects的高级风险管理软件可在您最需要的时候安全的保护您的业务。使用Zoho Projects强大的风险管…...

html2canvas使用文档
一、安装 Install NPM npm install --save html2canvasInstall Yarn yarn add html2canvas二、引入 import html2canvas from html2canvas;三、使用 以 vue 举例,这样写起来比较方便 <div ref"picture"><h4>Hello world!</h4> &l…...

HTML DOM 改变 CSS
HTML DOM 允许 JavaScript 改变 HTML 元素的样式。改变 HTML 样式如需改变 HTML 元素的样式,请使用这个语法:document.getElementById(id).style.propertynew style 下面的例子会改变 <p> 元素的样式:实例<html><body><…...

基于EB工具的TC3xx_MCAL配置开发01_WDG模块配置介绍
目录 1.概述2. WDG 配置2.1 General部分配置2.2 WdgSettingsConfig配置2.2.1 配置概述2.2.2 CPU WDG具体配置2.3 WdgDemEventParameterRefs3. WDG配置注意事项1.概述 本篇开始我们基于EB Tresos工具对英飞凌TC3xx系列MCU的MCAL开发进行介绍,结合项目经验对各MCAL外设的开发及…...

Activty启动到显示的过程[二]
Activity的显示从handleResumeActivity()方法开始。 //ActivityThread.javaOverridepublic void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason) {final ActivityClientRecord r performResumeActivity(token, finalStat…...

ubuntu 18.04.06LST安装R4.0+版本报错及解决过程
1. sudo apt-get update无法正常使用 错误:13 http://ppa.launchpad.net/webupd8team/sublime-text-3/ubuntu bionic Release 404 Not Found [IP: 2620:2d:4000:1::3e 80] 解决措施:删除 webupd8team/sublime-text-3这个ppa文件。 sudo add-apt-repository --…...

数据湖架构Hudi(五)Hudi集成Flink案例详解
五、Hudi集成Flink案例详解 5.1 hudi集成flink flink的下载地址: https://archive.apache.org/dist/flink/ HudiSupported Flink version0.12.x1.15.x、1.14.x、1.13.x0.11.x1.14.x、1.13.x0.10.x1.13.x0.9.01.12.2 将上述编译好的安装包拷贝到flink下的jars目录…...

【Java学习笔记】9.Java 循环结构 - for, while 及 do...while
Java 循环结构 - for, while 及 do…while 顺序结构的程序语句只能被执行一次。 如果您想要同样的操作执行多次,就需要使用循环结构。 Java中有三种主要的循环结构: while 循环do…while 循环for 循环 在 Java5 中引入了一种主要用于数组的增强型 f…...

【面向对象初步】之面向对象VS面向过程
面向对象(ObjectorientedProgramming,OOP)编程的思想主要是针对大型软件设计而来的。面向对象编程使程序的扩展性更强、可读性更好,使的编程可以像搭积木一样简单。 面向对象编程将数据和操作数据相关的方法封装到对象中,组织代码和数据的方式更加接近人的思维,从而大大提…...

原型链(回顾)
概念prototype__proto__原型链查找机制万物皆对象判断私有/共有属性方法Object.prototype.prototype nullObject.create(proto, [propertiesObject])给类的原型上扩展属性方法的4种方法Fn.prototype.xxx xxxObject.prototype.xxx xxxf1.proto.xxx xxx原型重定向 概念 原型…...

DS内排—2-路归并排序
目录 题目描述 AC代码 题目描述 输入一组字符串,用2-路归并排序按字典顺序进行降序排序。 输入 测试次数t 每组测试数据:数据个数n,后跟n个字符串,字符串不含空格。 输出 对每组测试数据,输出2-路归并排序的每…...

深度账户抽象(Account Abstraction)第 3 部分:Wallet创建
Wallet创建 我们还没有解决的是每个用户的钱包合约最初是如何在区块链上结束的。部署合约的“传统”方式是使用 EOA 发送包含合约部署代码的且没有收件人的交易。这在这里会非常令人不满意,因为我们刚刚做了很多工作来实现它,所以有人可以在没有 EOA 的情况下与链交互。如果用…...

代码分享:面波数据快速成图
代码分享:面波数据快速成图 前言 目前,物探数据主要用surfer软件成图,surfer软件具有强大的插值和绘图功能,成图比较美观。但是,生产过程中大量的物探数据,依靠excel和surfer来成图耗费人力时间成本。本博…...

常见数据结构
一. 数据结构概述、栈、队列 1. 数据结构概述 2. 栈数据结构的执行特点 3. 常见数据结构之队列 二. 常见数据结构之数组 数组它就是内存中的一块儿连续区域。数组变量存的是数组在堆内存当中的起始地址。数组查询任意索引位置的值耗时相同,数组根据索引查询速度快。…...

Mycat
Mycat 1.概述 1.Mycat是数据中间件2.中间件:连接软件组件和应用的计算机软件,便于软件和各部件的交互3.数据中间件:连接Java应用程序与数据库的软件2.适用场景 1.Java与数据库紧耦合(直接连接)2.高访问量高并发对数据库压力(集群)3.读写请求数据不一致(读写分离+主从复制)3.…...