2018秋招前端面试回顾(阿里、百度、网易、迅雷、美团等)

今年秋招对我是个打击,不过也让我认清了现实。借用鲁迅先生的一句话,真正的勇士敢于直面惨淡的人生,敢于正视失败的面试。面试失败不可怕,可怕的是不能吸取教训。在吸取教训上我做的不好,不然也不会有些面试问题记不住了。回顾几次面试失败经历,我总结了一下各家公司问的问题,为未来作打算,也为师弟师妹们做个参考。总结了一下,发现实习经历真的很重要,而且项目经验也要重点突出一些东西,展现自己的技术特点,让面试官无懈可击。不然问一些东西说不出来就很尴尬了。

  1. 阿里一面(其实一面挺简单的,但发挥不好,面试官希望你会框架。问我react时,我一谦虚说不算很会,就不问我了,然后就挂了):

    • web语义化
    • meta标签作用(页面信息、搜索引擎、不同设备)认识<meta>这篇文章讲得很全面。
    • 行内元素、块元素有哪些,布局
    • 布局方式
    • 三栏布局
    • css选择器优先级
    • http请求过程
    • http2.0了解
    • es2015了解哪些新特性(let/const,promise,class,set/map等忘了说箭头函数)
    • 箭头函数和普通函数区别(this指向、不能做构造函数、不能使用arguments等)
    • 异步编程(回调函数、监听/订阅、promise、async/await)
    • promise相关,规范、状态
  2. 百度三面(百度做了一个试题集,真是用心!!!面试感觉还是挺好的,很愉快的面试,但可怜的我并没有收到offer。另外有些面试会考手写代码,从头写到尾,不知道为什么没考我。。。) 
    百度一面:

    • 自我介绍
    • 获取页面上个数top3标签
    • 提取url键值对
    • console.log输出加上“hello”
    • linux bash命令cp/rm/mv/cat/ln -s/alias
    • 有一个目录很深,如何很快的进入(建立软链接、设置别名?)
    • ajax跨域(cors、反向代理)
    • 简述jsonp过程
    • ajax请求过程
    • 两栏布局
    • css选择器优先级
    • 离线缓存(manifest(貌似废弃了)、service worker(还不成熟))
    • 客户端存储方式及异同
    • 自定义表单,使各浏览器表现一致

    百度二面:

    • 自我介绍
    • 继承方式(原型链、组合模式、寄生组合式继承)
    • web性能优化、图片优化(雪碧图懒加载)
    • web安全:xss csrf sql注入
    • linux部分知识tail top
    • 自定义dialog组件(注意:要用闭包封装模块)
    • nodejs http获取百度页面,把百度改为千百度
    • 输入url过程
    • 单纯的聊天(不记入面试):看一个页面布局,说出布局想法

    百度三面(总监面):

    • 自我介绍
    • 某个取值范围的随机数生成
    • nodejs优点
    • ajax请求过程
    • 项目相关
    • 谈人生规划
  3. 网易一面:

    • 写一个继承,解释原型链
    • css规范化
    • 闭包应用、模块
    • mvvm相关
    • 知道哪些设计模式
    • 两列布局
    • 跨域方法
    • flex布局属性
    • 事件流的三个阶段,哪些事件不能冒泡
  4. 迅雷一面(不得不说,迅雷笔试很有水平):

    • 项目相关
    • unicode与utf-8字符编码方式关系
    • nodejs处理请求过程
    • require(‘child_process’).fork和linux fork区别
  5. 美团一面:

    • webpack原理
    • 闭包自由发挥
    • react优势(组件化、虚拟dom)
    • 怎么设计好的组件
    • 项目相关
    • 反转链表
    • https与http区别
    • git命令了解哪些
    • github开源做过哪些,贡献过什么,pr过吗

最后说一句:厉兵秣马,砥砺前行。我还要继续再战。

------------------------------------------------------------------------------------

2018年搜狗秋招前端笔试题:字符串删除

昨天做了搜狗前端笔试题,其中有一道题目是为字符串添加一个删除方法,给定一个参数n,求从该字符串删除n个字符组成的不同子串个数。题目看起来很简单,但是并不好编写。如果字符串字符各不相同还好说,直接可以使用排列组合公式来得到最终的个数;否则的话就得考虑删除后可能会产生相同的子串了。这样的话就得做一个Set来保存所有的字符串了。(我是这样想的,不知道还没有什么其他的方法。)当时想的是递归,但迫于时间没有写出来,所以趁着最近时间充裕,把算法实现了出来。如有错误,请不吝指正。

console.log('---从长为m字符串删除k个字符组成的不同子串个数---');
String.prototype.delete=function(k){
  if(k==0)return 1;
  var l=this.length;
  var tmp=[];
  var set=new Set();
  help(this.split(''),0,k,tmp);
  //print(set)
  return set.size;
  function help(arr,start,k,tmp){
    if(k==0){
      var rest=arr.filter((item,index)=>tmp.indexOf(index)==-1);
      set.add(rest.join(''));
      return;
    }
    if(l-start-1<k-1)return;
    for(var i=start;i<l;i++){
      tmp.push(i);
      help(arr,i+1,k-1,tmp);
      tmp.pop(i);
    }
  }
}
console.log('------test------');
console.log('segeg'.delete(0))  //1
console.log('segeg'.delete(1))  //5
console.log('segeg'.delete(2))  //8
console.log('segeg'.delete(3))  //6
console.log('segeg'.delete(4))  //3
console.log('segeg'.delete(5))  //1
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

算法的关键是递归函数help(arr,start,k,tmp)。它接收四个参数,arr是字符数组,把原来的字符串转为了数组。start是开始位置,表示从start开始的位置都可以删除,之前的保持不变。k表示还能删除几个字符,当k=0时递归停止。tmp是保存的删除的字符索引。set保存删除字符之后的数组,该数组是过滤tmp中保存的索引得到的。最后只返回set的长度就可以了。每次递归的时候选择一个字符,把它保存下来,start+1,k-1,继续递归,等它完成后弹出该字符,继续下一个字符的递归。

最近感觉自己的递归水平太差了,笔试题的递归基本都写不出来,像全排列什么的,所以要加强联系了。这道题是我自己理解的解法,如果您有更好的方法,欢迎讨论。

--------------------------------------

前端面试题:如何使字符串可执行

这是一道今年腾讯春招的面试题。当考官一开始问我这道题的时候,我没有反应过来,什么叫使字符串可执行。好吧,请原谅我的无知。考官耐心的解释,字符串可执行的意思是将字符串转为立即执行的代码,如字符串var a=23;,使其经过某种操作后确实有个值为23的a变量。听了面试官的话后,我第一时间想到了eval方法。然而面试官并不满意,追问我还有其他方式吗,我一时没有想起来。面试过后我就想总结一下这个问题,不过因为拖延症,拖到今天才写,敬请见谅。本文内容主要借鉴《JavaScript忍者秘籍》中使字符串转为立即执行的代码一节。下面将讲述字符串可执行的四种方式。

1. eval()方法

eval()方法是一个很强大的方法,它接收一个字符串作为参数,当解析器发现代码中调用该方法时,会将传入的参数当作ECMAScript语句来解析,然后把执行结果插入到原位置。如代码eval('var str="hi"');,执行了这个语句后,就可以直接使用变量str了,如console.log(str)将输出”hi”。不过关于这个方法有以下几点要注意:

(1). 通过该方法执行的代码有与该执行环境相同的作用域链。这意味着它可以引用在包含环境中定义的变量。也意味着它可以形成闭包,这与下文的Function方法形成对比。

var str="hi, I'm student!";
eval('console.log(str)');
//output:hi, I'm student!
 
 
  • 1
  • 2
  • 3

(2). 在eval()中创建的任何变量或函数都不会被提升。这很好理解,因为它只有在解析之后才会运行。

f1()    //Uncaught ReferenceError: f1 is not defined
eval("function f1(){console.log('hi')}")
 
 
  • 1
  • 2

(3). 任何不是简单变量、原始值、赋值语句的内容都需要在外面包装一个括号。执行返回结果则是最后一个表达式的执行结果。eval("{name:1}")的结果是1,惊不惊喜,意不意外?

var o1=eval("1");
console.log(o1);
//output:1

var o2=eval("{name:1}")
console.log(o2);
//output:1    why?

var o3=eval("({name:1})")
console.log(o3);
//output: Object {name: 1}

eval("3+4,5+6")//output:11
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(4). eval()方法是全局方法,但eval和window.eval结果有时不同的。前者作用域顶端是当前上下文,后者作用域是window对象。

var color='red';
function test(){
  var color='blue';
  eval('console.log(color)');
  window.eval('console.log(color)');
  with(window){
    eval('console.log(color)');
  }
}
test()
//outputs:
//blue
//red
//red
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
2. 使用Function构造器

我们都知道函数实际上是对象。每个函数都是Function类型的实例,而且都与其他引用类型一样具有属性和方法。函数除了使用函数声明和函数表达式,第三种定义函数的方式就是使用Function构造函数。以下摘自《JavaScript高级程序设计》:

Function构造函数可以接受任意数量的参数,但最后一个参数始终都被看成是函数体,而前面的参数则枚举出了新函数的参数。 
我们不推荐读者使用这种方法定义函数,因为这种语法会导致解析两次代码(第一次是解析常规的ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能。

我相信大家平常也很少使用这种方式,不过这种方式在模板引擎中(如EJS)应用很广泛。使用它确实能使字符串执行,只不过作用域是在函数里。但有一点要注意,就是它不会创建闭包,请看如下代码:

var color="red"
function test1(){
  var color="blue";
  eval("var f1=function(){console.log(color)}");
  return f1;
}
test1()()
//output:blue

function test2(){
  var color="blue";
  var f2=new Function("console.log(color)");
  return f2;
}
test2()()
//output:red       no closure!
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
3. 使用setTimeout

setTimeout通常被用来执行异步代码,如可以用setTimeout(function(){console.log(2)},1000)来实现隔1s后输出2。不过你也可以在第一个参数中传入字符串,如下所示:

function print(num){
    console.log(num);
}
setTimeout("print(2)",1000);
 
 
  • 1
  • 2
  • 3
  • 4

当传入的第一个参数为字符串时,感觉像是在使用eval方法处理似的,至于是不是,我也不知道。如果您知道,请不吝赐教。其实setTimeout很强大,我也收集过一篇讲述setTimeout的好文章,就是它了:你应该知道的setTimeout秘密

4. 巧用<script>标签

将要执行的代码放在动态生成的script标签內,并将标签注入文档中,同样可实现字符串的执行。如下所示:

var str="console.log(2222)"
var script=document.createElement('script');
script.text=str;
document.body.appendChild(script);
document.body.removeChild(script);
//output:2222
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

由于本人才疏学浅,暂时只知道这四种,如果您还有其他方法,欢迎指教。如您发现错误,请不吝指正。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值