2021前端面试题整理

作者: halowyn | 来源:发表于2020-12-24 18:32 被阅读0次

    面试官主要还是针对简历上的内容进行提问的,所以一定要把写在简历上的内容自己进行深挖并拓展不仅要有广度,更要有深度,以下是我的面试题以及自己整理出来的答案,有不同意见可以评论区交流一下,我写的答案仅供参考。

    题目

    1. 带连接符的字符串转驼峰的方法

    2. css实现一个宽度为页面宽度的正方形,几种方法

    3. bootstrap实现栅格话布局原理

    4. 移动端适配方案

    5. 构造函数重写,指针指向,实例化构造函数的时候都做了什么

    6. 手写一个复选框列表的组件,实现全选和取消效果<check-list v-model="checkIds" :checkList="checkList"></check-list>

    7. promise的原理手动实现一个简单的promise、 promise.all、 promise.race、promise实现一个原生ajax、promise实现一个图片加载

    8. webpack了解多少,自己做了哪些配置

    9. loader和plugins的区别

    10. 有没有手写过loader

    11. nodejs

    12. react

      • this.setState是怎么实现异步的
      • 宏任务/微任务
      • hook
    13. promise的原理,是怎么实现的(同7)

    14. seo优化的过程是什么样的(自己项目上的,有兴趣可以了解一下,每一个操作的原因是什么, 为什么不直接用js,反而用jsp代替了(服务端渲染ssr)

    15. es6常用的方法

    16. 有没有用canvas做过截图

    17. 函数式编程

    18. 柯里化?compose?

    19. vue 组件 data为什么必须是函数?

    20. 设计模式的实现,工厂者模式、发布者订阅者模式手写代码说明

    21. 代码中有很多console.log,如何做到不改动代码的提前下,做到log内容的上报

    22. 正则实现首单享受<hightLight>50</highLight>元福利
      转换成
      首单享受<span class='highLight'>50</span>元福利

    23. flex实现以下布局


      image.png
    24. rem适配怎么设置0.01rem =1px

    25. typescript

    26. 自己觉得印象最深的项目,然后都做了什么事情

    27. 跨端项目:如何实现与端之间的通信,

      如何让客户端知道我需要拍照
      另外canvas实现一个手动马赛克的效果

    28. 函数防抖和节流
      31.笔试题:求连续子数组的最大和

    29. javascript实现继承的6种方式和其优缺点

    30. jquery链式调用的实现方式

    31. 实现一个Array.filter

    32. vuex的使用和原理

    33. 小程序是如何实现视图层和逻辑层的联系的

    34. uniapp的跨端方案是如何实现的

    35. 单元测试怎么查看覆盖率的

    36. V8引擎垃圾回收机制:导致内存泄漏的原因 -> 规避递归导致的内存泄漏:蹦床

    37. A网站请求B网站的多个js文件,可以同时获取吗(HTTP2多路复用)

    38. Set、WeakSet、Map、WeakMap的区别

    39. 内存中的变量是如何分配存储的

    40. var和let的区别

    41. 查找链表的倒数第N个节点

    42. flexible适配的原理,rem和em区别

    43. this指针的理解和应用场景,构造函数中的this指针问题

    44. jquery中的链式调用是怎么实现的

    45. proxy相对于defineproperty的优势

    46. jsBridge的回调,以及客户端实现

    47. webpack的treeShaking与其他打包工具之间的差异

    48. 服务端渲染的深入了解,nodejs返回页面之后是如何加载其他的script和css资源的

    49. call, apply, bind的区别

    50. 事件冒泡和捕获了解吗?先冒泡还是先捕获

    51. axios做了哪些封装

    52. http和https的区别,https相对于http的优点和缺点

    53. http2相对于http1的优化

    54. cookies和session的区别

    55. 浏览器缓存

    56. vue的通信方式

    57. vuex的常用的属性,多模块的情况下和单模块的异同

    58. mvvm和mvc的区别

    59. animation和transition的区别,以及如何知道这个动画执行完毕

    60. position和transform的区别和优缺点

    61. async返回什么,setTimeout和promise的执行顺序,为什么

    62. 输出结果是什么

    var n = 0
        function a() {
            var n = 10
            function b() {
                n++
                console.log(n)
            }
        b()
        return b
    }
    
    var c = a()
    c()
    console.log(n)
    

    64.js实现深度拷贝

    1. Javascript的事件流模型都有什么?

    2. promise 实现一个图片加载,完成loadImg

    loadImg('/a.png').then( res=>{
    ***
    })

    1. 300px div
      内容一行内容居中显示多行居左显示

    2. 打印输出

    async function async1() {
        console.log('async1 start');
        await async2();
        console.log('async1 end');
    }
    async function async2() {
        console.log('async2');
    }
    console.log('script start');
    setTimeout(function() {
        console.log('setTimeout');
    }, 0)
    async1();
    new Promise(function(resolve) {
        console.log('promise1');
        resolve();
    }).then(function() {
        console.log('promise2');
    }).then(function() {
    
       console.log('promise3');
    
    })
    
    
    new Promise(function(resolve) {
    
        console.log('promise4');
    
        resolve();
    
    }).then(function() {
    
        console.log('promise5');
    
    });
    
    console.log('script end');
    
    1. 打印输出
    var a = 10;
    function a() { };
    
    console.log(a); 
    
    (function () {
        console.log(a) 
    
        a = 5
    
        console.log(window.a)
    
         var a = 20
         
    })()
    
    console.log(a)
    
    1. 父元素宽高未知,子元素图片的宽高未知,实现图片居中显示的多种方式(grid布局了解吗,margin和padding分别是相对于谁的)
    2. 多种方法实现数组的乱排序
    3. 多种方式实现去除数组的空元素
    4. 如何实现a==1&&a==2&&a==3(结合defineProperty和proxy来做,考察对数据劫持和隐式转换函数重写的理解)
    5. nextTick的实现原理(考察vue异步批量更新)
    6. 浏览器缓存读取规则:可以分成 Service Worker、Memory Cache、Disk Cache 和 Push Cache,那请求 的时候 from memory cache 和 from disk cache 的依据是什么,哪些数据什么 时候存放在 Memory Cache 和 Disk Cache 中?
    7. 原生操作dom的方法有哪些
    8. 求输出结果(字节跳动)
    new Promise(function(resolve) {
          for (var i = 0; i < 10; i++) {
            resolve(i);
          }
        }).then(function(i) {
          console.log(i);
        });
        new Promise(function(resolve) {
          for (var i = 0; i < 10; i++) {
            function a() {
              resolve(i);
            }
          }
          a();
        }).then(function(i) {
          console.log(i);
        });
    // 0
    // 10
    
    1. 实现一个柯里化函数
    // 实现 currying 函数,使得 curryingSum 函数输出正确
    const currying = (func) => {
          var args = Array.prototype.slice.call(arguments, 1) // 除却第一个参数
          var curry = function () {
            if (arguments.length === 0) {
              return func.apply(this, args) // 无参数时直接返回求和的值
            } else {
              args = args.concat(Array.prototype.slice.call(arguments)) // 如果后续继续有参数,直接返回该函数
              // console.log(args)
              return curry
            }
          }
          return curry
        }
        const sum = (...args) => args.reduce((prev, cur) => prev + cur, 0)
        sum(1, 2, 3) // 6
        const curryingSum = currying(sum)
        console.log(curryingSum(1)(2)(3)())
        console.log(curryingSum(1, 2)(3)())
    

    看到题目之后先别着急看答案,自己思考一下

    解答:

    1. 带连接符的字符串转驼峰的方法 (如get-element-by-id)

    • 方法1. 正则匹配(面试官想要的最优解)
    let str = 'get-element-by-id'
    let res = str.replace(/-\w/g, (a) => {
      return a.toUpperCase()
    }).replace(/-/g, '')
    console.log(res)
    
    • 方法2. 字符串分割拼接
    let str = 'get-element-by-id'
    function toCamelCase (str) {
      let str1 = str.split('-')
      for (let i = 1; i < str1.length; i++) {
        str1[i][0].toUpperCase()
      }
      return str1.join('')
    }
    console.log(toCamelCase(str))
    

    2. css实现一个宽度为页面宽度的正方形

    • 方法1:vw
    .child {
      width: 50%;
      height: 50vw;
      background: #ccc;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
    
    • 方法2:百分比
    .child {
      width: 50%;
      height: 0;
      padding-bottom:50%;
      background: #ccc;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
    
    • 方法3
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
    }
    .child {
      display: flex;
      width: 50%;
      height: 50vw;
      background: yellow;
    }
    

    3. bootstrap实现栅格话布局原理

    栅格化列的种类,一行根据百分比分为12列,当col相加大于12时,超出部分当作下一行展示

    .col-xs-* 针对超小屏幕 手机(<768px)
    .col-sm-* 小屏幕 平板 (≥768px)
    .col-md-* 中等屏幕 桌面显示器 (≥992px)(栅格参数)
    .col-lg-* 针对特大的(≥1200px)
    

    通过媒体查询根据不同的屏幕适配对应的栅格化样式,添加对应的类,比如

    /*超小设备(手机:小于768px)*/
    @media(max-width:768px){
      .col-xs-1{ width: 8.33333333%;}
      .col-xs-2{ width: 16.66666667%;}
      .col-xs-3{ width: 25%;}
      .col-xs-4{ width: 33.33333333%;}
      .col-xs-5{ width: 41.66666667%;}
      .col-xs-6{ width: 50%;}
      .col-xs-7{ width: 58.33333333%;}
      .col-xs-8{ width: 66.66666667%;}
      .col-xs-9{ width: 75%;}
      .col-xs-10{ width: 83.33333333%;}
      .col-xs-11{ width: 91.66666667%;}
      .col-xs-12{ width: 100%;}
    }
     
    /*小型设备 (平板电脑:768px起)0*/
    @media(min-width:768px){
      .col-sm-1{ width: 8.33333333%;}
      ...
    }
     
    /*中型设备(台式电脑:992px起)*/
    @media(min-width:992px){
      .col-md-1{ width: 8.33333333%;}
      ...
    }
     
    /*大型设备(台式电脑:1200px起)*/
    @media(min-width:1200px){
      .col-lg-1{ width: 8.33333333%;}
      ...   
    }
    

    4. 移动端适配方案

    通过postcss-px-to-viewport插件实现px->vw的转化,安装插件之后进行如下配置

    loaderOptions: { // css预设器配置项
        postcss: {
            plugins: [
              require('postcss-px-to-viewport')({
                unitToConvert: 'px',
                viewportWidth: 750,
                viewportHeight: 1334,
                unitPrecision: 5,
                propList: [
                  '*'
                ],
                viewportUnit: 'vw',
                fontViewportUnit: 'vw',
                selectorBlackList: [],
                minPixelValue: 1,
                mediaQuery: false,
                replace: true,
                exclude: [/(\/|\\)(node_modules)(\/|\\)/]
              })
            ]
          },
          stylus: {}
        }
    

    5. 实例化构造函数, 求输出结果

        function A() {
            this.a = 1
            return {
                a: 2,
                b: 3
            }
        }
    
        A.prototype.b = 4
        A.prototype.c = 5
    
        let newObj = new A()
    
        console.log(newObj.a)
        console.log(newObj.b)
        console.log(newObj.c)
    

    输出:
    2
    3
    undefined

    考察点:new一个构造函数时具体执行了什么操作?

    1. 在内存中新建一个空对象;
    2. this指向这个内存中的空对象;
    3. 根据定义的键值和传入的参数,依次给这个空对象添加上键值对;
    4. 返回这个新的对象

    6. 手写一个复选框列表的组件,实现全选和取消效果<check-list v-model="checkIds" :checkList="checkList"></check-list>

    考察点:v-model语法糖
    父组件

    <template>
      <div class="list">
        <input type="checkbox" v-model="chooseAll">全选
        <check-list :checkIds="checkIds" :checkList="checkList" @update="arr => checkIds=arr"></check-list>
      </div>
    </template>
    <script>
    import CheckList from '@/components/CheckList'
    export default {
      name: 'list',
      components: {
        'check-list': CheckList
      },
      data () {
        return {
          chooseAll: false,
          checkIds: [],
          checkList: [{
            id: 1,
            name: '苹果'
          }, {
            id: 2,
            name: '梨'
          }, {
            id: 3,
            name: '橘子'
          }]
        }
      },
      watch: {
        chooseAll () {
          if (this.chooseAll) {
            this.checkIds = this.checkList.map(item => { return item.id })
          } else if (!this.chooseAll && this.checkIds.length === this.checkList.length) {
            this.checkIds = []
          }
        },
        checkIds () {
          this.chooseAll = this.checkIds.length === this.checkList.length
        }
      }
    }
    </script>
    

    子组件

    <template>
      <div class="hello">
        <ul>
          <li v-for="item in checkList" :key="item.id">
            <input type="checkbox" v-model="ids" :value="item.id" @change="$emit('update', ids)">{{item.name}}
          </li>
        </ul>
      </div>
    </template>
    
    <script>
    export default {
      name: 'CheckList',
      props: {
        checkList: Array,
        checkIds: Array
      },
      data () {
        return {
          ids: []
        }
      },
      watch: {
        checkIds () {
          console.log(this.checkIds)
          this.ids = this.checkIds
        }
      }
    }
    </script>
    
    

    7. 手动实现一个简单的promise, promise.all/promise.race

    promise

      class Promise1 {
          constructor (executor) {
            this.state = 'pending'
            this.result = null
            this.reason = null
            const resolve = value => {
              this.state = 'fulfilled'
              this.result = value
            }
            const reject = reason => {
              this.state = 'rejected'
              this.reason = reason
            }
            try {
              executor(resolve, reject)
            } catch (err) {
              reject(err)
            }
          }
          then (onFullfilled, onRejected) {
            if (this.state === 'fulfilled') {
              onFullfilled(this.result)
            }
            if (this.state === 'rejected') {
              onRejected(this.reason)
            }
          }
        }
        const a = new Promise1((resolve, reject) => {
          resolve('888888')
          // reject('888888')
        })
        a.then(data => {
          console.log(data)
        })
    

    promise.all

        Promise1.all = function(promiseArr) {
            let length = promiseArr.length
            let result = []
            let hasErr = false
            return new Promise1((resolve, reject) => {
                for (i = 0; i < length; i++) {
                    promiseArr[i].then(data => {
                        result[i] = data
                        if (i === length) resolve(result)
                    }, error => {
                        !hasErr && reject(error)
                        hasErr = true
                    })
                }
            })
        }
    

    promise.race

         Promise1.race = function(promiseArr) {
            let hasValue = false
            let hasErr = false
            return new Promise1((resolve, reject) => {
                for (let i = 0; i < promiseArr.length; i++) {
                    promiseArr[i].then(data => {
                        if (!hasValue && !hasErr) resolve(data)
                        hasValue = true
                    }, error => {
                        if (!hasValue && !hasErr) reject(error)
                        hasErr = true
                    })
                }
            })
        }
    

    promise实现一个原生的ajax请求

         let getJSON = function () {
          let promise = new Promise((resolve, reject) => {
              let client = new XMLHttpRequest()
              client.open('get', url)
              client.onreadystatechange = handler
              clent.responseType = 'json'
              client.setRequestHeader('Content-Type', 'application/json')
              client.send()
              function handler () {
                if (this.readyState === 4) {
                  if (this.status === 200) {
                    resolve(this.response)
                  } else {
                    reject(new Error(this.statusText))
                  }
                }
                
              }
            })
            return promise
          }
          getJSON('/getJson').then((data) => {
            console.log(data)
          }, (err) => {
            consoel.log('出错了')
          })
    

    给定一张图片的url,通过promise实现一个图片加载

        const url1 = '***.png'
        const url2 = '***2.png'
        loadImg(url1).then(img=>{
            console.log(img.width)
            return img
        }).then(img=>{
            console.log(img.height)
            return loadImg(url2)
        }).then(img2=>{
            console.log(img2.width)
            return img2
        }).then(img2=>{
            console.log(img2.height)
        })
        .catch(err=>{
            console.log(err)
        })
    
    1. webpack了解多少,自己做了哪些配置
    2. loader和plugins的区别
    3. 有没有手写过loader
    4. nodejs
    5. react
      • this.setState是怎么实现异步的
      • 宏任务/微任务
      • hook
    6. promise的原理,是怎么实现的(同7)
    7. seo优化的过程是什么样的(自己项目上的,有兴趣可以了解一下,每一个操作的原因是什么, 为什么不直接用js,反而用jsp代替了(服务端渲染ssr)
    8. es6常用的方法
    9. seo优化
    10. 设计模式的实现,工厂者模式、发布者订阅者模式手写代码说明
    • 一个对象作为特定任务或是另一对象的活动的观察者,并且在这个任务或活动发生时,通知观察者。观察者也被叫作订阅者(Subscriber),它指向被观察的对象,既被观察者(Publisher 或 subject)。当事件发生时,被观察者(Publisher)就会通知观察者(subscriber)。
    // 发布者订阅者模式
        let observer = {
          callbacks: [],
          add: function (fn) {
            this.callbacks.push(fn)
          },
          trigger: function () {
            this.callbacks.forEach((fn) => {
              fn()
            })
          }
        }
        observer.add(function() {
          console.log('我是订阅者1')
        })
        observer.add(function() {
          console.log('我是订阅者2')
        })
        observer.trigger()
    
    • 工厂模式:所谓工厂模式就是像工厂一样重复的产生类似的产品,工厂模式只需要我们传入正确的参数,就能生产类似的产品;

    工厂模式根据抽象程度依次分为简单工厂模式、工厂方法模式、抽象工厂模式;
    三种模式的代码实现:https://www.cnblogs.com/dengyao-blogs/p/11646810.html

    1. javascript实现继承的6种方式和其优缺点
      https://blog.csdn.net/weixin_38343894/article/details/79214821
    2. 在使用jQuery库的时候,是可以连续调用多个方法的,这是怎么实现的呢
    // 方法1,通过对象属性的方式
        let A = {
          name: 'hello',
          get: function  () {
            console.log(this.name)
            return this
          },
          set: function  () {
            console.log(this.name)
            return this
          }
        }
        A.get().set()
    // 方法2,通过函数的形式
        function A () {
          this.name = 'wyn'
        }
        A.prototype.get = function () {
          console.log(this.name)
          return this
        }
        A.prototype.set = function () {
          this.name = 'www'
          return this
        }
        let b = new A()
    
    1. 实现一个Array.filter
        Array.prototype.filter =  Array.prototype.filter || function (func) {
          let arr = this
          let r = []
          for (let i = 0; i < arr.length; i++) {
            if (func(arr[i])) {
              r.push(arr[i])
            }
          }
          return r
        }
    
    1. vuex的使用和原理

    2. 小程序和普通的H5页面有什么区别,如何实现视图层和逻辑层的联系的

    3. uniapp的跨端方案

      uin-app 和原生开发是有很大差别的,至少在性能和需求覆盖度上会差很多。uin-app 框架使用的其实是 cordova 的进阶版,也就是把 web 代码打包到本地,本地实质上还是通过 WebView 运行,那性能的瓶颈不言而喻。另外 uni-app 支持使用 Weex 框架拓展性能,本质上是通过桥的功能把 Vue 控件映射为原生控件进行渲染,效果和 react-native 差不多,虽然性能有所提升,但是和原生相比差距还是有的。

    4. http协议详细内容

    5. jsBridge的回调,以及客户端实现

    6. webpack的treeShaking与其他打包工具之间的差异

    7. 服务端渲染的深入了解,nodejs返回页面之后是如何加载其他的script和css资源的

    8. call, apply, bind的区别,是否立即执行

    9. 事件冒泡和捕获了解吗?先冒泡还是先捕获

    10. axios做了哪些封装

    11. http和https的区别,https相对于http的优点和缺点

      image.png
    12. http2相对于http1的优化

    13. [cookies和session的区别]s(https://www.cnblogs.com/l199616j/p/11195667.html)

    14. 浏览器缓存

    15. vue的通信方式

    16. vuex的常用的属性,多模块的情况下和单模块的异同

    17. mvvm和mvc的区别

    18. animation和transition的区别,以及如何知道这个动画执行完毕

    19. position和transform的区别和优缺点

    20. async返回什么,setTimeout和promise的执行顺序,为什么

    相关文章

      网友评论

        本文标题:2021前端面试题整理

        本文链接:https://www.haomeiwen.com/subject/mhvmwktx.html