为什么这一串div class删除不了,也不能修改?

用法相同,都是前后是值,中间用符号连接。根据前面的值来判断最终返回前面的值还是后面的值。

  • 使用 || 时,值1会转换为布尔值判断,为true返回值1false 返回值2

总的来说,??更加适合在不知道变量是否有值时使用。

    • 301 状态码表明目标资源被永久的移动到了一个新的 URI,任何未来对这个资源的引用都应该使用新的 URI
    • 302 状态码表示目标资源临时移动到了另一个 URI 上。由于重定向是临时发生的,所以客户端在之后的请求中还应该使用原本的 URI。
  • 注意:由于历史原因,用户代理可能会在重定向后的请求中把 POST 方法改为 GET 方法。如果不想这样,应该使用 307(Temporary Redirect) 状态码
    • 303 状态码表示服务器要将浏览器重定向到另一个资源,这个资源的 URI 会被写在响应 Header 的 Location 字段。从语义上讲,重定向到的资源并不是你所请求的资源,而是对你所请求资源的一些描述。
    • 303 常用于将 POST 请求重定向到 GET 请求,比如你上传了一份个人信息,服务器发回一个 303 响应,将你导向一个“上传成功”页面。
    • 不管原请求是什么方法,重定向请求的方法都是 GET(或 HEAD,不常用)。
    • 303 和 302 的作用很类似,除去语义差别,似乎是 302 包含了 303 的情况。确实,这是由历史原因导致的
    • 307 的定义实际上和 302 是一致的,唯一的区别在于,307 状态码不允许浏览器将原本为 POST 的请求重定向到 GET 请求上
    • 308 的定义实际上和 301 是一致的,唯一的区别在于,308 状态码不允许浏览器将原本为 POST 的请求重定向到 GET 请求上
  • 302 允许各种各样的重定向,一般情况下都会实现为到 GET 的重定向,但是不能确保 POST 会重定向为 POST
  • 303 只允许任意请求到 GET 的重定向

那为什么有了 307 和 303 还需要 302呢?把总结放在最前面。302 在最初的定义中,内容和现在的 307 是一样的,不允许重定向方法的改写(从 POST 到 GET,由于 GET 不应该有 body,实际上 body 也被改了)。但是早期浏览器在实现的时候有的实现成 303 的效果,有的实现成 307 的效果。于是在之后的标准,302 在某些浏览器中错误的实现被写进规范,成为 303,而 302 原本的效果被复制了到了 307。在最近的一次标准修订中,302 标准被修改成不再强制需要维持原请求的方法。所以就产生了现在的 302、303 和 307

第53题 简单请求和复杂请求的区别

我们在日常的开发中,经常会遇到跨域资源共享,或者进行跨域接口访问的情况。跨域资源共享( CORS)机制允许 Web 应用服务器进行跨域访问控制。

跨域资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是GET以外的 HTTP 请求,或者搭配某些 MIME 类型的POST请求),浏览器必须首先使用OPTIONS方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括Cookies和 HTTP 认证相关数据)。

在涉及到CORS的请求中,我们会把请求分为简单请求和复杂请求

/ 可以把正则分析成容易理解的可视化的逻辑脑图。其中我们可以看到,匹配规则是:全局匹配(g)左括号或者右括号,将它们替换成空格,最后返回处理后的结果。之后拿着正则处理好的结果重新在外层包裹括号,最后通过 JSON.parse 转换成数组返回。

  • 使用console.log()方法输出的时候,因为obj上有length属性和splice方法,故将其作为数组输出打印
  • 打印时因为数组未设置下标为0和1的值,故打印的结果就是empty,主动获取obj[0] = undefined

非匿名自执行函数,函数名只读

  • 如标题一样,非匿名自执行函数,函数名不可以修改,严格模式下会TypeError
  • 非严格模式下,不报错,修改也没有用。
  • 查找变量b时,立即执行函数会有内部作用域,会先去查找是否有b变量的声明,有的话,直接复制
  • IIFE的函数内部无法进行复制(类似于const)

  • 数组的原型是数组,对象的原型是对象,函数的原型是函数

  • 解析:相等(==)和全等(===)还是比较引用地址。引用类型间比较大小是按照字典序比较,就是先比第一项谁大,相同再去比第二项。

  • 解析:函数的名字不可变.

这段代码的执行结果是?

    • 首先new在函数带()时运算优先级和.一样所以从左向右执行

期望输出的是0,1,2,实际上却不会。原因就是涉及作用域,怎么解决呢?

  • [x] 使用let代替var,形成块级作用域

解法还有其他的,比如使用IIFE,形成私有作用域等等做法。

你们觉得答案是多少呢?

一道容易被人轻视的面试题

唯一需要注意的就是for语句后面带了;沙雕题

加了;,会认为for执行完,所以指定的都是空语句,最后numbers为[5]

关于0.1+0.2!=0.3浮点数计算分析与解决方法

小数点在计算机中是以二进制表示,而有些小数用二进制表示是无穷,所以才会出现上面这种精确度的问题。 一些浮点数表示成二进制

出现这个问题的原因,其实是因为数值的表示在计算机内部是用二进制的。例如,十进制的0.625,换成二进制表示就是0.101(1*2-1+0*2-2+1*2-3)0.625这个数倒还好,刚好可以准确表示出来。但如果是0.1的话呢,换成二进制就是0.00011(0011无限循环),也就是:0....,位数是无限的,只能取近似。对于这些不能准确表示的数就有可能会出现这个问题。为什么是可能呢?因为有些数的计算结果,例如0.1+0.3,它虽然也是不能精确地表示,但是它结果足够接近0.4,那取了近似后就成了0.4了。

使用简单点四舍五入方法,取了一个10位小数

Tree shaking 是一种通过清除多余代码方式来优化项目打包体积的技术

  • ES6 Module 引入进行静态分析,故而编译的时候正确判断到底加载了那些模块
  • 静态分析程序流,判断那些模块和变量未被使用或者引用,进而删除对应代码

CommonJS 是一种模块规范,最初被应用于 Nodejs,成为 Nodejs 的模块规范。运行在浏览器端的 JavaScript 由于也缺少类似的规范,在 ES6 出来之前,前端也实现了一套相同的模块规范 (例如: AMD),用来对前端模块进行管理。自 ES6 起,引入了一套新的 ES6 Module 规范,在语言标准的层面上实现了模块功能,而且实现得相当简单,有望成为浏览器和服务器通用的模块解决方案。但目前浏览器对 ES6 Module 兼容还不太好,我们平时在 Webpack 中使用的 exportimport,会经过 Babel 转换为 CommonJS 规范。在使用上的差别主要有

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
  • CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。
  • CommonJs 是动态语法可以写在判断里,ES6 Module 静态语法只能写在顶层

  • 当我们写下这段简单new Vue()代码,vue框架做了什么呢?
  • 接下来调用原型上面_init方法,是我们要重点分析的,其入参options就是我们定义的对象时传入的参数对象
  • 执行内部初始化方法,首先是options的合并,之后是一堆init方法
  • options进行合并,vue会将相关的属性和方法都统一放到vm.$options中,为后续的调用做准备工作。vm.$option的属性来自两个方面,一个是Vue的构造函数(vm.constructor)预先定义的,一个是new Vue时传入的入参对象。合并完成后的options属性包括:
  • 挂载。如果说前面几部分都是准备阶段,那么这部分是整个new Vue的核心部分,将template编译成render表达式,然后转化为大名鼎鼎的Vnode,最终渲染为真实的dom节点

Vue 初始化主要就干了几件事情,合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 datapropscomputedwatcher

第43题 说一下vue2.x中如何监测数组变化

使用了函数劫持的方式,重写了数组的方法,Vuedata中的数组进行了原型链重写,指向了自己定义的数组原型方法。这样当调用数组api时,可以通知依赖更新。如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历进行监控。这样就实现了监测数组变化。

  • 客户端使用httpsurl访问web服务器,要求与服务器建立ssl连接
  • web服务器收到客户端请求后, 会将网站的证书(包含公钥)传送一份给客户端
  • 客户端收到网站证书后会检查证书的颁发机构以及过期时间, 如果没有问题就随机产生一个秘钥
  • 客户端利用公钥将会话秘钥加密, 并传送给服务端, 服务端利用自己的私钥解密出会话秘钥
  • 之后服务器与客户端使用秘钥加密传输

HTTPS 握手过程中,客户端如何验证证书的合法性

  • 首先浏览器读取证书中的证书所有者、有效期等信息进行一一校验。
  • 浏览器开始查找操作系统中已内置的受信任的证书发布机构 CA,与服务器发来的证书中的颁发者 CA 比对,用于校验证书是否为合法机构颁发。
  • 如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的。如果找到,那么浏览器就会从操作系统中取出颁发者 CA 的公钥,然后对服务器发来的证书里面的签名进行解密。
  • 浏览器使用相同的 Hash 算法根据证书内容计算出信息摘要,将这个计算的值与证书解密的值做对比。
  • 对比结果一致,则证明服务器发来的证书合法,没有被冒充。此时浏览器就可以读取证书中的公钥,用于后续加密了。

第41题 解释以下代码输出什么

  • push 方法有意具有通用性。该方法和 call()apply() 一起使用时,可应用在类似数组的对象上。push 方法根据 length属性来决定从哪里开始插入给定的值。如果 length 不能被转成一个数值,则插入的元素索引为 0,包括 length 不存在时。当 length 不存在时,将会创建它
  • 这个对象如果有pushsplice会输出会转换为数组

笔试题,下面的代码输出什么?

第38题 (头条)异步笔试题

请写出下面代码的运行结果

js 的完美继承是寄生组合继承

第36题 实现一个柯里化函数

预先处理的思想,利用闭包的机制

  • 柯里化的定义:接收一部分参数,返回一个函数接收剩余参数,接收足够参数后,执行原函数。
  • 函数柯里化的主要作用和特点就是参数复用提前返回延迟执行
  • 柯里化把多次传入的参数合并,柯里化是一个高阶函数

第35题 实现一个简易的MVVM

实现一个简易的MVVM我会分为这么几步来:

  1. 首先我会定义一个类Vue,这个类接收的是一个options,那么其中可能有需要挂载的根元素的id,也就是el属性;然后应该还有一个data属性,表示需要双向绑定的数据
  2. 其次我会定义一个Dep类,这个类产生的实例对象中会定义一个subs数组用来存放所依赖这个属性的依赖,已经添加依赖的方法addSub,删除方法removeSub,还有一个notify方法用来遍历更新它subs中的所有依赖,同时Dep类有一个静态属性target它用来表示当前的观察者,当后续进行依赖收集的时候可以将它添加到dep.subs中。
  3. Dep()实例化一个dep对象,在get的时候调用其addSub方法添加当前的观察者Dep.target完成依赖收集,并且在set的时候调用dep.notify方法来通知每一个依赖它的观察者进行更新
  4. 完成这些之后,我们还需要一个compile方法来将HTML模版和数据结合起来。在这个方法中首先传入的是一个node节点,然后遍历它的所有子级,判断是否有firstElmentChild,有的话则进行递归调用compile方法,没有firstElementChild的话且该child.innderHTML用正则匹配满足有/\{\{(.*)\}\}/项的话则表示有需要双向绑定的数据,那么就将用正则new
  5. 完成变量替换的同时,还需要将Dep.target指向当前的这个child,且调用一下this.opt.data[key],也就是为了触发这个数据的get来对当前的child进行依赖收集,这样下次数据变化的时候就能通知child进行视图更新了,不过在最后要记得将Dep.target指为null哦(其实在Vue中是有一个targetStack栈用来存放target的指向的)
  6. 那么最后我们只需要监听documentDOMContentLoaded然后在回调函数中实例化这个Vue对象就可以了
  • childNodes会获取到所有的子节点以及文本节点(包括元素标签中的空白节点)
  • firstElementChild表示获取元素的第一个字元素节点,以此来区分是不是元素节点,如果是的话则调用compile进行递归调用,否则用正则匹配
  • 这里面的正则真的不难,大家可以看一下

第34题 实现一下hash路由

第33题 实现一个发布订阅者模式

发布订阅者模式,一种对象间一对多的依赖关系,但一个对象的状态发生改变时,所依赖它的对象都将得到状态改变的通知。

  1. 广泛应用于异步编程中(替代了传递回调函数)
  2. 对象之间松散耦合的编写代码
  • 创建订阅者本身要消耗一定的时间和内存
  • 多个发布者和订阅者嵌套一起的时候,程序难以跟踪维护
  • 创建一个对象(缓存列表)
  • on方法用来把回调函数fn都加到缓存列表中
  • emit方法取到arguments里第一个当做key,根据key值去执行对应缓存列表中的函数
  • remove方法可以根据key值取消订阅

发布订阅者模式和观察者模式的区别?

  • 发布/订阅模式是观察者模式的一种变形,两者区别在于,发布/订阅模式在观察者模式的基础上,在目标和观察者之间增加一个调度中心。
  • 观察者模式是由具体目标调度,比如当事件触发,Subject 就会去调用观察者的方法,所以观察者模式的订阅者与发布者之间是存在依赖的。
  • 发布/订阅模式由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在。

还是比较简单的,而padEnd的实现和它一样,只需要把第二层for循环里的${padString[j]}${orignStr}换下位置就可以了。

第30题 设计一个方法提取对象中所有value大于2的键值对并返回最新的对象

方法有很多种,这里提供一种比较简洁的写法,用到了ES10Object.fromEntries()

用一个正则提取字符串中所有""里内容

第28题 去除字符串首位空格

第一种:正则匹配首位空格并去除:

第三种:使用Vue中的修饰符.trim:

  • 是否知道ES10新出的两个去除空白字符的方法
  • 是否知道实际运用中有什么简便的方法(react用的不是很多,搜索了一下好像也没有看到类似Vue的修饰符,给出的解决方案是封装一个高阶组件)
  • 正则^如果不是放在[]里的话就是表示从头开始匹配;
  • \s用于匹配一个空白字符,而\S用于匹配一个非空字符
  • +表示匹配前面的模式 x 1 或多次。等价于 {1,}

第27题 用正则写一个根据name获取cookie中的值的方法

这里获取到的是类似于这样的字符串:

可以看到这么几个信息:

  • 每一项的开头可能是一个空串''(比如username的开头其实就是), 也可能是一个空字符串' '(比如user-id的开头就是)
  • 如果某项中有多个值的时候,是用","来连接的(比如user-roles的值)
  • 每一项的结尾可能是有";"的(比如username的结尾),也可能是没有的(比如user-roles的结尾)
  1. 所以我们将这里的正则拆分一下:
  • '(^| )'表示的就是获取每一项的开头,因为我们知道如果^不是放在[]里的话就是表示开头匹配。所以这里(^| )的意思其实就被拆分为(^)表示的匹配username这种情况,它前面什么都没有是一个空串(你可以把(^)理解为^它后面还有一个隐藏的'');而|表示的就是或者是一个" "(为了匹配user-id开头的这种情况)
  • +name+这没什么好说的
  • =([^;]*)这里匹配的就是=后面的值了,比如poetry;刚刚说了^要是放在[]里的话就表示"除了^后面的内容都能匹配",也就是非的意思。所以这里([^;]*)表示的是除了";"这个字符串别的都匹配(*应该都知道什么意思吧,匹配0次或多次)
  • 有的大佬等号后面是这样写的'=([^;]*)(;|$)',而最后为什么可以把'(;|$)'给省略呢?因为其实最后一个cookie项是没有';'的,所以它可以合并到=([^;]*)这一步。
  1. 最后获取到的match其实是一个长度为4的数组。比如:

所以我们是要拿第2项match[2]的值。

  1. 为了防止获取到的值是%xxx这样的字符序列,需要用unescape()方法解码。

第25题 JSONP的原理并用代码实现

基本原理:主要就是利用 script 标签的src属性没有跨域的限制,通过指向一个需要访问的地址,由服务端返回一个预先定义好的 Javascript 函数的调用,并且将服务器数据以该函数参数的形式传递过来,此方法需要前后端配合完成。

  • 后端获取到前端声明的执行函数(jsonpCallback),并以带上参数且调用执行函数的方式传递给前端
  • 前端在script标签返回资源的时候就会去执行jsonpCallback并通过回调函数的方式拿到数据了。
  • 兼容性好,在一些古老的浏览器中都可以运行

第24题 实现一个拖拽

第23题 项目中你做过哪些优化

  1. 对动态表单下拉框的内容查询提出建议。原先请求一个动态表单的页面,后台会一次性把很多的下拉列表都带出来数据量很大。后我提出意见,第一次获取的时候后台可以只返回当前选项的键值对,当用户点击下拉框的时候我才获取数据。
  2. 列表中图片懒加载。因为我们项目中不考虑兼容性,所以我们直接就用了img标签的loading="lazy"实现图片懒加载,但是如果要考虑兼容性的话,可能需要用监听window.scroll然后通过获取要懒加载图片距离可是窗口顶部的距离来判断需不需要加载。

一些需要根据用户输入的信息实时查询的输入框,需要做防抖处理

  • 先使用webpack-bundle-analyzer分析打包后整个项目中的体积结构,既可以看到项目中用到的所有第三方包,又能看到各个模块在整个项目中的占比。
  • 第三方库按需加载,例如lodash库、UI组件库
  • 使用purgecss-webpack-pluginglob插件去除无用样式(glob插件可以可以同步查找目录下的任意文件夹下的任意文件):
    • babel-loader编译慢,可以通过配置exclude来去除一些不需要编译的文件夹,还可以通过设置cacheDirectory开启缓存,转译的结果会被缓存到文件系统中
    • 问题原因:使用moment时发现会把整个locale语言包都打包进去导致打包体积过大,但是我们只需要用到中文包
  • 使用splitChunks进行拆包,抽离公共模块,一些常用配置项:

    • cacheGroups: 可以配置多个组,每个组根据test设置条件,符合test条件的模块,就分配到该组。模块可以被多个组引用,但最终会根据priority来决定打包到哪个组中。默认将所有来自 node_modules目录的模块打包至vendors组,将两个以上的chunk所共享的模块打包至default组。
  • DllPlugin动态链接库,将第三方库的代码和业务代码抽离:

手写Promise最简20行版本,实现异步链式调用

本文将围绕这个最核心的案例来讲,这段代码的表现如下:

好,写到这里先回过头来看案例

分开来看,fn 就是用户传的函数,这个函数内部调用了 resolve 函数后,就会把 promise 实例上的 cbs 全部执行一遍。

到此为止我们还不知道 cbs 这个数组里的函数是从哪里来的,接着往下看。

这里是最重要的 then 实现,链式调用全靠它:

  • 在用户调用 then 方法的时候,用户手动构造了一个 promise 并且返回,用来做异步的操作,叫它user promise

那么重点看这个 push 的函数,注意,这个函数在 promise1resolve 了以后才会执行。

结合下面这个例子来看:

  • 这样就实现了用户自己写的 resolve2 执行完毕后,then2 里的逻辑才会继续执行,也就是异步链式调用

简单实现一个可以异步链式调用的 promise,而真正的 promise 比它复杂很多很多,涉及到各种异常情况、边界情况的处理。

promise A+规范还是值得每一个合格的前端开发去阅读的

第21题 实现一个迷你版的vue

  • 串行:请求是异步的,需要等待上一个请求成功,才能执行下一个请求
  • 并行:同时发送多个请求「HTTP请求可以同时进行,但是JS的操作都是一步步的来的,因为JS是单线程」,等待所有请求都成功,我们再去做什么事情?

并发限制指的是,每个时刻并发执行的promise数量是固定的,最终的执行结果还是保持与原来的

JS实现Ajax并发请求控制的两大解决方案

tasks:数组,数组包含很多方法,每一个方法执行就是发送一个请求「基于Promise管理」

Ajax前后端数据通信「同源、跨域」

Axios也是对ajax的封装,基于Promise管理请求,解决回调地狱问题

FetchES6新增的通信方法,不是ajax,但是他本身实现数据通信,就是基于promise管理的

第18题 基于HTTP网络层的前端性能优化

  • 数据埋点及性能监控 ...

从输入URL地址到看到页面,中间都经历了啥

  • 打开网页:查找 disk cache 中是否有匹配,如有则使用,如没有则发送网络请求

浏览器对于强缓存的处理:根据第一次请求资源时返回的响应头来确定的

  • Expires:缓存过期时间,用来指定资源到期的时间(HTTP/1.0

协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程

每一次DNS解析时间预计在20~120毫秒

第四步:TCP三次握手

  • seq序号,用来标识从TCP源端向目的端发送的字节流,发起方发送数据时对此进行标记
  • ack确认序号,只有ACK标志位为1时,确认序号字段才有效,ack=seq+1
    • SYN:发起一个新连接

三次握手为什么不用两次,或者四次?

TCP作为一种可靠传输控制协议,其核心思想:既要保证数据可靠传输,又要提高传输的效率!

  • 202 Accepted :服务器已接受请求,但尚未处理(异步)
  • 204 No Content:服务器成功处理了请求,但不需要返回任何实体内容

第六步:TCP四次挥手

为什么连接的时候是三次握手,关闭的时候却是四次握手?

  • 服务器端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文
  • 但关闭连接时,当服务器端收到FIN报文时,很可能并不会立即关闭链接,所以只能先回复一个ACK报文,告诉客户端:”你发的FIN报文我收到了”,只有等到服务器端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送,故需要四步握手。

    • 对于静态资源文件实现强缓存和协商缓存(扩展:文件有更新,如何保证及时刷新?)
    • 分服务器部署,增加HTTP并发性(导致DNS解析变慢)
  • TCP的三次握手和四次挥手
    • 内容或者数据压缩(webpack等)
    • 服务器端一定要开启GZIP压缩(一般能压缩60%左右)
    • 大批量数据分批次请求(例如:下拉刷新或者分页,保证首次加载请求数据少)
  • 减少HTTP请求的次数
  • CDN服务器“地域分布式”

网络优化是前端性能优化的中的重点内容,因为大部分的消耗都发生在网络层,尤其是第一次页面加载,如何减少等待时间很重要“减少白屏的效果和时间”

  • 骨架屏:客户端骨屏 + 服务器骨架屏

  • 带宽优化及网络连接的使用HTTP1.1支持断点续传,即返回码是206Partial Content
  • 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除…
  • Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request

  • 新的二进制格式(Binary Format)HTTP1.x的解析是基于文本,基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认01的组合,基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮
  • fields表,既避免了重复header的传输,又减小了需要传输的大小
  • 服务端推送(server push),例如我的网页有一个sytle.css的请求,在客户端收到sytle.css数据的同时,服务端会将sytle.js的文件推送给客户端,当客户端再次尝试获取sytle.js时就可以直接从缓存中获取到,不用再发请求了
    • HTTP/1.0 每次请求响应,建立一个TCP连接,用完关闭
    • HTTP/1.1 「长连接」 若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞;
    • HTTP/2.0 「多路复用」多个请求可同时在一个连接上并行执行,某个请求任务耗时严重,不会影响到其它连接的正常执行;

第16题 异步串行 | 异步并行

第15题 以下代码输出什么

  • IIFE中的foo函数名相当于是使用const关键字定义的,因此没有办法对一个常量再赋值。相当于创建了一个局部的作用域,并且以 const 声明为常量,严格模式下会报错,无法对常量重新赋值,因此执行结果将打印出函数声明,等价于 const b =
  • 在严格模式下,直接报TypeError类型的错误,这类错误同数据类型相关.
  • 在非严格模式下,会忽略对常量的赋值

则由于局部变量无法找到,继续寻找全局变量,导致输出结果为 123

对象转原始类型,会调用内置的[ToPrimitive]函数,对于该函数而言,其逻辑如下:

  • 调用valueOf(),如果转换为原始类型,则返回
  • 调用toString(),如果转换为原始类型,则返回
  • 如果都没有返回原始类型,会报错

第13题 异步执行顺序问题

阅读下面代码,我们只考虑浏览器环境下的输出结果,写出它们结果打印的先后顺序,并分析出原因,小伙伴们,加油哦!

浏览器下 输出结果的先后顺序是

答案解析:这道题考察重点是 js异步执行 宏任务 微任务。

  • 一开始代码执行,输出AAAA. 1
  • 第二行代码开启一个计时器t1(一个称呼),这是一个异步任务且是宏任务,需要等到1秒后提交。
  • 第四行是个while语句,需要等待3秒后才能执行下面的代码,这里有个问题,就是3秒后上一个计时器t1的提交时间已经过了,但是线程上的任务还没有执行结束,所以暂时不能打印结果,所以它排在宏任务的最前面了。
  • 第六行又开启一个计时器t2(称呼),它提交的时间是0秒(其实每个浏览器器有默认最小时间的,暂时忽略),但是之前的t1任务还没有执行,还在等待,所以t2就排在t1的后面。(t2排在t1后面的原因是while造成的)都还需要等待,因为线程上的任务还没执行完毕。
  • Promise将执行promise函数,它参数是一个回调函数,这个回调函数内的代码是同步的,它的异步核心在于resolve和reject,同时这个异步任务在任务队列中属于微任务,是优先于宏任务执行的,(不管宏任务有多急,反正我是VIP)。所以先直接打印输出同步代码EEEE。第九行中的代码是个不存在的对象,这个错误要抛给reject这个状态,也就是catch去处理,但是它是异步的且是微任务,只有等到线程上的任务执行完毕,立马执行它,不管宏任务(计时器,ajax等)等待多久了。
  • 第十四行,这是线程上的最后一个任务,打印输出 IIII
  • 我们先找出线程上的同步代码,将结果依次排列出来:AAAA CCCC EEEE IIII
  • 然后我们再找出所有异步任务中的微任务 把结果打印出来 HHHH
  • 最后我们再找出异步中的所有宏任务,这里t1排在前面t2排在后面(这个原因是while造成的),输出结果顺序是 BBBB DDDD

await是一个表达式,如果后面不是一个promise对象,就直接返回对应的值。

await后面如果跟一个promise对象,await将等待这个promise对象的resolve状态的值value,且将这个值返回给前面的变量,此时的promise对象的状态是一个pending状态,没有resolve状态值,所以什么也打印不了。

await后面如果跟一个promise对象,await将等待这个promise对象的resolve状态的值,且将这个值返回给前面的变量,此时的promise对象的状态是一个resolve状态,它的状态值是hello,所以打印出hello。

await后面如果跟一个promise对象,await将等待这个promise对象的resolve状态的值,且将这个值返回给前面的变量,此时的promise对象的状态是一个resolve状态,它的状态值是hello,紧接着后面又执行了一个then方法,then方法又会返回一个全新的promise对象,且这个then方法中的返回值会作为这个全新的promise中resolve的值,所以最终的结果是lala。

首先考虑 fn() 执行返回一个promise对象,因为fn执行没有返回值,所以这个promise对象的状态resolve的值是undefined,且将这个undefined当作下一个then中回调函数的参数,所以打印的结果是undefined

首先考虑 fn() 执行返回一个promise对象,因为fn()执行有返回值lala,所以这个promise对象的状态resolve的值是lala,且将这个lala当作下一个then中回调函数的参数,所以打印的结果是lala。

  • async函数执行的返回结果是一个promise对象,这个函数的返回值是这个promise状态值resolve的值
  • await后面如果不是一个promise对象,将直接返回这个值
  • 以上没有考虑reject状态。

1 分析代码下面输出什么

调用Foo的静态方法,所以,打印2

  • 第二步向空对象中添加一个属性getName,值为一个函数
  • new Foo得到的实例对象上的getName方法,再将这个原型上getName方法当做构造函数继续new ,所以执行原型上的方法,打印3

2 写出打印结果,并分析出原因

  • 解析:首先,我们在全局定义了一个变量length、一个对象obj和一个函数fnlength赋值为10。接下来是fn函数,输出this.length。对象obj中,obj.length是5,obj.method是一个函数。method函数里面的形参也是一个函数,这个函数里面调用了fn函数,arguments是一个伪数组,代表method函数实际接收到的参数列表,所以arguments[0]
  • 分析完了代码的含义,我们来看输出结果。method函数当中调用的fn函数是全局当中的函数,所以this指向的是windowthis.length就是10。上面说了,arguments[0] ()代表的是调用arguments里面的第一项,也就是传参进来的fn,所以这个this指向的是arguments,method函数接收的参数是两个,所以arguments.length就是2。最后的输出结果就是

3 写出打印结果,并分析出原因

  • 解析:首先,我们在全局定义了一个变量x、一个变量y和一个函数a,函数a当中的this.x等于接收到的参数,返回this,这里要注意,返回的不是this.x,而是this。接下来我们给x赋值,值为a(5),又给y进行赋值,值为a(6)。最后,我们输出x.xy.x
  • 分析完代码的含义,我们来看输出结果。a函数传了一个参数5,那么this.x就被赋值为了5,函数athis指向的是window,也就是window.x =

  • 第一种 catch 方法可以捕获到 catch 之前整条 promise 链路上所有抛出的异常
  • 第二种 then 方法的第二个参数捕获的异常依赖于上一个 Promise 对象的执行结果

注册回调,可以捕获到前面then没有被处理的异常。第二种是回调函数写法,仅为为上一个promise 注册异常回调。

如果是promise内部报错 reject 抛出错误后,then 的第二个参数就能捕获得到,如果then的第二个参数不存在,则catch方法会捕获到。

如果是then的第一个参数函数 resolve 中抛出了异常,即成功回调函数出现异常后,then的第二个参数reject 捕获捕获不到,catch方法可以捕获到。

urls 数组中存放了 10 个接口地址。同时还定义了一个 loadDate 函数,这个函数接受一个 url 参数,返回一个 Promise 对象,该 Promise 在接口调用成功时返回 resolve,失败时返回

  • 要求:任意时刻,同时下载的链接数量不可以超过 3 个。
  • 试写出一段代码实现这个需求,要求尽可能快速地将所有接口中的数据得到。

按照题意我们可以这样做,首先并发请求 3 个 url 中的数据,当其中一条 url 请求得到数据后,立即发起对一条新 url 上数据的请求,我们要始终让并发数保持在 3 个,直到所有需要加载数据的 url 全部都完成请求并得到数据。

在你开发的过程中,什么情况下会遇到跨域问题,你是怎么解决的?

  1. API跨域可以通过服务器上nginx反向代理

cors需要后台配合设置HTTP响应头,如果请求不是简单请求(1. method:get,post,2. content-type:三种表单自带的content-type,3. 没有自定义的HTTP header),浏览器会先发送option预检请求,后端需要响应option请求,然后浏览器才会发送正式请求,cors通过白名单的形式允许指定的域发送请求

jsonp是浏览器会放过 img script标签引入资源的方式。所以可以通过后端返回一段执行js函数的脚本,将数据作为参数传入。然后在前端执行这段脚本。双方约定一个函数的名称。

联调的时候会需要跨域,线上前端站点域和后台接口不一致也需要跨域,开发时跨域可以通过代理服务器来转发请求,因为跨域本身是浏览器对请求的限制,常见的跨域处理还有JSONP和cors,jsonp是利用脚本资源请求本身就可以跨域的特性,通过与请求一起发送回调函数名,后台返回script脚本直接执行回调,但是由于资源请求是get类型,请求参数长度有限制,也不能进行post请求。cors需要后台配合设置HTTP响应头,如果请求不是简单请求(1. method:get,post,2. content-type:三种表单自带的content-type,3. 没有自定义的HTTP header),浏览器会先发送option预检请求,后端需要响应option请求,然后浏览器才会发送正式请求,cors通过白名单的形式允许指定的域发送请求

同源策略只是浏览器客户端的防护机制,当发现非同源HTTP请求时会拦截响应,但服务器依然处理了这个请求。 服务器端不拦截,所以在同源服务器下做代理,可以实现跨域。

给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。

说明:本题中,我们将空字符串定义为有效的回文串。

首先,去除字符串中的非字母和数字,然后,利用数组将字符串翻转,再和原字符串进行比较,即可得到结果。

  • 将传入的字符串,利用 toLowerCase() 方法统一转化为小写,再利用正则表达式 /[ ^ A-Za-z0-9]/g 在字符串中去除非字母和数字,得到字符串 arr
  • 将字符串 arr 转换为数组,利用数组的方法反转数组,再将数组转为字符串 newArr
  • 将字符串 arr 和 字符串 newArr 进行比较,相等即为回文串,不相等则不为回文串

写一个函数来判断它是否是 3 的幂次方

给定一个整数,写一个函数来判断它是否是 3 的幂次方

  • 3 的幂,顾名思义,需要判断当前数字是否可以一直被 3 整除

或许,我们可以考虑使用递归的方法实现。递归的思路类似于循环,只不过将循环体改为方法的递归调用。

  1. 若待定值 n 可以被 3 整除,则开始递归
  2. 若不满足上述条件,则返回 false

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数

  • 首先计算出需要循环移动的次数;
  • unshift() 方法将把它的参数插入数组的头部,并将已经存在的元素顺次地移到较高的下标处,该方法不会创建新数组,而是直接修改原数组。
  • pop() 方法将删除数组的最后一个元素,把数组长度减 1,并且返回它删除的元素的值
  • 首先还是计算出需要截取的数组元素的长度;
  • 通过数组的 splice() 方法截取需要移动的元素,然后使用扩展运算符‘...‘将截取的元素当作参数,通过 unshift() 方法将截取的 元素放到数组的前边。
  • splice() 方法可删除从 index 处开始的零个或多个元素,然后返回被删除的项目。
  • 数组的扩展运算符...相当于将数组展开,主要的使用场景是用于数组复制、合并等。
  • unshift() 方法的第一个参数将成为数组的 index 为0的新元素,如果还有第二个参数,它将成为 index 为1的新元素,以此类推。

第3题 修改嵌套层级很深对象的 key

第2题 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

  • 遍历数组,由于需要返回值,这里使用map方法
  • 使用过滤函数,过滤数组中值与当前遍历的元素的值相同的元素
  • 现在得到了一个存在多个集合的数组,而数组中唯一值的那个元素的集合肯定值存在它自己
  • 查询这个集合中长度只有1的集合,再取这个集合的第一个元素,即是只出现一次的数字

给定一个整数数组nums和一个目标值target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。

  • 并查找是否存在一个值与 target - x 相等的目标元素
}

所以我试图让一个移动菜单在单击图标时在左侧滑出,并且在您单击菜单之外后再次消失。像这样: http://codepen.io/anon/pen/LzJuq(旧的,请参阅下面的新codepen) 它在桌面和Android的默认浏览器上正常工作。 在我的手机中,在Chrome中,菜单仅在第一次打开。随后的每一次它在完成开放之前都会自行关闭。 我可以看到它尝试打开...所以我假设,因为#menu-ico




我正在使用jQuery将一个类“选定”添加到一个div当用户点击它(它将一个红色边框添加到缩略图)。同时我想从先前选择的div中移除该类。 我可以得到这个工作,如果所有div是兄弟姐妹,但文档中的其他div保持选中状态。我正在设计和开发的页面要求divs不能都是兄弟姐妹。如何在文档中的任何位置的先前选定的div上移除“selected”类,而不仅仅是兄弟姐妹? 您可以查看和编辑上的jsfiddle



我有两个选择框和一些按钮作为后类别过滤器。看看我的Fiidle。当我点击任何按钮或选择框时,我想添加背景颜色,并在点击另一个时将其删除。效果与此example中的 完全相同。 我想我必须在选择框中注册一个change事件。然而,作为一个初学者,我可以拿出被切碎该代码 $selectors.change(function() { var $selector = $(this);





我有一个div,我试图动画。该div有一个叫做peek_up的动画类,我正在使用else/if来添加一个动画,如果应用了peek_up,则会降低div,如果不是,则会将其提升。我的问题是,即使应用了peek_up,我正在使用的类来提高peek_up类的效果。我将如何去除完成后用于提升的动画? $('#box').on('click', function() { var $this =


}

我要回帖

更多关于 为什么两个div部分重叠 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信