福州优秀网站建设公司,流量最大的网站,不会编程做网站,百度seo软件首选帝搜软件1、面试官#xff1a;说说JavaScript中的数据类型#xff1f;存储上的差别#xff1f;在JavaScript中#xff0c;我们可以分成两种类型#xff1a;基本类型和复杂类型。两种类型的区别是#xff1a;存储位置不同基本类型主要为以下6种#xff1a;NumberStringBooleanUnd…1、面试官说说JavaScript中的数据类型存储上的差别在JavaScript中我们可以分成两种类型基本类型和复杂类型。两种类型的区别是存储位置不同基本类型主要为以下6种NumberStringBooleanUndefinednullsymbolES11中还多了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 浅拷贝如果属性是基本类型拷贝的就是基本类型的值。如果属性是引用类型拷贝的就是内存地址即浅拷贝是拷贝一层深层次的引用类型则共享内存地址下面简单实现一个浅拷贝bodyscriptfunction 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
/bodynewObj Object.assign({ }, Obj); //语法糖简单实现不让手写时可以使用还可以使用拓展运算符 5.2 深拷贝深拷贝开辟一个新的栈两个对象属完成相同但是对应两个不同的地址修改一个对象的属性不会改变另一个对象的属性常见的深拷贝方式有_.cloneDeep()jQuery.extend()JSON.stringify()手写循环递归1、const obj2 _.cloneDeep(obj1)2、obj2 $.extend(true, {}, obj1)3、obj2JSON.parse(JSON.stringify(obj1));手写深拷贝bodyscriptlet 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
/body6、面试官说说你对闭包的理解闭包使用场景闭包指有权访问另一个函数作用域中变量的函数。简单理解就是一个函数和对其周围状态的引用捆绑在一起或者说函数被引用包围这样的组合就是闭包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); // falsetypeof与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则默认指向全局window3、三者都可以传参但是apply是数组而call是参数列表且apply和call是一次性传入参数而bind可以分为多次传入4、bind是返回绑定this之后的函数不会立即执行apply、call则是立即执行 18、面试官说说你对正则表达式的理解应用场景正则表达式是一种用来匹配字符串的工具它的设计思想是用一种描述性的语言定义一个规则凡是符合规则的字符串我们就认为它“匹配”了否则该字符串就是不合法的它可由字面量或调用RegExp对象的构造函数来构建。常见的校验规则如^匹配输入的开始$匹配输入的结束{n}匹配前面字符刚好出现了 n 次g 全局搜索 应用场景如验证QQ合法性、校验用户账号合法性、将url参数解析为对象等 19、面试官说说你对事件循环的理解JS是单线程的为了防止一个函数执行时间过长阻塞后面的代码所以会先将同步代码压入执行栈中依次执行将异步代码推入异步队列异步队列又分为宏任务队列和微任务队列因为宏任务队列的执行时间较长所以微任务队列要优先于宏任务队列。微任务队列的代表就是Promise.thenMutationObserver宏任务的话就是setImmediate setTimeout setInterval当主程结束先执行准备好微任务然后再执行准备好的宏任务一个轮询结束。事件循环可以简单的描述为以下四个步骤:1、函数入栈当Stack中执行到异步任务的时候就将他丢给WebAPIs,接着执行同步任务,直到Stack为空2、此期间WebAPIs完成这个事件把回调函数放入队列中等待执行微任务放到微任务队列宏任务放到宏任务队列3、执行栈为空时Event Loop把微任务队列执行清空4、微任务队列清空后进入宏任务队列取队列的第一项任务放入Stack(栈中执行执行完成后查看微任务队列是否有任务有的话清空微任务队列。重复4继续从宏任务中取任务执行执行完成之后继续清空微任务如此反复循环直至清空所有的任务。 20、面试官DOM常见的操作有哪些DOM常见的操作主要分为1、创建节点2、查询节点3、更新节点4、添加节点5、删除节点创建节点获取节点更新节点添加节点删除节点createElementquerySelectorinnerHTML(危险)innerText(安全)appendChildinsertBeforeremoveChild21、面试官说说你对BOM的理解常见的BOM对象你了解哪些BOM(Browser Object Model)浏览器对象模型提供了独立于内容与浏览器窗口进行交互的对象。其作用就是跟浏览器做一些交互效果,比如如何进行页面的后退前进刷新浏览器的窗口发生变化滚动条的滚动以及获取客户的一些信息如浏览器品牌版本屏幕分辨率。常见的BOM对象1、windowBom的核心对象是window它表示浏览器的一个实例在浏览器中window对象有双重角色即是浏览器窗口的一个接口又是全局对象2、locationlocation属性描述如下hrefsearchporthostname完整urlurl的查询字符串通常为后面的内容url的端口号没有则为空域名不带端口号3、navigatornavigator对象主要用来获取浏览器的属性区分浏览器类型。属性较多且兼容性比较复杂如navigator.userAgent 返回浏览器的用户代理字符串4、screen保存的是浏览器窗口外面的客户端显示器的信息比如像素宽度和像素高度5、historyhistory对象主要用来操作浏览器URL的历史记录可以通过参数向前向后或者向指定URL跳转如history.go() 22、面试官举例说明你对尾递归的理解有哪些应用场景在函数内部可以调用其他函数。如果一个函数在内部调用自身本身这个函数就是递归函数一般来说递归需要有边界条件、递归前进阶段和递归返回阶段。当边界条件不满足时递归前进当边界条件满足时递归返回。尾递归即在函数尾位置调用自身在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储递归次数过多容易造成栈溢出。这时候我们就可以使用尾递归即一个函数中所有递归形式的调用都出现在函数的末尾对于尾递归来说由于只存在一个调用记录所以永远不会发生栈溢出错误应用场景数组求和以及数组扁平化等23、面试官Cookie、sessionStorage、localStorage的区别及应用场景相同点存储在客户端不同点1、cookie数据大小不能超过4ksessionStorage和localStorage的存储比cookie大得多可以达到5M2、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 viewPortHeightoffsetTop返回元素相对带有定位父元素上方的偏移scrollTop返回被卷去的上侧距离返回数值不带单位。根据上述公式计算元素是否在可视区域。30、面试官大文件上传如何做断点续传断点续传指的是在下载或上传时将下载或上传任务人为的划分为几个部分每一个部分采用一个线程进行上传或下载如果碰到网络故障可以从已经上传或下载的部分开始继续上传下载未完成的部分而没有必要从头开始上传下载。用户可以节省时间提高速度一般实现方式有两种1、服务器端返回告知从哪开始2、浏览器端自行处理上传过程中将文件在服务器写为临时文件等全部写完了文件上传完将此临时文件重命名为正式文件即可。如果中途上传中断过下次上传的时候根据当前临时文件大小作为在客户端读取文件的偏移量从此位置继续读取文件数据块上传到服务器从此偏移量继续写入文件即可实现思路整体思路比较简单拿到文件保存文件唯一性标识切割文件分段上传每次上传一段根据唯一性标识判断文件上传进度直到文件的全部片段上传完毕 31、面试官如何实现上拉加载下拉刷新上拉加载及下拉刷新都依赖于用户交互上拉加载判断页面触底我们需要先了解一下下面几个属性scrollTop滚动视窗的高度距离window顶部的距离它会随着往上滚动而不断增加初始值是0它是一个变化的值clientHeight:它是一个定值表示屏幕可视区域的高度scrollHeight页面不能滚动时也是存在的,此时scrollHeight等于clientHeight。scrollHeight表示body所有元素的总长度(包括body元素自身的padding)综上我们得出一个触底公式scrollTop clientHeight scrollHeight下拉刷新下拉刷新的本质是页面本身置于顶部时用户下拉时需要触发的动作关于下拉刷新的原生实现主要分成三步1、监听原生touchstart事件记录其初始位置的值e.touches[0].pageY2、监听原生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、CSRFCross-siterequest forgery跨站请求伪造3、SQL注入攻击一、XSSXSS跨站脚本攻击允许攻击者将恶意代码植入到提供给其它用户使用的页面中XSS的攻击目标是为了盗取存储在客户端的cookie或者其他网站用于识别客户端身份的敏感信息。一旦获取到合法用户的信息后攻击者甚至可以假冒合法用户与网站进行交互XSS的预防XSS攻击的两大要素1、攻击者提交而恶意代码 2、浏览器执行恶意代码针对第一个要素我们在用户输入的过程中过滤掉用户输入的恶劣代码然后提交给后端防止浏览器执行恶意代码如在使用 .innerHTML、document.write() 时要特别小心不要把不可信的数据作为 HTML 插到页面上而应尽量使用 .textContent二、CSRFCSRFCross-site request forgery跨站请求伪造攻击者诱导受害者进入第三方网站在第三方网站中向被攻击网站发送跨站请求利用受害者在被攻击网站已经获取的注册凭证绕过后台的用户验证达到冒充用户对被攻击的网站执行某项操作目的。CSRF的预防同源检测、双重Cookie验证等三、SQL注入Sql注入攻击是通过将恶意的 Sql查询或添加语句插入到应用的输入参数中再在后台 Sql服务器上解析执行进行的攻击预防方式1、严格检查输入变量的类型和格式2、过滤和转义特殊字符3、对访问数据库的Web应用程序采用Web应用防火墙 34、面试官JavaScript字符串的常用方法有哪些我们也可将字符串常用的操作方法归纳为增、删、改、查增concat 用于将一个或多个字符串拼接成一个新字符串删举例letstringValue hello worldslice()substr()substring()stringValue.slice(3)stringValue.substr(3)stringValue.substring(3,7)lo worldlo worldlo wstringValue.slice(3, 7) stringValue.substring(3,7)lo wlo w改常见的有1、trim()、trimLeft()、trimRight() //删除前、后或前后所有空格符再返回新的字符串2、repeat() //接收一个参数表示要将字符串复制多少次3、toLowerCase()、 toUpperCase() //大小写转化查charAt() //返回给定索引位置的字符由传给方法的整数参数指定indexOf() //从字符串开头去搜索传入的字符串并返回位置如果没找到则返回 -1 转换方法split把字符串按照指定的分割符拆分成数组中的每一项letstr 122334letarr str.split() // [12,23,34]替换方法replace()接收两个参数第一个参数为匹配的内容第二个参数为替换的元素可用函数lettext cat, bat, sat, fat;letresult text.replace(at, ond);console.log(result);// cond, bat, sat, fat