前端面试复习

128 阅读10分钟
  1. 赋值、深拷贝和浅拷贝

  • 赋值:复制指针

  • 浅拷贝:创建一个新对象,将对象或数组中的基本类型直接复制给新的对象或数组,引用类型复制指针。

    function shallowCopy(obj){
        var newObj = obj.constructor === Array ? [] : {};
        for(let i in obj){
            if(obj.hasOwnProperty(i)){
                newObj[i] = obj[i];
            }
        }
        return newObj;
    }
    
  • 深拷贝:在浅拷贝的基础上做递归,直到最深层全部复制完毕。

  • 深拷贝实现方法:

    • 递归

      function deepClone(obj){
          var newObj = obj.constructor === Array ? [] : {};
          for(let keys in obj){
              if(obj.hasOwnProperty(keys)){//能够排除继承来的原型链上的属性
                  if(typeof obj[keys] === 'object'){
                      newObj[keys] = obj[keys].constructor === Array ? [] : {};
                      newObj[keys] = deepClone(obj[keys]);
                  }
                  else{
                      newObj[keys] = obj[keys];
                  }
              }
          }
          return newObj;
      }
      
    • JSON.parse(JSON.Stringfy(obj))

      缺点:不能处理函数对象和正则对象

      function deepClone(obj){
          var newObj = {};
          return newObj = JSON.parse(JSON.Stringfy(obj));
      }
      
  1. 浏览器是怎么渲染页面的

    • 通过HTML解析器解析HTML文档,构建一个DOM Tree,同时通过CSS解析器解析HTML中存在的CSS,构建Style Rules,两者结合形成一个Attachment。
    • 通过Attachment构造出一个呈现树(Render Tree)
    • Render Tree构建完毕,进入到布局阶段(layout/reflow),将会为每个阶段分配一个应出现在屏幕上的确切坐标。
    • 最后将全部的节点遍历绘制出来后,一个页面就展现出来了。

    引擎为了力求显示的及时,会在文档请求不完全的情况下就开始渲染页面,同时,如果在解析的过程中遇到script的时候,文档的解析将会停止下来,立即解析执行脚本,如果脚本是外部的,则会等待请求完成并解析执行。所以,为了不阻塞页面地呈现,一般会把script脚本放在文档的最后。

    解决方案:

    • 在最新的HTML4和HTML5规范中,也可以将脚本标注为defer,这样就不会停止文档解析,而是等到解析结束后才执行。
    • HTML5 增加了一个选项,可将脚本标记为async,以便由其他线程解析和执行。

    作者:elliott_hu 链接:https://segmentfault.com/a/1190000013522717

  2. css实现左右固定宽度 中间自适应

    • 父级div包3个子div,父级设置display:flex,对左右两边的div设置固定width,中间的要设置width:100%或者flex:1 (flex-grow:1)

      flex属性是flex-grow,flex-shrink,flex-basis,默认值为0,1,auto
      flex-grow:定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大
      flex-shrink:定义了缩小比例,默认为1,空间不足则项目缩小
      flex-basis定义了在分配多余空间之前,项目占据的主轴空间,默认为auto,即本来大小
      
    • 利用浮动元素float,让左右元素浮动,缺点是中间元素必须置于二者之后

      左项目左浮动,右项目右浮动,左右元素需要定义width,height。
      中间元素需要定义height。
      <div class="left"></div>
      <div class="right"></div>
      <div class="center"></div>
      center占据文档流位置,所以一定要放在最后,左右两个元素位置没有关系。
      当浏览器窗口很小的时候,右边元素会被击倒下一行。
      
    • 利用绝对定位,父元素相对定位,左右元素绝对定位,中间元素用margin给左右元素留出位置

      <div class="father">
          <div class="left"></div>
          <div class="right"></div>
          <div class="center"></div>
      </div>
      
      <style>
          .father{
              width: 100%;
              height: 100%;
              position: relative;
          }
          .left{
              position: absolute;
              left: 0;
              top: 0;
              width: 400px;
              height: 200px;
          }
          .right{
              position: absolute;
              top: 0;
              right: 0;
              width: 400px;
              height: 200px;  
          }
          .center{
              margin: 0 400px;
              height: 200px;
          }
      </style>
      
  3. 合并两个有序数组(去重)

    var merge = function(arr1, m, arr2, n){
        let len1 = m-1;
        let len2 = n-1;
        let len = m + n - 1;
        while(len2 >= 0){
            if(len1 < 0){
                arr1[len--] = arr2[len2--]
                continue;
            }
            arr1[len--] = arr1[len1] >= arr2[len2] ? arr1[len1--] : arr2[len2--];
        }
        return [...new Set(arr1)];
    }
    
  4. 求两个数组的交集 返回一个包含所有交集元素的数组

    var intersection = function(arr1, arr2){
        return [...new Set(arr1.filter((item) => arr2.includes(item)))]
    }
    
  5. 宏任务和微任务有哪些

    首先js是同步执行的,但对于某些执行时间比较长的函数或代码来说,所有之后的代码都需等待直至它执行完,所以加入了回调函数的概念,进行异步操作。

    所以任务可以简单分为同步任务和异步任务。首先我们进行顺序执行,遇到异步操作时,等异步操作结束之后,若同步任务还未执行完,则需等待至同步任务执行完再执行回调函数。

    img

    宏任务和微任务的执行顺序:在执行宏任务时若碰到微任务则执行所有的微任务,直至执行完毕再执行下一个宏任务。

    img
    任务 函数
    微任务 promise/process.nextTick/MutationObserver
    宏任务 setTimeout/setInterval/setImmediate
    • promise:一个对象,获取异步操作的消息
    • process.nextTick:类似于setTimeout,node层面
    • MutationObserver:监听目标DOM节点

    两者都代表主线程完成后立即执行,其执行结果是不确定的。setTimeout回调函数执行结果在前的概率更大些,这是因为他们采用的观察者不同,setTimeout采用的是类似IO观察者,setImmediate采用的是check观察者,而process.nextTick()采用的是idle观察者。

    www.ruanyifeng.com/blog/2018/0…

  6. es6的新特性

    class,constructor,export,import
    let(只在声明的代码块有效,且不会向var那样对变量进行提升)
    const(只读的常量)
    =>
    反引号``
    Set类似于数组,但是成员的值都是唯一的,没有重复的值。
    Map类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
    Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
    
    //...解构赋值
    let [head, ...tail] = [1, 2, 3, 4];
    head // 1
    tail // [2, 3, 4]
    
    new Set(arr)
    [...new Set(arr)]
    
    let { bar, foo } = { foo: "aaa", bar: "bbb" };
    foo // "aaa"
    bar // "bbb"
    
    // assign方法对象的合并,将obj1,obj2合并到obj中
    Object.assign(obj,obj1,obj2)
    
  7. 箭头函数和普通函数区别

  8. this的指向问题

  9. 基本类型和引用类型

  10. css布局(这里面试官让说弹性盒子布局)

  11. emrem区别

    rem=root of em

    em=16px(一般)

  12. css权重(选择器优先级)

    !important>内联样式>id选择器>class选择器>伪类|
    
  13. 重绘和重排

  14. vuex在项目中的使用场景:(一般在数据和组件分离,分别处理的场景下使用)

    • 涉及非父子关系(兄弟关系、祖孙关系等)组件之间的数据交互
    • 组件会被销毁
    • 组件基于数据而创建,数据变化会影响到多个组件
    • 多对多事件——多处触发,影响多处
  15. 父子组件通信

    Prop, $emit, .sync, $attrs & $listeners, Vuex等
    
  16. 页面跳转传值(路由跳转)

    • url后带参数

    • sessionStoragelocalStorage

      window.localStorage.setItem('data','1');
      window.localStorage.getItem('data')
      
  17. 项目中如何解决跨域(答的是cors跨域资源共享)

  18. 事件委托和事件冒泡

    • 事件捕获是从外层元素到目标元素的过程

    • 事件冒泡是从目标元素到外层元素的过程

      juejin.cn/post/684490…

  19. vue生命周期

    • beforeCreate:在页面创建之前调用

    • created:页面创建后被立即调用,已完成数据观测,属性和方法的运算,watch/event事件回调。挂载阶段还没开始,$el属性目前不可见

    • beforeMount:在挂载开始之前被调用,相关的渲染函数首次被调用

    • mounted:挂载成功立即调用

    • beforeUpdate:数据更新时调用

    • updated:dom已经更新,组件更新完毕

    • activated:组件激活时调用

    • deactivated:组件停用时调用

    • beforeDestroy:实例销毁之前调用

    • destroyed:实例销毁之后调用,调用后实例绑定的所有东西都会解绑,所有的时间监听都会移除

    • errorCaptured:捕获来自子组件的错误时调用

  20. post的几种提交数据方式

    • application/x-www-form-urlencoded:原生form表单

    • multipart/form-data:使用表单上传文件时

    • application/json:JSON字符串

    • text/html:html

    • rawtext/json/xml/html

  21. for each、for in、for of的区别

    • forEacharr.forEach()遍历数组元素进行操作,不接受return

    • for in:取的是key

    • for of:遍历的是value

  22. vuex的核心作用

  23. vue的底层原理:MVVM

  24. css加载会造成阻塞吗

  25. 从输入url到页面加载完成会发生什么?

    segmentfault.com/a/119000001…

    • 拿到url后,通过DNS解析拿到ip地址

    • 进行TCP连接,三次握手

    • 发送HTTP请求

    • 服务端处理请求并返回HTTP报文

    • 浏览器解析渲染页面

    • 连接结束,四次挥手

  26. 建立TCP连接的正确流程(连接时的三次握手):

    客户端向服务器端发送SYN包;服务端向客户端发送SYN+ACK;客户端回复ACK。
    
    第一次,本机将标识位 SYN 置为 1, seq = x(Sequence number)发送给服务端。此时本机状态为SYN-SENT
    第二次,服务器收到包之后,将状态切换为SYN-RECEIVED,并将标识位 SYN 和 ACK都置为1, seq = y, ack = x + 1, 并发送给客户端。
    第三次,客户端收到包后,将状态切换为ESTABLISHED,并将标识位ACK置为1,seq = x + 1, ack = y + 1, 并发送给服务端。服务端收到包之后,也将状态切换为ESTABLISHED。
    
    
  27. 断开时的4次挥手:

    客户端向服务器端发送FIN;服务器端回复ACK,并进入wait状态;服务器端确认并发送FIN;客户端回复ACK.
    
    第一次,客户端发送一个FIN置为1的包,ack = y, seq = x + 1,此时客户端的状态为 FIN_WAIT_1。
    第二次,服务端收到包后,状态切换为CLOSE_WAIT发送一个ACK为1的包, ack = x + 2。客户端收到包之后状态切换为FNI_WAIT_2。
    第三次,服务端处理完任务后,向客户端发送一个 FIN包,seq = y; 同时将自己的状态置为LAST_ACK。
    第四次,客户端收到包后状态切换为TIME_WAIT,并向服务端发送ACK包,ack = y + 1,等待2MSL后关闭连接。
    
    
  28. 原型、原型链、作用域、作用域链、继承、闭包

    • 原型:用来生产实例对象的模型

    • 原型链:实例模型有个指针指向原型对象,原型对象有个指针指向构造函数,这就形成了一条原型链,最终指向null

    • 作用域:变量或函数作用的范围

    • 作用域链:内部函数一直向外寻找变量的路径

    • 闭包:内部函数使用外部函数的变量和方法

      //闭包的运用(面试题)
      var go = function (a) {
      var str = 'go';
          var add0 = function (a) {
          	str += 'o';
          	return a ? str += a : add0;// 巧妙使用
          }
      	return a ? str += a : add0;// 巧妙使用
      }
      console.log(go('l'));//gol
      console.log(go()('l'));//gool
      console.log(go()()('l'));//goool
      
    • 继承:一个对象可以共享父级对象的一些属性而不需要去重复定义

    • 继承的方式:juejin.cn/post/684490…

      1. 组合继承:在子类函数中调用父类函数并传参。子类的构造函数定义为父类的构造函数,继承父类所有属性。缺点:子类的原型上多了不需要的父类属性,造成内存上的浪费

        function Parent(name, age) {
            this.name = name;
            this.age = age;
        }  
        function child(name, age, sex) {
            Parent.call(this, name, age);
            this.sex = sex;
        }
        child.prototype = new Parent()
        
        var c1 = new child('zenquan', '23', 'M')
        console.log(c1)
        
        
      2. class继承:extends,子类的构造函数中放入需要的参数,super方法中放入父类存在的参数

        class parent {
            constructor(name, age) {
                this.name = name;
                this.age = age;
            }
            getName() {
                return this.name;
            }
        }  
        class child extends parent {
            constructor(name, age, sex) {
                super(name, age);
                this.sex = sex;
            }
        }
        
  29. vue双向绑定原理

  30. vuereact区别

  31. 如何判断数据类型

  32. css权重

    !important>行内样式>id选择器>类选择器>标签选择器>通配符>继承
    
  33. 几种width

    clientWidth offsetWidth scrollTop scrollHeight
    宽度+padding 宽度+paddingborder 被卷上去的距离 自身实际的高度(不包括边框)
  34. 可以被继承的css属性:

    文本(font-),颜色(背景颜色不可以!),列表(list-style-type),元素可见性visibility