前端面试题杂烩(答案)

549 阅读11分钟

一、Html相关

1、html5新增的表单元素

  • datalist
  • keygen
  • output

二、css相关

  • 1、如何画一个三角形(阿里一面同款)
      <div class="triangle"></div>
      .triangle{
          width:0;
          height:0;
          border-left:20px solid transparent;
          <!--border-left:20px solid transparent;-->
          border-top:20px solid pink;
      }
    

  • 2、CSS3中对溢出的处理: overflow:visiblle/hidden/auto/scroll

    • visible:如果内容区域的大小能够容纳子矩形对象,浏览器会正常地显示子矩形对象;当内容区域无法容纳子矩形区域时,浏览器会在内容区域之外,显示完整的子矩形对象。
    • hidden:如果内容区域的大小能够容纳子矩形对象,浏览器会正常地显示子矩形对象;当内容区域无法容纳子矩形区域时,浏览器会显示内容区域之内的子矩形对象,超出内容区域的则不显示。
    • scroll:如果内容区域的大小能够容纳子矩形对象,浏览器会正常地显示子矩形对象,并且显示预设滚动条;当内容区域无法容纳子矩形区域时,浏览器会在内容区域之内显示完整的子矩形对象,并且显示滚动条、启用滚动条功能,让用户能够浏览完整的子矩形对象。
    • auto:如果内容区域的大小能够容纳子矩形对象,浏览器会正常地显示子矩形对象;当内容区域无法容纳子矩形区域时,浏览器会在内容区域之内显示完整的子矩形对象,并且显示滚动条、启用滚动条功能,让用户能够浏览完整的子矩形对象。
  • 3、CSS的选择器及优先级:

不同级别:
    在属性后面使用 !important 会覆盖页面内任何位置定义的元素样式。
    作为style属性写在元素内的样式
    id选择器
    类选择器
    标签选择器
    通配符选择器
    浏览器自定义或继承
总结排序:!important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性
权重值:
    内联样式表的权值为 1000
    ID 选择器的权值为 100
    Class 类选择器的权值为 10
    HTML 标签选择器的权值为 1
  • 4、BFC(块级格式化上下文)

    1、block-level box:display 属性为 block, list-item, table 的元素,会生成 block-level box。并且参与 block fomatting context;
    2、定义:它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干(不会影响盒子外的布局外部布局也不会影响盒子内的布局)。
    3、布局规则:
        内部的Box会在垂直方向,一个接一个地放置。
        Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
        每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
        BFC的区域不会与float box重叠。
        BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
        计算BFC的高度时,浮动元素也参与计算
    4、触发BFC:
        根元素
        float属性不为none
        position为absolute或fixed
        display为inline-block, table-cell, table-caption, flex, inline-flex
        overflow不为visible
    
    
  • 5、清除浮动的方法:

    1、触发父元素的BFC(块级格式化上下文);

    2、在浮动元素后增加元素,并将clear:both;

         <div class="div1 clearfloat"> 
            <div class="left">Left</div> 
            <div class="right">Right</div> 
            <div style="clear:both"></div>
        </div>
        
        <div class="div2">
            div2
        </div>
        .div1{background:#000080;border:1px solid red;}
        .div2{background:#800080;border:1px solid red;height:100px;margin-top:10px}
    

    3、在父元素上使用after伪类

        <div class="div1 clearfloat"> 
            <div class="left">Left</div> 
            <div class="right">Right</div> 
        </div>
        <div class="div2">
            div2
        </div>
       .div1{background:#000080;border:1px solid red;}
       .div2{background:#800080;border:1px solid red;height:100px;margin-top:10px}
       .left{float:left;width:20%;height:200px;background:#DDD}
       .right{float:right;width:30%;height:80px;background:#DDD}
       .clearfloat:after{display:block;clear:both;content:"";visibility:hidden;height:0}
       .clearfloat{zoom:1}
    
  • 6、实现一个两列等高布局

  • 7、怎么样让一个元素消失

      是怎样的的消失法呢?
      1、display:none;(元素不会被绘制)
      2、visibility:hidden(visible/collapse),元素不可见,但是仍处于dom结构中,会影响布局。
      3、opacity:0
      4、position: absolute; top: -999em; /* 不占据空间,无法点击 */ 
         position: relative; top: -999em; /* 占据空间,无法点击 */ 
    

三、js相关

1、闭包的理解:

  • 闭包的定义:有权访问另一个函数作用域中变量的函数

  • 闭包的用途:(1)、可以在函数外部访问函数内部的变量;(2)、可以将一些变量一直留在内存当中。(这块的用处是什么欢迎补充)

  • 闭包的副作用:由于闭包会携带包含它的函数的作用域,因此会比其他函数占用过多的内存。过度使用闭包会导致内存占用过多。(虽然像V8等优化后JavaScript引擎会尝试收回被闭包占用的内存,但还是建议大家谨慎使用闭包)

  • 我对闭包的理解

    • 从作用域链的角度出发:js分为全局作用域和局部作用域
      function createComparisonFunction(propertyName) {
          return function(object1, object2){
              var value1 = object1[propertyName];
              var value2 = object2[propertyName];
              if (value1 < value2){
                  return -1;
              } else if (value1 > value2){
                  return 1;
              } else {
                  return 0;
          } };
      }
      
      //创建函数
      var compareNames = createComparisonFunction("name");
      //调用函数
      var result = compareNames({ name: "Nicholas" }, { name: "Greg" });
      //解除对匿名函数的引用(以便释放内存) compareNames = null;
    
    • 闭包与变量:

      作用域链的这种配置机制引出了一个引人注意的副作用:即闭包只能取得包含函数中任何变量的最后一个值。之快又引出了一个新的问题,如何避免这个问题,若是使用es6的let,那么又会引出let和var的区别是什么?

    • 闭包this指向:匿名函数的执行环境具有全局性,其this对象通常指向window
    • this对象:this对象是在运行时基于函数的执行环境绑定的,在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this 等 于那个对象。
    红宝书上关于上述问题的例子
    1、function creatClosure1(){
        var result = new Array()
        for(var i = 0;i < 6;i++){
            result[i] = function(){
                return i
            }
        }
    }
    解决办法:
    2、function creatClosure2(){
        for(var i = 0;i < 6;i++){
            result[i] = (function(num){
            //多了一个外层函数
                return function(){
                    return num
                }
            })(i)
        }
    }
    3、functionn  creatClosure3(){
        for(let i = 0;i < 6;i++){
            result[i] = function(){
                return i
            }
        }
    }
  • let和var的区别
var:在函数作用域内生效,存在变量提升,可以重复声明。
let:在块级作用域生效,不存在变量提升,不允许重复声明,必须先声明后使用。
//第一段代码  
var a = 2;  
var a = 3;  
alert(a);//3  
//第二段代码  
<span style="font-size:18px;"></span><pre name="code" class="javascript">a = 2;  
alert(a);//2 
在js代码执行的过程中,引擎负责代码的编译及运行,编译器负责词法分析、语法分析、代码生成等工作,作用域则负责变量的管理即维护所有的表标识符。

而编译器和引擎在执行代码的过程中还会执行额外的工作:检查变量是否存在。

        1.首先编译器对代码进行分析拆解,从左至右遇见var a,则编译器会询问作用域是否已经存在叫a的变量了,如果不存在,则招呼作用域声明一个新的变量a,若已经存在,则忽略var 继续向下编译,这时a = 2被编译成可执行的代码供引擎使用。

        2.引擎遇见a=2时同样会询问在当前的作用域下是否有变量a,若存在,则将a赋值为2(由于第一步编译器忽略了重复声明的var,且作用域中已经有a,所以重复声明会发生值得覆盖而并不会报错)。若不存在,则顺着作用域链向上查找,若最终找到了变量a则将其赋值2,若没有找到,则招呼作用域声明一个变量a并赋值为2(这就是为什么第二段代码可以正确执行且a变量为全局变量的原因,当然,在严格模式下JS会直接抛出异常:a is not defined)。
  • 2、如何判断一个数组

        1、es5定义的Array.isArray(arr);//返回true/false
        2、若是不支持isArray方法,则使用:
            a、Object.prototype.tostring.call(arr) == [Objejct Array];
            b、arr.constructor === 'Array'
        //将上述方式汇总成一个判断是不是数组的方法
         ifArray(arr){
            if(!!Array.isArray){
                return Array.isArray(arr);
            }else{
                let result;
                result = !!Object.prototype.toString.call(arr) === '[Object Array]'?true:false;
                return result;
                
            }
            // if(typeof arr === 'object' && arr.constructor.name === 'Array'){
            //     return true;
            // }else{
            //     return false;
            // }
        }
    
  • 3、JS实现倒计时

    倒计时校准

    vue写的部分代码,大概是这个意思
      let _self = this;
        // let timeId;
        if(!!_self.showTime){
            return;
        }
        _self.showTime = true;
        _self.text = "重新发送验证码";
        let startTime = new Date();
        let count = 1;
        timeId = setInterval(function(){
            console.log('count',count)
            let endTime = new Date();
            let offset = endTime - startTime - count*1000;
            console.log('offset',offset);
            count++;
        },1000);
        timeId = setInterval(function(){
            // console.log(_self.time);
            if(_self.time>0){
                 console.log(_self.time);
                _self.time -= 1;
            }else{
                _self.time = 5;
                _self.text = '获取验证码'
                _self.showTime = false
                clearInterval(timeId);
            }
        },1000);
    
  • 数组去重的三种实现方式

         //1、ES6 新特性 Set
        removeDuplicate1(arr){
            let arrNew = new Set(arr);
            return Array.from(arrNew);
        }
        //2、基本去重 for循环 +indexof
        removeDuplicate2(arr){
            let copyArr = [];
            for(let i = 0;i<arr.length;i++){
                if(copyArr.indexOf(arr[i]) < 0){
                    copyArr.push(arr[i]);
                }
            }
            return copyArr;
        }
        //3、利用对象的属性
        removeDuplicate3(arr){
            if(arr.length<=1){
                return arr;
            }
            let obj = {};
            let copyArr = [];
            for(let i=0;i<arr.length;i++){
                if(!obj[arr[i]]){
                    obj[arr[i]] = 1;
                    copyArr.push(arr[i]);
                }
            }
            return copyArr;
        }
    

四、ES6相关

1、实现promise.all()

    function promiseAll(promises){
         return new Promise(function(resolve,reject){
           //先判断参数是不是数组
          if(!!Array.isArray){
            if(!Array.isArray(promises)){
              return
            }
          }else{
            if(!Object.prototype.toString.call(promises)==='[Object Array]'){
              return
            }
            if(!promises.constructor.name === 'Array'){
              return
            }
          }
           //再判断参数数组长度是否为0
           if(promises.length < 1){
             return resolve('is an empty obj')
           }
           let count = promises.length
           let successCount = 0
           let successArr = []
           promises.map(function(val,index){
             val.then((value) => {
               successCount++
               successArr.push(value)
               if(successCount === count){
                 return resolve(successArr)
               }
             }).catch((e) => {
               return reject(e)
             })
           })
         })
      }
    let p1 = Promise.resolve(Promise.resolve("wode"))
    let p2 = Promise.resolve(Promise.resolve("haole"))
    let p3 = Promise.reject(Promise.resolve("good luck"))
    this.promiseAll([]).then((results) => {
      console.log('success',results)
    }).catch( (e) => {
      console.log('fail',e)
    })

五、算法相关

六、计网相关

(一)、HTTP相关

1、get和post请求

  • 根据HTTP规范,GET用于信息获取,而且应该是安全的和幂等的 。

    1.所谓安全的意味着该操作用于获取信息而非修改信息。换句话说,GET请求一般不应产生副作用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改,增加数据,不会影响资源的状态。

    2.幂等的意味着对同一URL的多个请求应该返回同样的结果。

2、http三次握手和四次挥手 这篇讲的很详细:juejin.cn/post/684490…

七、数据结构相关

八、操作系统相关

1、进程和线程的区别 2、线程的哪些资源共享,那些资源不共享

九、其他

  • base64相关

    1、base64原理

    2、前端性能优化中用到base64:

    
     1. 优点
     (1)base64格式的图片是文本格式,占用内存小,转换后的大小比例大概为1/3,降低了资源服务器的消耗;
     (2)网页中使用base64格式的图片时,不用再请求服务器调用图片资源,减少了服务器访问次数。
     2. 缺点
     (1)base64格式的文本内容较多,存储在数据库中增大了数据库服务器的压力;
     (2)网页加载图片虽然不用访问服务器了,但因为base64格式的内容太多,所以加载网页的速度会降低,可能会影响用户的体验。
     (3)base64无法缓存,要缓存只能缓存包含base64的文件,比如js或者css,这比直接缓存图片要差很多,而且一般HTML改动比较频繁,所以等同于得不到缓存效益。
     
     因为base64的使用缺点,所以一般图片小于10kb的时候,我们才会选择使用base64图片,比如一些表情图片,太大的图片转换成base64得不偿失。当然,极端情况极端考虑。
    
  • 移动端网页性能优化自查表

  • 2018 前端性能优化清单

  • 重排和重绘: 这篇就够了

  • HTTP状态码说说你知道的 这篇挺详细

  • 讲讲304(我能介绍一下浏览器缓存机制吗): 条件请求

  • 浏览器缓存机制: 详解

  • 从性能优化的角度讲解了浏览器缓存机制

  • 必须强推的面试干货之浏览器的渲染机制解析

  • DOMContentLoaded: DOM解析完成即触发此事件,不等待styles, images等资源的加载(仅当DOM加载完成,不包括样式表,图片,flash)
    load:依赖的资源也已加载完成(页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了)
    DOMContentLoaded绑定到document,load绑定到window