前端题目集锦

20190530(blw)

JavaScript数据类型转换: juejin.im/post/5cee56…

20190524(wyn)

  • 箭头函数和普通函数的区别?
    • note.youdao.com/noteshare?i…
  • vue-router 有几种路由模式?他们的实现原理?
    • note.youdao.com/noteshare?i…
  • webpack 和 gulp 的区别?
    • gulp 任务执行器

      侧重规范前端开发的流程,通过配置一系列的task,定义task处理的事务(例如:文件压缩合并,启动server),然后定义执行顺序,来让gulp执行task,从而构建其前端项目的流程。合并后仍然是你写的代码,只是局部变量名被替换,一些语法做了转换而已,整体内容并没有发生改变。

    • webpack 模块打包器

      侧重模块打包,把开发中的所有资源(图片,js文件,css文件等)都开成模块,通过loader(加载器)和plugins(插件)对资源进行处理,打包成符合生产环境部署的前端资源。打包后的代码已经不只是你写的代码,其中夹杂很多webpack自身的模块处理代码。

    • 区别

      Gulp是对整个过程进行控制,所以在其配置文件(gulpfile.js)中配置的每一个task对项目中该task配置路径下所有的资源都可以管理 Webpack则不是这样管理资源的,它是根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源, 对资源文件的处理是通过入口文件产生的依赖形成的,不会像Gulp那样,配置好路径后,该路径下所有规定的文件都会受影响

  • 在webpack中如何做长缓存优化?
    • 用户从访问网页开始,浏览器向服务器下载请求,服务器返回请求的时候,通过控制http协议的这些响应头,告诉浏览器某些资源以内的是强缓存,不用更新它。
    • 如果代码有更新,版本号发生变化,则这段代码需要更新的代码。如果已经被浏览器缓存,用户希望获取缓存代码。只更新改变的代码。
    • 优化方式一:在webpack中,可以在output给出输出的文件制定chunkhash,并且分离经常更新的代码和框架代码,通 过NameModulesPlugin或者HashedModulesPlugin使再次打包文件名不变。 chunkhash:它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。 HashedModulesPlugin:由于引入了一个新模块,使得打包过程中部分模块的模块ID发生了改变。而模块ID的改变,直接导致了包含这些模块的chunk内容改变,进而导致chunkHash的改变

20190517(swl)

  • https通信双方获取加密密钥的过程?https为什么需要证书?
    图解SSL/TLS协议 - 阮一峰
    漫画:什么是 HTTPS 协议?
  • 实现一个chunk函数,chunk([1, 2, 3, 4, 5], 2) -> [[1, 2], [3, 4], [5]]
    // 先计算出生成的数组长度,然后利用Array.from的第二个参数去映射
    const chunk = (arr, size) =>
      Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
        arr.slice(i * size, i * size + size)
      );
    复制代码
    30 seconds of code 这个链接收集了很多短小但实用的代码片段,你可以在30秒内理解它。里面很可能就有你每天在用的lodash方法
  • 下面是MDN给出的bind方法的Polyfill(篇幅原因略去了类型检测),思考标注的代码解决了什么问题,你觉得该实现还有哪些比较重要的缺陷?
    Function.prototype.bind = function (oThis) {
      var aArgs = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP = function () { },
        fBound = function () {
          return fToBind.apply(this instanceof fBound
            ? this
            : oThis,
            aArgs.concat(Array.prototype.slice.call(arguments)));
        };
    
      // 以下两行代码解决了什么问题,试举例说明
      if (this.prototype) fNOP.prototype = this.prototype;
      fBound.prototype = new fNOP();
    
      return fBound;
    };
    复制代码
    如果没有上面的简单原型链继承,这里F的原型对象上的print方法就会丢失:
    const F = function() {
      this.name = 'haha'
    }
    
    F.prototype.print = function() {
      return this.name
    }
    
    const FBound = F.myBind(null)
    
    const f = new FBound()
    
    console.log(f)
    console.log(f.print()) // 不维护原型的话,这里会找不到print,进而报错
    复制代码
    除此之外,这个bind实现没有处理函数的length属性,而原生的bind会进行处理。例如:
    const add = (a, b) => a + b
    const addOne = add.bind(null, 1)
    addOne.length // 1
    复制代码
    这可能会导致依赖length的后续操作失败,例如柯里化等
    这里又涉及到另一个问题,函数的length属性是不可写的,我们只能通过Object.defineProperty去设置:
    Function.prototype.myBind = function (ctx, ...fixed) {
      if (typeof this !== 'function') {
        throw new TypeError('What is trying to be bound is not callable');
      }
    
      const fToBind = this
      const fNOP = function () { }
      const fBound = function (...args) {
        return fToBind.call(
          this instanceof fBound ? this : ctx,
          ...fixed, ...args
        )
      }
    
      if (this.prototype) fNOP.prototype = this.prototype
      fBound.prototype = new fNOP()
    
      // 设置新函数的length,如果本来就是0,那我们就也设置为0
      Object.defineProperty(fBound, 'length', {
        value: Math.max(0, fToBind.length - fixed.length),
        writable: false,
        configurable: true
      })
    
      return fBound
    }
    
    const addThreeNum = (a, b, c) => a + b + c
    
    console.log(addThreeNum.myBind(null, 1).length) // 2
    复制代码
    MDN - Function​.prototype​.bind()
  • 补全以下代码,实现一个简单的Observable
    class Observable {
      constructor() {
        this.cbs = []
      }
    
      subscribe (cb) {
        this.cbs.push(cb)
      }
    
      emit (x) {
        this.cbs.forEach(cb => cb(x))
      }
    }
    
    const observable = new Observable()
    
    observable.subscribe(console.log)
    observable.subscribe(x => console.log(x * 2))
    
    observable.emit(3) // output: 3 6
    复制代码

20190510(sjj)

  • []==![]

我们来分析一下:[]==![] 是true还是false?

  1. 首先,我们需要知道 ! 优先级是高于 == (更多运算符优先级可查看:运算符优先级)
  2. ![]引用类型转换成布尔值都是true,因此![]的是false
  3. 其中一方是 boolean,将 boolean 转为 number 再进行判断,false转换成 number,对应的值是 0.
  4. 有一方是number,那么将object也转换成Number,空数组转换成数字,对应的值是0.(空数组转换成数字,对应的值是0,如果数组中只有一个数字,那么转成number就是这个数字,其它情况,均为NaN)
  5. 0 == 0; 为true
  • commonJS的es6模块的区别
  1. commonJS 浅拷贝,值可以被修改,优先从缓存中取值,加载时执行,一旦出现某个模块被“循环加载”,就只输出已执行的部分,还未执行的部分不输出
  2. es6 动态(原始值发生变化,import加载的值也会发生变化)只读引用,脚本执行时,去取值
  • console.log(fn); // function fn() {console.log('哈哈')}
    fn = 'hello'
    function fn() {console.log('哈哈')};
    console.log(fn); // 'hello'

所有的声明都会提升到当前作用域最顶上,
同一个变量只会声明一次,其它会被忽略
函数声明的优先级高于变量声明的优先级,并且函数声明和函数定义的部分一起被提升

20190426(shj)

  • for..in 和 for...of 的区别
  1. for...in 循环读取键名,for...of 循环读取键值
  2. for...of 循环需要调用遍历器接口,for...in不需要。对于普通的对象,因为没有遍历器接口,所以不能直接用for...of 遍历对象
  3. 某些情况下,for。。。in循环会以任意顺序遍历键名
  4. (补充)for...of 与forEach 对比,for...of 可以使用break,continue,return跳出循环
  • 什么是事件委托
  1. 通俗地来讲,就是把一个元素响应事件(click、keydown......)的函数委托到另一个元素;一般来讲,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,当事件响应到需要绑定的元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后在外层元素上去执行函数。
  2. 事件委托的实现是利用事件冒泡的机制
  3. 对于不支持冒泡机制的事件(如focus、blur等),想要使用事件委托,需要利用捕获机制。通过document.addEventListener 将事件模型设置为事件捕获
  • 如何判断数组类型
  1. 使用 instanceof 操作符
  2. 使用Array.isArray()
  3. 使用Object的toString()方法 Object.prototype.toString.call([]); //"[object Array]"
  • new 一个对象会发生什么
  1. 创建空对象
  2. 设置新对象的constructor属性为构造函数的名称,设置新对象的__proto__属性指向构造函数的prototype对象
  3. 使用新对象调用函数,函数中的this被指向新实例对象中
  4. 将初始化完毕的新对象地址保存到等号左边的变量中
  5. 若构造函数中返回this或返回值是基本类型(number、string、boolean、null、undefined、symbol)的值,则返回新对象;若返回值是引用类型的值,则实际返回值为这个引用类型。
  • JSONP的原理
  1. 原理:Web页面上调用js文件时不受是否跨域的影响(不仅如此,我们还发现凡是拥有src这个属性的标签都拥有跨域的能力,比如script、img、iframe、link)
  2. 实现:允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了
  • CORS

跨域请求在发送前,会判断该请求是简单请求还是复杂请求。

  1. 如果是简单请求,浏览器会在请求头增加Origin字段后发送跨域请求。请求发送过去后,服务端一般会在响应头里添加上Access-Control-Allow-Origin 字段,浏览器通过校验该值是否是Origin的值或者是*,来判断是否跨域
  2. 如果是复杂请求,跨域请求会先发送一个预检请求(携带复杂请求部分信息)来询问服务器是否同意这次复杂请求。
    • 预检请求使用OPTIONS方法,发送Origin、Access-Control-Request-Method、Access-Control-Request-Headers(可选)头部。
    • 发送该请求后,服务器可以通过在响应头中携带以下头部
      • Access-Control-Allow-Origin
      • Access-Control-Allow-Methods
      • Access-Control-Allow-Headers
      • Access-Control-Max-Age (预检请求的有效期)
  • 预检请求结束后,结果将按照响应中指定的时间缓存起来,下次再发送这样的复杂请求时,不会再发送预检请求
  • vue父子组件中的生命周期与钩子函数的调用顺序
  1. 从外到内,再从内到外,mixins先于组件
  2. 父组件beforeCreated ->父组件created ->父组件beforeMounted ->子组件beforeCreated ->子组件created ->子组件beforeMounted ->子组件mounted -> 父组件mounted。

20190418(rtj)

  • CSS有哪些继承属性?
  1. CSS中关于文字排版的属性如:font、word-break、letter-spacing、text-align、text-rendering、word-spacing、white-space 、text-indent、text-transform、text-shadow
  2. 其他类型的如:line-height、color、visibility、cursor
  • 描述一下offsetWidth/offsetHeight、clientWidth/clientHeight、scrollWidth/scrollHeight的区别?
  1. offsetWidth/offsetHeight返回值包含content + padding + border,效果与e.getBoundingClientRect()相同
  2. clientWidth/clientHeight返回值只包含content + padding,如果有滚动条,也不包含滚动条
  3. scrollWidth/scrollHeight返回值包含content + padding + 溢出内容的尺寸
  • 什么情况下会打印出1?
    let a = ?
    if (a == 1 && a == 2 && a ==3 ) {
        console.log(1)
    }
复制代码

在类型不同时,用==比较会进行隐式类型转换,而在隐式类型转换时会调用toString()或者valueOf()方法,所以我们可以利用这个特性,定义a为一个对象类型,并且复写这两个方法其中之一就可以达到题目中的效果。

let a = [1, 2, 3]
a.valueOf = a.shift
// a.toString = a.shift 这个方法也可以
if (a == 1 && a == 2 && a == 3) {
  console.log(1)   
}
复制代码
  • 讲一下什么是防抖和节流以及他们的区别和用途?

防抖(debounce)

  1. 概念:指定时间内只执行一次回调函数,如果在指定的时间内又触发了该事件,则回调函数的执行时间会基于此刻重新开始计算。
  2. 用途:比如用户搜索时,当输入停止后再去触发搜索事件

节流(throttle)

  1. 概念:频繁触发事件时,只会在指定的时间段内执行事件回调,即触发事件间隔大于等于指定的时间才会执行回调函数
  2. 用途:比如处理浏览器滚动事件

20190412(blw)

  • document 中的load事件和DOMContentLoaded事件之间的区别是什么?

当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded事件被触发,而无需等待样式表、图像和子框架的完成加载。

window的load事件仅在 DOM 和所有相关资源全部完成加载后才会触发。

  • 如此执行正确吗?【function foo(){console.log(123) }()】

JavaScript 解析器将 function foo(){ }();解析成function foo(){ }和();。其中,前者是函数声明;后者(一对括号)是试图调用一个函数,却没有指定名称,因此它会抛出Uncaught SyntaxError: Unexpected token )的错误。 修改方法是:再添加一对括号,形式上有两种:(function foo(){ })()和(function foo(){ }())。以上函数不会暴露到全局作用域,如果不需要在函数内部引用自身,可以省略函数的名称。

  • 负责的主要业务内容是什么? 开放性问题。要求有条理,逻辑清晰。

20190404(wyn)

  • 介绍一下CSS的盒子模型?种类、组成、区别

每个元素被表示为一个矩形的盒子,由四部分组成:内容content/内边距padding/边框/border/外边距margin

盒模型有两种:标准盒模型(W3C盒模型)、IE盒模型

区别:标准盒模型内容大小就是content大小,而IE盒模型内容大小则是content+padding+border总的大小

  • 什么是margin坍塌?怎么解决

相邻的两个标准流中的块元素,如果它们在垂直方向上设置了外边距,那么外边距会发生重叠,最终的外边距等于发生层叠的外边距中绝对值较大者

解决:触发BFC(Block Formatting Contexts 块级格式化上下文) 1、 body根元素 2、浮动元素:float:除none以为的值 3、绝对定位元素:position:absolute/fixed 4、display:inline-block/table-cells/flex 5、overflow:除了visible以外的值(hidden/auto/scroll)

  • display: none;与visibility: hidden的作用和区别

作用:都是让元素不可见

区别: display:none会让元素完全从 render 树中消失,渲染的时候不占据任何空间,子元素不允许覆盖值。 visibility:hidden不会让元素从渲染树 dom 中消失,而且还是会占据空间,只是内容不可见而已,子元素允许覆盖值(设置visibility:visible;元素可见)。

  • vue-router 中组件内的导航钩子beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave的用法

直接在路由组件内部直接进行定义的

接收参数(to,from,next) 1、 to:router即将进入的路由对象 2、 from:当前导航即将离开的路由 3、 next:,进行管道中的一个钩子,如果执行完了,调用next();否则为false,终止导航。 beforeRouteEnter:进入路由之前执行的函数 beforeRouteUpdate:当前路由改变 beforeRouteLeave:离开路由之前执行的函数

  • position的absolute与fixed共同点与不同点

共同点: 1.改变行内元素的呈现方式,display被置为block;2.让元素脱离普通流,不占据空间;3.默认会覆盖到非定位元素上

不同点: absolute:生成绝对定位的元素,相对于static定位以外的第一个父元素进行定位。 fixed:生成绝对定位的元素,相对于浏览器窗口进行定位。滚动网页,fixed元素与浏览器窗口之间的距离不变。

20190328(blw)

  • cookie、sessionStorage和localStorage的区别。

  • script、script async和script defer的区别

script - HTML 解析中断,脚本被提取并立即执行。执行结束后,HTML 解析继续。

script async - 脚本的提取、执行的过程与 HTML 解析过程并行,脚本执行完毕可能在 HTML 解析完毕之前。当脚本与页面上其他脚本独立时,可以使用async,比如用作页面统计分析。

script defer - 脚本仅提取过程与 HTML 解析过程并行,脚本的执行将在 HTML 解析完毕后进行。如果有多个含defer的脚本,脚本的执行顺序将按照在 document 中出现的位置,从上到下顺序执行。 注意:没有src属性的脚本,async和defer属性会被忽略。

  • CSS和script的标签一般放在什么地方为什么?

把link标签放在head之间是规范要求的内容。此外,这种做法可以让页面逐步呈现,提高了用户体验。将样式表放在文档底部附近,会使许多浏览器(包括 Internet Explorer)不能逐步呈现页面。一些浏览器会阻止渲染,以避免在页面样式发生变化时,重新绘制页面中的元素。这种做法可以防止呈现给用户空白的页面或没有样式的内容。把script标签恰好放在body之前脚本在下载和执行期间会阻止 HTML 解析。把script标签放在底部,保证 HTML 首先完成解析,将页面尽早呈现给用户。 例外情况是当你的脚本里包含document.write()时。但是现在,document.write()不推荐使用。同时,将script标签放在底部,意味着浏览器不能开始下载脚本,直到整个文档(document)被解析。也许,对此比较好的做法是,script使用defer属性,放在head中。

  • CSS 选择器的优先级是如何计算的

浏览器通过优先级规则,判断元素展示哪些样式。优先级通过 4 个维度指标确定,我们假定以a、b、c、d命名,分别代表以下含义: a表示是否使用内联样式(inline style)。如果使用,a为 1,否则为 0。 b表示 ID 选择器的数量。 c表示类选择器、属性选择器和伪类选择器数量之和。 d表示标签(类型)选择器和伪元素选择器之和。 优先级的结果并非通过以上四个值生成一个得分,而是每个值分开比较。a、b、c、d权重从左到右,依次减小。判断优先级时,从左到右,一一比较,直到比较出最大值,即可停止。所以,如果b的值不同,那么c和d不管多大,都不会对结果产生影响。比如0,1,0,0的优先级高于0,0,10,10。

  • 如何为功能受限的浏览器提供页面? 使用什么样的技术和流程?

优雅的降级:为现代浏览器构建应用,同时确保它在旧版浏览器中正常运行。

渐进式增强:构建基于用户体验的应用,但在浏览器支持时添加新增功能。

利用 caniuse.com 检查特性支持。

使用 autoprefixer 自动生成 CSS 属性前缀。

使用 Modernizr进行特性检测。

转载于:https://juejin.im/post/5cad85365188251af76ee128

你可能感兴趣的:(前端题目集锦)