阅读 2934

前端实习面经

前端实习面经

不记得的部分也没有办法写下来了,这些天我看了太多的掘友们的blog了,不得不说,我才刚入门,不过我觉得一些经验还是可以回馈一下掘友们

二月份开始,在家边上学校的网课边学习前端,学到现在

新文达教育(电话面:20min)

这是一个小公司(我觉得),电话面,内容都很基础,学过前端就会吧,一个算法题,删除一个数组中的偶数,这实现的方式就多种多样了,电话面,也不用你写代码

  1. 浏览器回流是什么
  2. 图片懒加载是怎么实现的
  3. 事件循环
  4. 删除数组的偶数

不到20分钟的电话面,面完后就被录了,感觉流程不是很正规,所以感觉公司太小了。

图森未来(视频一面60min)

这个面试有点东西,只面试了一面,约的第二面我打电话取消了(因为二面之前有了其他公司的offer)

我对这个公司做过一些调查,觉得不是很大,面试会比较简单吧,但一面过程中我还挺多不会的,让我觉得它高大尚起来了

  1. 关于项目的问题太多了,我本身做的高仿小米商城,就是跟着教程做的,所以深入一点的东西都回答不上来,他问,做项目的过程中有没有遇到什么难点,我说有,项目我用的Vue框架,但子组件更新后,父组件不更新,导致了某个在父组件中展示的数据,没有及时更新,具体的什么难点我也不太清楚,因为难点我自己都不清楚,更别谈解决办法了,我给自己挖了一个无比巨大的坑,后悔死了,后面balabala,混过去了。
  2. 我简历写了什么,他就问什么,但我没好好准备简历上的内容,吃了一次亏,webpack打包原理?以及配置文件怎么写?我说不知道,只会用
// vue.config.js中webpack的配置信息,我当时没答出来
module.exports = {
  //...
  devServer: {
      host:'localhost',
      port:8080,
      proxy: {
          '/api': { // 捕获API的标志,如果API中有这个字符串,那么就开始匹配代理
              target: 'http://www.baidu.com/',// 代理的API地址,就是需要跨域的API地址。
              pathRewrite: {'^/api' : ''},// 比如访问的API路径:/api/users,最终代理访问的路径:http://www.baidu.com/users
              changeOrigin: true,     // target是域名的话,需要这个参数,否则会代理失败
              secure: false,          // 不检查安全问题,可以接受运行在 HTTPS 上,可以使用无效证书的后端服务器
          },
          '/api2': {
              .....
          }
      }
  }
};

复制代码
  1. 组件怎么按需加载?我解释了半天都说不清楚,因为我是真的只有一点点影响,不知道项目里面具体的实现

现在知道了,大概有两种实现方式,都是利用模块化,一种是require()来实现异步按需加载,在es6提出import()加载方式后,也能使用import()加载了,每个组件被打包成一个js文件,这种方式需要比较新的webpack来打包。

  1. 前端怎么进行性能优化?面试前我背了挺多的,但是面试过程中只想出来了两个
  2. 前端实现跨域问题?
  1. 利用接口代理的方式,主要是配置服务器
  2. 利用jsonp来进行跨域
  1. 请求服务器的数据时,怎么对数据接口进行统一拦截,对request和respose数据都要进行拦截,怎么实现
  2. 组件间的通信,我说了五种方式
    1. props和$emit
    2. children/children / parent
    3. ref / refs
    4. eventBus
    5. Vuex

但是他问我会不会provide / inject,我说听过,但是没用过,所以不会

  1. Vuex中一般存放那种数据

面试结束后我觉的肯定凉凉,但是约了二面,所以大家一定要自信啊!!!

跟谁学(笔试20min,视频面试60min)

(给了offer,也打算去了,大厂等下一个实习再去吧,现在实力不允许)

  1. 笔试(给了60min,用来20min):基础的css、html、js问题

只记得一些题,因为有点简单,但我有些还没背熟

  • position的全部属性是什么,我有些不知道

  • html标签语义化的作用

  • 实现一个字符串的反转

剩下的考了一些基本的css,有些属性我真的是被不全,也有简答题,我觉得只要意思对了就行,这不是学校,不是考试,面试官懂你就行,关于笔试,只要学前端有一段时间就不用担心了!

  1. 面试

不得不说,我真是一个luckydog,遇到东大校友

  1. 图片点开时,比较模糊,然后逐渐变得清晰,我相信大家都遇到过,我一开始没理解他的意思,我说了图片懒加载技术,后面他说他问的不是这个,至于后面他和我说这是png的一种特性,浏览器接收了浏览器的一部分后就会展示图片,当传来数据慢慢增加时,图片当然变得更清晰了
  2. hash路由和history路由的区别

当进行路由跳转时,hash路由和history路由都不会进行整个页面的刷新,二者跳转都相当于是在同一个文档中的锚中跳转,所以不会刷新,history需要后端协同,hash路由不需要,但是hash路由跳转时,后端不知道是否跳转,也就是说对后端来说是透明的。

  1. 题目如下
// url参数解析http://xxx.com/yyy?a=1&b=2&c=3   返回 {a:1,b:2,c:3}
// 我的解答:
let str = 'http://xxx.com/yyy?a=1&b=2&c=3'
const fn = (str) => {
  const result = {}
  const temp = str.split('?')[1].split('&')
  for (let i = 0; i < temp.length; i++) {
    let temp2 = temp[i].split('=')
    result[temp2[0]] = temp2[1]
  }
  return result
}
console.log(fn(str));
复制代码
  1. 如下图,如果queryString被编码后怎么转换成中文,我说不知道,但我知道js里面有一个api可以转换,后面知道了,我居然之前写过与这相关的文章,面试时真的sb了,escape,encodeURI,encodeURIComponent的使用场景,后面知道可以用decodeURIComponent

  1. 题目如下
// 实现一个模板替换function,例如:输入aaa{{xxx}}bbb{{yyy}}ccc,{xxx:1,yyy:2},返回aaa1bbb2ccc
let str = 'aaa{{xxx}}bbb{{yyy}}ccc'
let obj = { xxx1yyy2 }

const fn = (str, obj) => {
  let count = 0
  let temp = ''
  let result = ''
  for (let i = 0; i < str.length; i++){
    if (str[i] === '{') {
      count ++
    }else if (str[i] === '}') {
      count--
      if (count === 0) {
        result += obj[temp]
        temp = ''
      }
    }else if (count === 2) {
      temp += str[i]
    } else {
      result += str[i]
    }
    
  }
  return result
}

console.log(fn(str,obj));
复制代码

上面内容用来20分钟左右,他觉得可以了,我可以过了,后面发现是校友,我就向他多取了一些经,是一个好人,这也是我选择跟谁学的一个较大的原因吧,有一个好学长在里面。

字节跳动(视频一面:60min,视频二面:60min)

一共两面,第一面过了,感觉第二面凉凉,说如果还有面试,hr会通知你的,第一面聊了一下轮播图的实现原理和一点点css,围绕transform,和浮动布局,前端里面的单位,前面的知识点是围绕我项目展开的,然后就是下面的1和2两道代码题,第二面聊了点http和https,http缓存,接着就是下面的3、4、5题,感觉算法很重要,多用js写代码很重要。

  1. 实现一个repeat方法,要求如下:
// 需要实现的函数 function repeat (func, times, wait) {}
// 使下面调用代码能正常工作 const repeatFunc = repeat(console.log, 4, 3000);
repeatFunc("hellworld"); //会输出4次 helloworld, 每次间隔3秒
复制代码

我有思路,但无奈当时状态不好,脑子晕,和面试官讲了思路,但是代码没写出来,没发挥出正常实力

最后和面试官和我讨论说可以用(setTimeoutsetInterval两种方式实现,我当时想的是setInterval

后来重新写了一下代码

function repeat(func, times, wait) {
    return (arg) => {
        for (let index = 1; index <= times; index++) {
            setTimeout(() => {
                func(arg)
            }, index * wait)
        }
    }
}
复制代码
  1. 实现一个函数,输入是两个二进制数的字符串,输出两个数相加后的十进值结果。
 add('01', '10') = 3
复制代码

我用了复杂的算法来实现,因为面试的状态真不好,我和面试官讲了两种方法,一种是将短的字符串前面补上零,然后从字符串的个位开始同时遍历相加,并加上进位标志,另一种方法是不补零,面试官和我说如果将两个字符串reverse一下就好多了,就可以正序遍历,而不用倒序遍历,我被我自己蠢到了

最后面试官和我说了用parseInt('01', 2); 实现,我太孤陋寡闻了,不知道parseInt居然可以传两个参数

代码如下:

const add = (str1, str2) => {
    return parseInt(str1, 2) + parseInt(str2, 2)
}
复制代码
  1. 从左往右看一棵树,输出看到的节点,我的想法是层序遍历,然后输出每一层的第一个数,代码也实现了
// 下面是面试官给的数的结构
interface Node {
//   left: Node;
//   right: Node;
//   value: string;
// }
// 我实现的代码
function levelNode(node,level){
  this.node = node
  this.level = level
}

const fn = (node) =>{
  const queue = []
  let result = []
  let ans = []
  let level = 0
  if(!node) {
    retun result
  }
  queue.push(new levelNode(node,0))
  while(queue.length){
    let tempNode = queue.shift()
    if(!result[tempNode.level]){
      result.push([])
    }
    result[tempNode.level].push(tempNode.level.value)
    if(tempNode.node.left){
      queue.push(new levelNode(tempNode.node.left,tempNode.level + 1))
    }
    if(tempNode.node.right){
      queue.push(new levelNode(tempNode.node.right,tempNode.level + 1))
    }
  }
  for(let i = 0; i < result.length; i++){
    ans.push(result[i][0])
  }
  return ans
}
复制代码
  1. 实现数组的扁平化

这个比较简单,代码如下

const flat = (arr,result = []) => {
  if(Array.isArray(arr)){
    for(let i = 0; i < arr.length; i++){
      flat(arr[i],result)
    }
  }else{
    result.push(arr)
  }
  return result
}


let temp =[1, [2, [3, [4]]]]

console.log(flat(temp))
复制代码

问题是这个实现面试官不满意,他加要求,在实现过程中使用splice对原数组进行操作,最后不能返回一个新数组,也就是说执行函数后,原数组已经被扁平化了,我哭了,不会

后来又想了一下:

const flat = (arr) => {
    for (let i = 0; i < arr.length; i++) {
        const temp = arr[i];
        if(Array.isArray(temp)) {
            arr.splice(i, 1, ...flat(temp))
        }
    }
    return arr
}

复制代码
  1. 第五题就太有难度了
// 题目如下
fs.readFile('1.txt', (err, data) => {});

const newReadFile = promisify(fs.readFile);

newReadFile('1.txt')
  .then(data => {})
  .catch(err => {});

promisify

利用promisify函数封装fs.readFile函数,封装成promise的形式,请实现promisify
复制代码

这也太有难度了吧,他问我会不会promise,我说了解一点点,他就让我做这道题,我还是一个孩子,好吧?

后来看了一些别人的文章,写了一种实现方法:

const promisify = (func) => {
    return (filePath) => {
        return new Promise((resolve, reject) => {
            func(filePath, (err, data) => {
                if (!err) {
                    resolve(JSON.parse(data))
                }
                else {
                    reject(err)
                }
            })
        })
    }
}
复制代码

最后我问面试官我有哪些不足,总的来说,就是:写代码的时候,如果卡克了,抓紧时间说,不会的赶紧说,因为面试官想知道你会什么,如果你一直卡在不会的上面,那么时间就浪费了,你会的东西就展现不出来了。

360

约了下周面,但考试太多了,不想再试了,就跟谁学了吧,所以取消了面试

其中我在跟谁学和字节跳动面试中问了我哪里不足,都说了我接触的前端的时间不长,所以我还是慢慢积累吧。

更多

我在校还有两周时间,后面的四个考试两个课设都没开始准备,因为一直在准备面试了,时间比较紧,所以此文有许多写的不好的地方,望掘友们体谅,毕竟我还是一个编码小孩

文章分类
前端
文章标签