2021前端面试题整理

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

题目

  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的执行顺序,为什么

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 1、解释一下CSS的盒子模型? ☆ 答:1)盒模型: 内容(content)、填充(padding)、边界(mar...
    高磊_IT阅读 783评论 0 7
  • css相关 1. 万能居中 1.margin: 0 auto;水平 2.text-align: center;水平...
    chaocc阅读 950评论 0 2
  • 前言 记录面试大厂的一些面试题,用作保留并分享(部分重复题目会剔除) 阿里 1、promise规范?有多少种状态 ...
    半条河粉阅读 261评论 0 5
  • 1、JS的数据类型只有浮点型,没有整型。null,underfined,boolean,number,string...
    6e5e50574d74阅读 2,178评论 2 1
  • 简单面试题 1.map与foreach区别、 共同点1.都是循环遍历数组中的每一项。2.forEach() 和 m...
    栀璃鸢年_49a3阅读 1,943评论 2 18