当前位置: 首页 > news >正文

前端JavaScript面试100问(中)

31、http 的理解 ?

HTTP 协议是超文本传输协议,是客户端浏览器或其他程序“请求”与 Web 服务器响应之间的应用层通信协议。HTTPS主要是由HTTP+SSL构建的可进行加密传输、身份认证的一种安全通信通道。

32、http 和 https 的区别 ?

  • 1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
  • 2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  • 3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • 4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

33、git 的常用指令有哪些 ?

git branch 分支查看git branch branch_1 增加分支git checkout branch 分支切换git merge branch_1 合并分支(合并前要切换当前分支至master)git branch -d branch_1 删除分支git remote 查看当前仓库管理的远程仓库信息git remote show origin 查看指定的远程仓库的详细信息git push --set-upstream origin branch_1 第一次将本地分支推到远程仓库git push <远程主机名> <本地分支名>:<远程分支名> 将本地分支推到远程分支git pull <远程主机名> <远程分支>:<本地分支> 将远程分支拉到本地分支git branch -d branch_0 删除本地合并后分支git brench -D branch_0 删除本地未合并分支it push origin --delete branch_0 删除远程分支git restore [filename] 进行清除工作区的改变git tag 查看标签git tag v1.0.0 打标签git push origin v1.0.0 将tag同步到远程服务器

34、平时是使用 git 指令还是图形化工具 ?

repository:git库相关操作,基本意思就是字面意思。

  • 1)资源管理器中浏览该Git库工作空间文件,省去查找路径不断点击鼠标的操作。
  • 2)启动Git bash工具(命令行工具)。
  • 3)查看当前分支文件状态,不包括未提交的信息。
  • 4)查看某个分支的文件(弹出框中可选择需要查看的版本、分支或标签),跟上一条差不多,用的比较少,可能是没有这方面的额需求。
  • 5)可视化当前分支历史、可视化所有分支历史:弹出分支操作历史,也就是gitk工具,放到
    gitk工具中介绍。
  • edit:用于操作commit时操作信息输入,只能操作文字输入部分,你没有看错。常用的快捷键大家都知道,何必要单独做成基本没啥用的。本来以为对变更的文件进行批量操作、本来以为可以对未版本跟踪的文件批量删除、本来、、、,都说了是本来。
  • Branch:新建分支(需要选择其实版本,可以根据版本号、其他分支或标签来选择)、检出分支(觉得切换分支更合适)、重命名分支、删除分支、当前分支Reset操作(会丢弃所有未提交的变更,包括工作区和索引区,当然了,有弹出框提示危险操作)。

35、Promsie.all() 使用过吗, 它是怎么使用的 ?

   promise.all()用于一个异步操作需要在几个异步操作完成后再进行时使用。promise.all()接受一个promise对象组成的数组参数,返回promise对象。当数组中所有promise都完成了,就执行当前promise对象的then方法,如果数组中有一个promise执行失败了,就执行当前promise对象的catch方法。

36、什么是三次握手和四次挥手 ?

三次握手是网络客户端跟网络服务器之间建立连接,并进行通信的过程。相当于客户端和服务器之间你来我往的3个步骤。

  • 第一次握手是建立连接,客户端发送连接请求报文,并传送规定的数据包;
  • 第二次握手是服务器端表示接收到连接请求报文,并回传规定的数据包;
  • 第三次握手是客户端接收到服务器回传的数据包后,给服务器端再次发送数据包。这样就完成了客户端跟服务器的连接和数据传送。

四次挥手表示当前这次连接请求已经结束,要断开这次连接。

  • 第一次挥手是客户端对服务器发起断开请求,
  • 第二次握手是服务器表示收到这次断开请求,
  • 第三次握手是服务器表示已经断开连接
  • 第四次握手是客户端断开连接。

37、for in 和 for of 循环的区别 ?

   `for in` 用于遍历对象的键(`key`)`for in`会遍历所有自身的和原型链上的可枚举属性。如果是数组,for in会将数组的索引(index)当做对象的key来遍历,其他的object也是一样的。
   `for of``es6`引入的语法,用于遍历 所有迭代器iterator,其中包括`HTMLCollection`,`NodeList`,`Array``Map``Set``String``TypedArray``arguments`等对象的值(`item`)

38、async/await 怎么抛出错误异常 ?

  如果可能出错的代码比较少的时候可以使用try/catch结构来了处理,如果可能出错的代码比较多的时候,可以利用async函数返回一个promise对象的原理来处理,给async修饰的函数调用后返回的promise对象,调用catch方法来处理异常。

39、 函数式编程和命令式编程的区别 ?

  • 命令式编程(过程式编程) :
   专注于”如何去做”,这样不管”做什么”,都会按照你的命令去做。解决某一问题的具体算法实现。
  • 函数式编程:把运算过程尽量写成一系列嵌套的函数调用。
     函数式编程强调没有”副作用”,意味着函数要保持独立,所有功能就是返回一个新的值,没有其他行为,尤其是不得修改外部变量的值。 所谓”副作用”,指的是函数内部与外部交互(最典型的情况,就是修改全局变量的值),产生运算以外的其他结果。

40、http 常见的响应状态码 ?

   100——客户必须继续发出请求101——客户要求服务器根据请求转换HTTP协议版本200——交易成功201——提示知道新文件的URL202——接受和处理、但处理未完成203——返回信息不确定或不完整204——请求收到,但返回信息为空205——服务器完成了请求,用户代理必须复位当前已经浏览过的文件206——服务器已经完成了部分用户的GET请求300——请求的资源可在多处得到301——删除请求数据302——在其他地址发现了请求数据303——建议客户访问其他URL或访问方式304——客户端已经执行了GET,但文件未变化305——请求的资源必须从服务器指定的地址得到306——前一版本HTTP中使用的代码,现行版本中不再使用307——申明请求的资源临时性删除400——错误请求,如语法错误401——请求授权失败402——保留有效ChargeTo头响应403——请求不允许404——没有发现文件、查询或URl405——用户在Request-Line字段定义的方法不允许406——根据用户发送的Accept拖,请求资源不可访问407——类似401,用户必须首先在代理服务器上得到授权408——客户端没有在用户指定的饿时间内完成请求409——对当前资源状态,请求不能完成410——服务器上不再有此资源且无进一步的参考地址411——服务器拒绝用户定义的Content-Length属性请求412——一个或多个请求头字段在当前请求中错误413——请求的资源大于服务器允许的大小414——请求的资源URL长于服务器允许的长度415——请求资源不支持请求项目格式416——请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段417——服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求500——服务器产生内部错误501——服务器不支持请求的函数502——服务器暂时不可用,有时是为了防止发生系统过载503——服务器过载或暂停维修504——关口过载,服务器使用另一个关口或服务来响应用户,等待时间设定值较长505——服务器不支持或拒绝支请求头中指定的HTTP版本

41、 什么是事件流以及事件流的传播机制 ?

事件触发后,从开始找目标元素,然后执行目标元素的事件,再到离开目标元素的整个过程称之为事件流。

W3C标准浏览器事件流的传播分为3个阶段:捕获阶段、目标阶段、冒泡阶段

  • 捕获阶段指找目标元素的过程,这个找的过程,是从最大的document对象到html,再到body,。。。直到目标元素。

  • 找到目标元素后,调用执行他绑定事件时对应的处理函数,这个过程被称之为目标阶段。

  • 当目标元素的事件执行结束后,再从目标元素,到他的父元素。。。body、html再到document的过程,是冒泡阶段。

42、模块化语法 ? commonJS AMD CMD ES6 Module

  • commonJS是nodejs自带的一种模块化语法,将一个文件看做是一个模块,可以将文件中导出的时候,被另一个文件导入使用。导出使用:module.exports导出。导入使用:require函数导入。

  • AMD是社区开发的模块化语法,需要依赖require.js实现,分为定义模块,导出数据和导入模块,使用数据。AMD语法的导入是依赖前置的,也就是说,需要用到的文件需要在第一次打开页面全部加载完成,造成的后果就是首屏加载很慢,后续操作会很流畅。

  • CMD是玉伯开发的模块化语法,需要依赖sea.js实现,也分为模块定义导出,和模块导入使用数据。CMD语法可以依赖前置,也可以按需导入,缓解了AMD语法的依赖前置。

  • ES6的模块化语法,类似于commonJS的语法,分为数据导出和数据导入,导入导出更加灵活。

43、 什么是懒加载和预加载 ?

  • 懒加载:懒加载也叫延迟加载,延迟加载网络资源或符合某些条件时才加载资源。常见的就是图片延时加载。
    懒加载的意义:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。
    懒惰实现方式:

    • 1.第一种是纯粹的延迟加载,使用setTimeOut或setInterval进行加载延迟.
    • 2.第二种是条件加载,符合某些条件,或触发了某些事件才开始异步下载。
    • 3.第三种是可视区加载,即仅加载用户可以看到的区域,这个主要由监控滚动条来实现,一般会在距用户看到某图片前一定距离遍开始加载,这样能保证用户拉下时正好能看到图片。
  • 预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。

两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。预加载应用如广告弹窗等。

44、token 一般存放在哪里 ? 为什么不存放在 cookie 内 ?

token一般放在本地存储中。token的存在本身只关心请求的安全性,而不关心token本身的安全,因为token是服务器端生成的,可以理解为一种加密技术。但如果存在cookie内的话,浏览器的请求默认会自动在请求头中携带cookie,所以容易受到csrf攻击。

45、 less 和 sass 的区别 ?

  • 编译环境不一样,sass是服务器端处理的,可以用Ruby、node-sass来编译;less需要引入less.js来处理输出,也可以使用工具在服务器端处理成css,也有在线编译的。
  • 变量定义符不一样,less用的是@,而sass用$。
  • sass支持分支语句,less不支持

44、浏览器的同源策略机制 ?

同源策略,又称SOP,全称Same Origin Policy,是浏览器最基本的安全功能。站在浏览器的较短看网页,如果网络上的接口可以不受限制、无需授权随意被人调用,那将是一个非常严重的混乱场景。浏览器为了安全有序,内部实现了同源策略。同源策略,指的是浏览器限制当前网页只能访问同源的接口资源。所谓同源,指当前页面和请求的接口,两方必须是同协议、且同域名、且同端口。只要有一个不相同,则会受到浏览器额约束,不允许请求。但当一个项目变的很大的时候,将所有内容放在一个网站或一个服务器中会让网站变的臃肿且性能低下,所以,在一些场景中,我们需要跨过同源策略,请求到不同源的接口资源,这种场景叫跨域。跨域大致有3种方案:
  • jsonp

    这种方式是利用浏览器不限制某些标签发送跨域请求,例如link、img、iframe、script。通常请求请求回来的资源要在js中进行处理,所以jsonp跨域是利用script标签进行发送,且这种请求方式只能是get请求。

  • cors

    这种方式是让接口资源方面进行授权,授权允许访问。在接口资源处添加响应头即可通过浏览器的同源策略,响应头具体的键值对如下:

    {Access-Control-Allow-Origin: '*'}
    
  • proxy

    这种方式属于找外援的一种方式,浏览器只能限制当前正在打开的web页面发送请求,但无法限制服务器端请求接口资源。所以我们可以将请求发送到自己服务器,然后自己服务器去请求目标接口资源,最后自己服务器将接口资源返回给当前页面,类似于找外援代替自己请求目标接口资源。

    这种方式通常要对服务器进行代理配置,需要对apache服务器、nginx服务器、nodejs服务器进行配置。

45、 浏览器的缓存有哪些 ? 什么时候使用强制缓存 ? 什么时候使用协商缓存 ?

当我们访问同一个页面时,请求资源、数据都是需要一定的耗时,如果可以将一些资源缓存下来,那么从第二次访问开始,就可以减少加载时间,提高用户体验,也能减轻服务器的压力。浏览器缓存分为强缓存和协商缓存,当存在缓存时,客户端第一次向服务器请求数据时,客户端会缓存到内存或者硬盘当中,当第二次获取相同的资源,强缓存和协商缓存的应对方式有所不同。强缓存:当客户端第二次向服务器请求相同的资源时,不会向服务器发送请求,而是直接从内存/硬盘中间读取。缓存由服务器的响应头里 cache-control 和 expires 两个字段决定协商缓存:当客户端第二次向服务器请求相同的资源时,先向服务器发送请求"询问"该请求的文件缓存在ben'd与服务器相比是否更改,如果更改,则更新文件,如果没有就从内存/硬盘中读取。协商缓存由 last-modified 和 etag两个字段决定

46、 数组方法 forEach 和 map 的区别 ?

forEach和map都是循环遍历数组中的每一项。forEach() 和 map() 里面每一次执行匿名函数都支持3个参数:数组中的当前项item,当前项的索引index,原始数组input。匿名函数中的this都是指Window。只能遍历数组。他们的区别是:forEach没有返回值,但map中要有返回值,返回处理后的所有新元素组成的数组。

47、 什么是函数作用域 ? 什么是作用域链 ?

作用域就是在代码执行过程中,形成一个独立的空间,让空间内的变量不会邪泄露在空间外,也让独立空间内的变量函数在独立空间内运行,而不会影响到外部的环境。作用域分为全局作用域和局部作用域,也就是本来有一个巨大的空间,空间内定义的函数内部,就形成了一个独立的小空间,全局作用域是最大的作用域。但是当独立空间内的数据不能满足需求时,是可以从外部获取数据的,也就是说这样的独立空间之间是可以有层级关系的,外部的空间不可以从内部的空间获取数据,但内部的空间可以。当子级空间在父级空间中获取数据的时,父级空间没有的话,父级空间也会到他的父级空间中查找数据,这样形成的链式结构叫作用域链。当将一个变量当做值使用时,会先在当前作用域中查找这个变量的定义和数据,如果没有定义的话,就会去父级作用域中查找,如果父级作用域中有的话就使用这个值,如果父级作用域中也没有的话,就通过父级作用域查找他的父级作用域,直到找到最大的作用域-全局,如果全局也没有就报错。当将一个变量当做数据容器存储,也就是给变量赋值的时候,也要先在自己作用域中查找变量的定义,如果没有就在上一级作用域中查找,直到全局,如果全局作用域中也没有这个变量的定义,就在全局定义这个变量并赋值。

48、 ES6 中 Set 和 Map 的原理 ?

Set 是无重复值的有序列表。根据 `Object.is()`方法来判断其中的值不相等,以保证无重复。 Set 会自动移除重复的值,因此你可以使用它来过滤数组中的重复值并返回结果。 Set并不是数组的子类型,所以你无法随机访问其中的值。但你可以使用`has()` 方法来判断某个值是否存在于 Set 中,或通过 `size` 属性来查看其中有多少个值。 Set 类型还拥有`forEach()`方法,用于处理每个值Map 是有序的键值对,其中的键允许是任何类型。与 Set 相似,通过调用 `Object.is()`方法来判断重复的键,这意味着能将数值 5 与字符串 "5" 作为两个相对独立的键。使用`set()` 方法能将任何类型的值关联到某个键上,并且该值此后能用 `get()` 方法提取出来。Map 也拥有一个 `size` 属性与一个 `forEach()` 方法,让项目访问更容易。

49、 0.1 + 0.2 为什么不等于 0.3, 在项目中遇到要怎么处理 ?

计算机内部存储数据使用2进制存储,两个数字进行的数学运算,首先是将这两个数字以2进制形式,存储在计算机内部,然后在计算机内部使用两个2进制数字进行计算,最后将计算结果的2进制数字转为10进制展示出来。由于10进制的小数在转2进制的时候,规则是小数部分乘以2,判断是否得到一个整数,如果得到整数,转换完成;如果没有得到整数,则继续乘以2判断。所以,0.1和0.2在转换2进制的时候,其实是一个无限死循环,也就是一直乘以2没有得到整数的时候,但计算机内部对于无线死循环的数据,会根据一个标准保留52位。也就是说,计算机内部在存储0.1和0.2的时候,本来就不精准,两个不精准的小数在计算后,距离精准的结果是有一定误差的。项目中碰到这种情况,有3种处理方法:
  • 将小数乘以10的倍数,转为整数,然后计算,计算完成后,再缩小10的倍数,例如:
      var result = ((0.1 * 10) + (0.2 * 10)) / 10// result === 0.3

  • 使用数字的toFixed方法,强制保留小数点后多少位,例:
      var result = (0.1 + 0.2).toFixed(2)// result === 0.30

  • 自定义数字运算方法,当需要进行数学运算的时候,不直接进行,调用自定义的方法进行,例:(加法封装)
  function add(...args){var num = args.find(item => {if(item != 0 && !item){throw new Error("数学运算要使用数字")}})var arr = args.map(item => {var index = (item+'').indexOf('.')if(index >= 0){return (item+'').split('.')[1].length}})arr = arr.filter(item => item)if(arr.length){var max = Math.max(...arr)var data = args.map(item => item * Math.pow(10, max))var data.reduce((a, b) => a + b) / Math.pow(10, max)}else{var data = argsreturn data.reduce((a, b) => a + b)}}// 调用使用:var num1 = add(0.1, 0.2)console.log(num1); // 0.3var num2 = add(1, 2)console.log(num2); // 3var num3 = add(1, 2.1)console.log(num3); // 3.1

50、 什么是模块化思想 ?

就是JS中将不同功能的代码封装在不同的文件中, 再互相引用时不会发生命名冲突的一种思想, 大多数情况下, 一个文件就是一个模块模块化的实现,有多种方案:
  • CommonJS:

    CommonJSnodejs中使用的模块化规范
    nodejs 应用中每个文件就是一个模块,拥有自己的作用域,文件中的变量、函数都是私有的,与其他文件相隔离。模块导出:module.exports=数据,模块导入:require('模块文件路径')

  • ES6的模块化:

    模块功能主要由两个命令构成:exportimportexport命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

    一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个 JS 文件,里面使用export命令输出变量。

  • AMD (Asynchronous Module Definition):

    特点: 提倡依赖前置,在定义模块的时候就要声明其依赖的模块:导入模块require([module],callback);定义模块:define('模块名称', 函数)

  • CMD (Common Module Definition):

    CMD规范是国内SeaJS的推广过程中产生的。提倡就近依赖(按需加载),在用到某个模块的时候再去require。定义模块:define(function (require, exports, module) {}),使用模块:seajs.use()

51、 说说怎么用js 写无缝轮播图

将所有需要轮播的内容动态复制一份,放在原本的容器中,加定时器让整个容器中的内容滚动轮播,当内容轮播到left值为-原本的内容宽度时,快速将内容切换到left值为0的状态。

52、 JS 如何实现多线程 ?

我们都知道JS是一种单线程语言,即使是一些异步的事件也是在JS的主线程上运行的(具体是怎么运行的,可以看我另一篇博客JS代码运行机制)。像setTimeout、ajax的异步请求,或者是dom元素的一些事件,都是在JS主线程执行的,这些操作并没有在浏览器中开辟新的线程去执行,而是当这些异步操作被操作时或者是被触发时才进入事件队列,然后在JS主线程中开始运行。首先说一下浏览器的线程,浏览器中主要的线程包括,UI渲染线程,JS主线程,GUI事件触发线程,http请求线程。JS作为脚本语言,它的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。(这里这些问题我们不做研究)但是单线程的语言,有一个很致命的确定。如果说一个脚本语言在执行时,其中某一块的功能在执行时耗费了大量的时间,那么就会造成阻塞。这样的项目,用户体验是非常差的,所以这种现象在项目的开发过程中是不允许存在的。其实JS为我们提供了一个Worker的类,它的作用就是为了解决这种阻塞的现象。当我们使用这个类的时候,它就会向浏览器申请一个新的线程。这个线程就用来单独执行一个js文件。
    var worker = new Worker(js文件路径);
那么这个语句就会申请一个线程用来执行这个js文件。这样也就实现了js的多线程。

53、 闭包的使用场景 ?

一个函数被当作值返回时,也就相当于返回了一个通道,这个通道可以访问这个函数词法作用域中的变量,即函数所需要的数据结构保存了下来,数据结构中的值在外层函数执行时创建,外层函数执行完毕时理因销毁,但由于内部函数作为值返回出去,这些值得以保存下来。而且无法直接访问,必须通过返回的函数。这也就是私有性。本来执行过程和词法作用域是封闭的,这种返回的函数就好比是一个虫洞,开了挂。闭包的形成很简单,在执行过程完毕后,返回函数,或者将函数得以保留下来,即形成闭包。
  • 防抖:
    function debounce(fn, interval) {let timer = null; // 定时器return function() {// 清除上一次的定时器clearTimeout(timer);// 拿到当前的函数作用域let _this = this;// 拿到当前函数的参数数组let args = Array.prototype.slice.call(arguments, 0);// 开启倒计时定时器timer = setTimeout(function() {// 通过apply传递当前函数this,以及参数fn.apply(_this, args);// 默认300ms执行}, interval || 300)}}
  • 节流:
    function throttle(fn, interval) {let timer = null; // 定时器let firstTime = true; // 判断是否是第一次执行// 利用闭包return function() {// 拿到函数的参数数组let args = Array.prototype.slice.call(arguments, 0);// 拿到当前的函数作用域let _this = this;// 如果是第一次执行的话,需要立即执行该函数if(firstTime) {// 通过apply,绑定当前函数的作用域以及传递参数fn.apply(_this, args);// 修改标识为null,释放内存firstTime = null;}// 如果当前有正在等待执行的函数则直接返回if(timer) return;// 开启一个倒计时定时器timer = setTimeout(function() {// 通过apply,绑定当前函数的作用域以及传递参数fn.apply(_this, args);// 清除之前的定时器timer = null;// 默认300ms执行一次}, interval || 300)}}
  • 迭代器:
    var arr =['aa','bb','cc'];function incre(arr){var i=0;return function(){//这个函数每次被执行都返回数组arr中 i下标对应的元素return arr[i++] || '数组值已经遍历完';}}var next = incre(arr);console.log(next());//aaconsole.log(next());//bbconsole.log(next());//ccconsole.log(next());//数组值已经遍历完
  • 缓存:
    var fn=(function(){var cache={};//缓存对象var calc=function(arr){//计算函数var sum=0;//求和for(var i=0;i<arr.length;i++){sum+=arr[i];}return sum;}return function(){var args = Array.prototype.slice.call(arguments,0);//arguments转换成数组var key=args.join(",");//将args用逗号连接成字符串var result , tSum = cache[key];if(tSum){//如果缓存有   console.log('从缓存中取:',cache)//打印方便查看result = tSum;}else{//重新计算,并存入缓存同时赋值给resultresult = cache[key]=calc(args);console.log('存入缓存:',cache)//打印方便查看}return result;}})();fn(1,2,3,4,5);fn(1,2,3,4,5);fn(1,2,3,4,5,6);fn(1,2,3,4,5,8);fn(1,2,3,4,5,6);
  • getter和setter:
    function fn(){var name='hello'setName=function(n){name = n;}getName=function(){return name;}//将setName,getName作为对象的属性返回return {setName:setName,getName:getName}}var fn1 = fn();//返回对象,属性setName和getName是两个函数console.log(fn1.getName());//getterfn1.setName('world');//setter修改闭包里面的nameconsole.log(fn1.getName());//getter
  • 柯里化:
    function curryingCheck(reg) {return function(txt) {return reg.test(txt)}}var hasNumber = curryingCheck(/\d+/g)var hasLetter = curryingCheck(/[a-z]+/g)hasNumber('test1')      // truehasNumber('testtest')   // falsehasLetter('21212')      // false
  • 循环中绑定事件或执行异步代码:
    var p1 = "ss";var p2 = "jj";function testSetTime(para1,para2){return (function(){console.log(para1 + "-" + para2);})}var test = testSetTime(p1, p2);setTimeout(test, 1000);setTimeout(function(){console.log(p1 + "-" + p2)},1000)
  • 单例模式:
    var Singleton = (function () {var instance;function createInstance() {return new Object("I am the instance");}return {getInstance: function () {if (!instance) {instance = createInstance();}return instance;}};})();

54、 常见的兼容问题有哪些 ?

  • 获取标签节点:

    document.getElementsByClassName(‘类名’)在低版本ie中不兼容。解决方法是使用其他方式获取:

      document.getElementById('id名')document.getElementsByTagName('标签名')document.getElementsByName('name属性值')document.querySelector('css选择器')document.querySelectorAll('css选择器')

* 获取卷去的高度
      // 当有文档声明的时候document.documentElement.scrollTopdocument.documentElement.srollLeft// 没有文档声明的时候document.body.scrollTopdocument.body.scrollLeft
* 解决办法使用兼容写法:
      // 获取var t = document.documentElement.scrollTop || document.body.scrollTopvar l = document.documentElement.srollLeft || document.body.scrollLeft// 设置document.documentElement.scrollTop = document.body.scrollTop = 数值document.documentElement.srollLeft = document.body.scrollLeft = 数值

  • 获取样式
      // W3C标准浏览器window.getComputedStyle(元素)// 低版本IE中元素.currentStyle
  • 使用函数封装的方式兼容:
      function getStyle(ele,attr){if(window.getComputedStyle){return getComputedStyle(ele)[attr]}else{return ele.currentStyle[attr]}}

  • 事件侦听器
      // W3C浏览器ele.addEventListener(事件类型,函数)// 低版本Ieele.attachEvent('on事件类型',函数)
  • 使用函数封装的方式解决:
      function bindEvent(ele,type,handler){if(ele.addEventListener){ele.addEventListener(type,handler)}else if(ele.attachEvent){ele.attachEvent('on'+type,handler)}else{ele['on'+type] = handler}}	

  • 事件解绑
      // W3C浏览器ele.removeEventListener(事件类型,函数)// 低版本Ieele.detachEvent('on事件类型',函数)
  • 使用函数封装的方式解决:
      function unBind(ele,type,handler){if(ele.removeEventListener){ele.removeEventListener(type,handler)}else if(ele.detachEvent){ele.detachEvent('on'+type,handler)}else{ele['on'+type] = null}}

  • 事件对象的获取
      // W3C浏览器元素.on事件类型 = function(e){}元素.addEventListener(事件类型,fn)function fn(e){}// 在低版本IE中元素.on事件类型 = function(){ window.event }元素.addEventListener(事件类型,fn)function fn(){window.event}
  • 使用短路运算符解决:
      元素.on事件类型 = function(e){var e = e || window.event}元素.addEventListener(事件类型,fn)function fn(e){var e = e || window.event}

  • 阻止默认行为
      // W3C浏览器元素.on事件类型 = function(e){e.preventDefault()}// 在低版本IE中元素.on事件类型 = function(){ window.event.returnValue = false }
  • 通过封装函数解决;
      元素.on事件类型 = function(e){var e = e || window.evente.preventDefault?e.preventDefault():e.returnValue=false}

  • 阻止事件冒泡
      // W3C浏览器元素.on事件类型 = function(e){e.stopPropagation()}// 在低版本IE中元素.on事件类型 = function(){ window.event.cancelBubble = true }
  • 通过函数封装解决:
      元素.on事件类型 = function(e){var e = e || window.evente.stopPropagation?e.stopPropagation():e.cancelBubble=true}

  • 获取精准的目标元素
      // W3C浏览器元素.on事件类型 = function(e){e.target}// 在低版本IE中元素.on事件类型 = function(){ window.event.srcElement }
  • 通过短路运算符解决:
      元素.on事件类型 = function(e){var e = e || window.eventvar target = e.target || e.srcElement;}

  • 获取键盘码
      // W3C浏览器元素.on事件类型 = function(e){e.keyCode}// 在低版本火狐中元素.on事件类型 = function(e){e.which}
  • 通过短路运算符解决:
      元素.on事件类型 = function(e){var e = e || window.eventvar keycode = e.keyCode || e.which;}	

55、 在 JS 中如何阻止事件冒泡 ?

使用事件对象阻止事件冒泡,以前的w3c浏览器中,使用事件对象的方法阻止:

    事件对象.stopPropagation()

在ie低版本浏览器中,使用事件对象的属性阻止:

    事件对象.cancelBubble = true

现在的w3c浏览器也支持ie低版本浏览器中的写法,所以以前在阻止事件冒泡的时候,需要考虑兼容写法,现在就不需要了,直接用ie低版本浏览器中的写法即可。

56、两个数组 var A = [1, 5, 6]; var B = [2, 6, 7],实现一个方法,找出仅存在于A 或者 仅 存在于B中的所有数字。

    function getDiff(arr, brr){// 仅存在于arr中的内容var onlyArr = arr.filter(item => !brr.some(v => item === v))// 仅存在于brr中的内容var onlyBrr = brr.filter(v => !arr.some(item => v === item))// 需要哪个就返回哪个,或者一起返回return {"仅存在于arr中的内容": onlyArr,"仅存在于brr中的内容": onlyBrr}}

57、 你了解构造函数吗 ? class 是什么 ? 两者有什么区别 ?

在es5中构造函数其实就是在定义一个类,可以实例化对象,es6中class其实是构造函数的语法糖。但还是有点区别的:
  • 在class内部和class的方法内部,默认使用严格模式
  • class类不存在预解析,也就是不能先调用class生成实例,再定义class类,但是构造函数可以。
  • class中定义的方法默认不能被枚举,也就是不能被遍历。
  • class必须使用new执行,但是构造函数没有new也可以执行。
  • class中的所有方法都没有原型,也就不能被new
  • class中继承可以继承静态方法,但是构造函数的继承不能。

58、是否存在a的值(a0 && a1)为true 的情况 ?

    var value = -1Object.defineProperty(window,'a',{get(){return value+=1;}})if(a===0&&a===1){ // trueconsole.log('success')}

59、for (var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, 1000); } 要求:输出0,1,2,3,4

首先这个面试题考察的是对于js中异步代码以及作用域的理解:js中常见的异步代码包括定时器和ajax。js执行代码的流程是碰到同步代码就执行,碰到异步就交给浏览器的webAPI处理,当webAPI中的异步该执行时,webAPI会将需要执行的回调函数放在任务队列中,等候执行,所以,js中所有的异步代码总会在所有同步代码执行结束后,再执行任务队列中的代码。在这个问题中,循环是同步代码,定时器是异步代码,所以整个循环都执行结束以后才会执行定时器代码。for循环中使用var定义的变量是全局变量,定时器回调函数中输出变量的时候,根据作用域规则,先在当前作用域中变量i的定义表达式,如果没有找到,就去上一级作用域中找,此时,在局部作用域中没有找到,去上级作用域中,也就是全局找到了,全局中的i,因为循环已经执行结束了,所以i的值是5。最终,会输出5个5。其次考察的是对于类似问题的解决方式,间接性判断你是否有过类似情况的开发:这个问题的解决思路就是让回调函数中输出i的时候,不要去全局中找i,因为全局的i在循环执行结束后已经变成5了,根据这个思路,有2种解决办法:
  • 在异步代码外面嵌套一层函数作用域
       for(var i = 0;i < 5; i++){(function(i) {setTimeout(function() {console.log(i)}, 1000)})(i)}

原理是自调用函数会产生作用域,循环5次就会产生5个作用域,每个作用域代码在执行的时候都有形参i传递。所以每个作用域中的i都是不同的,分别是:0 1 2 3 4。当作用域中的异步代码执行的时候,自己作用域中没有i变量的定义,然后上级作用域就是自调用函数的作用域,找到了单独的i。最终可以输出:0 1 2 3 4

    1. 将循环代码中的var换成es6的let
       for(let i = 0;i < 5; i++){setTimeout(function() {console.log(i)}, 1000)}

es6的let自带块级作用域,原理跟第一种解决思路是一样的,转成es5后,代码是一样的。

60、实现一个 add 方法 使计算结果能够满足如下预期: - add(1)(2)(3)() = 6 - add(1,2,3)(4)() = 10

    function add (...args) {if(args.length === 3){return -(args[0] * args[1] * 2 + args[2] * 2)}else{return -args[args.length-1]}}function currying (fn) {let args = []return function _c (...newArgs) {if (newArgs.length) {args = [...args,...newArgs]return _c} else {return fn.apply(this, args)}}}let addCurry = currying(add)var a = addCurry(1)(2)(3)()console.log(-a); // 10var b = addCurry(1,2,3)(4)()console.log(6 - b); // 10

相关文章:

前端JavaScript面试100问(中)

31、http 的理解 ? HTTP 协议是超文本传输协议&#xff0c;是客户端浏览器或其他程序“请求”与 Web 服务器响应之间的应用层通信协议。HTTPS主要是由HTTPSSL构建的可进行加密传输、身份认证的一种安全通信通道。32、http 和 https 的区别 ? 1、https协议需要到ca申请证书&…...

Docker 安全及日志管理与https部署

容器的安全性问题的根源在于容器和宿主机共享内核。如果容器里的应用导致Linux内核崩溃&#xff0c;那么整个系统可能都会崩溃。与虚拟机是不同的&#xff0c;虚拟机并没有与主机共享内核&#xff0c;虚拟机崩溃一般不会导致宿主机崩溃。 Docker 容器与虚拟机的区别 虚拟机通…...

2.3 HLSL常用函数

一、函数介绍 函数图像参考网站&#xff1a;Graphtoy 1.基本数学运算 函数 含义 示例图 min(a,b) 返回a、b中较小的数值 mul(a,b) 两数相乘用于矩阵计算 max(a,b) 返回a、b中较大的数值 abs(a) 返回a的绝对值 round(x) 返回与x最近的整数 sqrt(x) 返回x的…...

互联网的发展

概述 互联网是现代社会中举足轻重的一个领域&#xff0c;它的发展对于人类的生活和工作方式产生了深远的影响。互联网的发展经历了几个阶段&#xff0c;从初创阶段到如今的高度普及和深入应用&#xff0c;本文将详细介绍互联网的发展状况。 第一阶段&#xff1a;互联网的起源…...

STM32 CAN通讯实验程序

目录 STM32 CAN通讯实验 CAN硬件原理图 CAN外设原理图 TJA1050T硬件描述 实验线路图 回环实验 CAN头文件配置 CAN_GPIO_Config初始化 CAN初始化结构体 CAN筛选器结构体 接收中断优先级配置 接收中断函数 main文件 实验现象 补充 STM32 CAN通讯实验 CAN硬件原理图…...

Python代码片段之Django静态文件URL的配置

首先要说明这段python代码并不完整&#xff0c;而且我也没有做过测试&#xff0c;只是我在工作时参考了其中的一些个方法。这是我在找python相关源码资料里看到的一段代码&#xff0c;是Django静态文件URL配置代码片段2&#xff0c;代码中有些方法还是挺技巧的&#xff0c;做其…...

基于飞桨paddle的极简方案构建手写数字识别模型测试代码

基于飞桨paddle的极简方案构建手写数字识别模型测试代码 原始测试图片为255X252的图片 因为是极简方案采用的是线性回归模型&#xff0c;所以预测结果数字不一致 本次预测的数字是 [[3]] 测试结果&#xff1a; PS E:\project\python> & D:/Python39/python.exe e:/pro…...

soft ip与hard ip

ip分soft和hard两种&#xff0c;soft就是纯代码&#xff0c;买过来要自己综合自己pr。hard ip如mem和analog与工艺有关。 mem的lib和lef是memory compiler产生的&#xff0c;基于bitcell&#xff0c;是foundry给的。 我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起…...

MyBatisPlus从入门到精通-2

接着上一讲的Mp的分页功能 下面我们讲解条件查询功能和其他功能 解决一下日志输出和banner问题 每次卞就会输出这些日志 很不美观&#xff0c;现在我们关闭一下 这样建个xml&#xff0c;文件名为logback.xml 文件内容改成这样 配置了logback但是里面什么都没写就不会说有日…...

AI面试官:Asp.Net 中使用Log4Net (一)

AI面试官&#xff1a;Asp.Net 中使用Log4Net (一) 当面试涉及到使用log4net日志记录框架的相关问题时&#xff0c;通常会聚焦在如何在.NET或.NET Core应用程序中集成和使用log4net。以下是一些关于log4net的面试题目&#xff0c;以及相应的解答、案例和代码&#xff1a; 文章目…...

Selenium自动化元素定位方式与浏览器测试脚本

Selenium八大元素定位方法 Selenium可以驱动浏览器完成各种操作&#xff0c;比如模拟点击等。要想操作一个元素&#xff0c;首先应该识别这个元素。人有各种的特征&#xff08;属性&#xff09;&#xff0c;我们可以通过其特征找到人&#xff0c;如通过身份证号、姓名、家庭住…...

人机交互与人机混合智能的区别

人机交互和人机融合智能是两个相关但不完全相同的概念&#xff1a; 人机交互是指人与计算机之间的信息交流和互动过程。它关注的是如何设计和实现用户友好的界面&#xff0c;以便人们能够方便、高效地与计算机进行沟通和操作。人机交互通常强调用户体验和界面设计&#xff0c;旨…...

【项目】轻量级HTTP服务器

文章目录 一、项目介绍二、前置知识2.1 URI、URL、URN2.2 CGI2.2.1 CGI的概念2.2.2 CGI模式的实现2.2.3 CGI的意义 三、项目设计3.1 日志的编写3.2 套接字编写3.3 HTTP服务器实现3.4 HTTP请求与响应结构3.5 EndPoint类的实现3.5.1 EndPoint的基本逻辑3.5.2 读取请求3.5.3 构建响…...

sketch如何在线打开?有没有什么软件可以辅助

Sketch 在线打开的方法有哪些&#xff1f;这个问题和我之前回答过的「Sketch 可以在线编辑吗&#xff1f;」是一样的答案&#xff0c;没有。很遗憾&#xff0c;Sketch 没有在线打开的方法&#xff0c;Sketch 也做不到可以在线编辑。那么&#xff0c;那些广告里出现的设计软件工…...

CSS Flex 笔记

1. Flexbox 术语 Flex 容器可以是<div> 等&#xff0c;对其设置属性&#xff1a;display: flex, justify-content 是沿主轴方向调整元素&#xff0c;align-items 是沿交叉轴对齐元素。 2. Cheatsheet 2.1 设置 Flex 容器&#xff0c;加粗的属性为默认值 2.1.1 align-it…...

Markdown常用标签及其用途-有示例

Markdown常用标签及其用途 Markdown是一种轻量级标记语言&#xff0c;具有简洁易读的特点。下面是一些常用的Markdown标签以及它们的用途&#xff0c;并附带一些示例&#xff1a; 标题 用于创建不同级别的标题&#xff0c;可通过添加一到六个#符号来表示不同级别的标题。 #…...

25.1 Knife4j-Swagger的增强插件

1.Knife4j概述 Knife4j是一款基于Swagger UI的增强插件&#xff0c;它可以为Spring Boot项目生成美观且易于使用的API文档界面。它是Swagger UI的增强版&#xff0c;提供了更多的功能和定制选项&#xff0c;使API文档更加易读和易于理解。 2.Knife4j使用 Knife4j 集Swagger2…...

用flask run代替flask run --debug

安装python-dotenv依赖。 在项目根目录下新建.flaskenv文件&#xff0c;并作如下配置&#xff1a; FLASK_ENVdevelopment FLASK_DEBUG1...

python_day14_综合案例

文件内容 导包配置 import jsonfrom pyspark import SparkContext, SparkConf import osos.environ["PYSPARK_PYTHON"] "D:/dev/python/python3.10.4/python.exe" os.environ["HADOOP_HOME"] "D:/dev/hadoop-3.0.0" conf SparkC…...

【算法题】2779. 数组的最大美丽值

题目&#xff1a; 给你一个下标从 0 开始的整数数组 nums 和一个 非负 整数 k 。 在一步操作中&#xff0c;你可以执行下述指令&#xff1a; 在范围 [0, nums.length - 1] 中选择一个 此前没有选过 的下标 i 。 将 nums[i] 替换为范围 [nums[i] - k, nums[i] k] 内的任一整…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

大学生职业发展与就业创业指导教学评价

这里是引用 作为软工2203/2204班的学生&#xff0c;我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要&#xff0c;而您认真负责的教学态度&#xff0c;让课程的每一部分都充满了实用价值。 尤其让我…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...