让渡居凉经
让渡居前端面试题
这是在拉钩上面投的一家公司,早上九点左右收到面试邀请,注册了一个网站,然后开始做题,前端的问题没有细问,比较注重编程逻辑。下面放一下面试题
1.从事前端开发多久了(这个问题没什么好说的,根据自己实际情况答就可以了)
2.对原生js感觉如何
题目分析:实际上希望你回答出,在框架横行的时代,原生js有哪些优缺点
回答如下:
优点: 性能高——由于JavaScript运行在客户端,节省了web服务器的请求时间和带宽轻量级的脚本语言,运行结果和处理相对比较快。
针对性强——代码完全由自己的业务决定,不会产生多余的代码
缺点: 安全性差——由于JavaScript在客户端运行,可能被黑客利用
兼容性差、扩展能力低——在不同浏览器中的处理结果可能不同,代码抽象的层次较低。
当然并不是说原生开发怎么怎么不好,使用原生js可以锻炼基本功,对于博主这种前端小白来说再适合不过了。再说了万物皆可原生( ̄_, ̄ )
3.git merge和git rebase的区别
这个是考git命令,没什么好说的,直接上答案,此外博主找到了一篇总结git知识点的文章,有兴趣的可以看看(https://www.cnblogs.com/codingdevops/p/11447815.html)
回答如下:
git merge:将两个分支,合并提交为一个新提交,并且新提交有2个parent。
git rebase:会取消分支中的每个提交,并把他们临时存放,然后把当前分支更新到最新的origin分支,最后再把所有提交应用到分支上。
4.如何找到在特定提交中已更改的文件列表
题目分析:一开始我以为是在问我实际开发场景中如何处理这个问题,后来一想好像不对,再一看好像也是git方面的知识点,因为博主在公司主要都是用SVN,git有所遗忘了,所以那瞬间很尬QAQ
回答如下:
方案1:git diff-tree -r {hash},给定提交哈希值,这个命令将列出在该提交中更改或添加的所有文件。-r 标志会让命令列出各个文件,而不是仅将它们折叠到根目录名称中。
方案2:输出还将包含一些额外信息,可以通过以下两个标志轻松去掉:git diff-tree -no-commit-id -name-only -r {hash},这里 -no-commit-id 将禁止提交哈希值出现在输出中,而 -name-only 只会打印文件名而不是它们的路径。
5.如何恢复已经推送并公开的提交的过程
题目分析:还是在考git的知识点,话不多说,上答案
回答如下:
方案1:在新提交中删除或修复错误文件,并将其推送到远程存储库。这是修复错误最自然的方式。对文件进行必要的更改后,将其提交到远程存储库,使用命令:git commit -m“commit message”
方案2:创建一个新的提交,撤消在错误提交中所做的所有更改,使用命令:git revert
6.以下代码输出什么
for (var i = 0; i < 3; i++) { setTimeout(function() { alert(i); }, 1000 + i); }
题目分析:代码中是一个for循环里面有一个setTimeout函数,每隔(1000+i)ms输出i。首先要注意的是setTimeout是一个异步函数,每隔(1000+i)ms往任务队列里添加一个任务,只有当主线上的任务全部执行完,才会执行。所以当for循环这个主线执行完成之后i的值是3,于是应该输出的是3次3。
提问:如果这里的var变成了let,结果又是什么?
回答:for循环头部的let不仅将i绑定到for循环块中, 它也将其重新绑定到for循环体的每一次迭代中,确保上一次迭代结束的值重新被赋值。 setTimeout里面的function()属于一个新的域, 通过 var 定义的变量是无法传入到这个函数执行域中的, 而通过使用 let 来声明块变量,这时候变量就能作用于这个块, 所以 function就能使用 i 这个变量,所以结果是输出0,1,2
7.以下代码输出什么
(function() { var a = b = 5; })();
console.log(a);
console.log(b);
题目分析:var a = b = 5;可以拆分为b=3;var a=b;原因是js是具有右结合性的,也就是从右边往左边赋值。拆分完成后,题目中的函数是一个立即执行函数,在函数中b被赋值为5,注意!b是一个全局变量(下面会解释)。然后a是立即执行函数里面的变量,当函数执行完时a被释放,在外部打印的时候就会报错:a is undefined,而b会打印出5。
补充:为什么b是全局变量?因为在函数中使用var关键字进行显式声明的变量是做为局部变量,在全局范围内声明的变量为全局变量;而没有用var关键字,使用直接赋值方式声明的是全局变量(全局对象属性)。
还不懂的小伙伴可以看一下这个网址(https://www.jb51.net/article/155045.htm),解释的很详细
8.最近的较小值
让函数NearestSmallerValues(arr)获取存储在arr中的整数数组,并为列表中的每个元素搜索所有先前值,以查找小于当前元素的最近元素,并从这些数字创建一个新列表。如果在某个较小位置之前没有元素,请输入-1。
例如:如果arr为[ 5、2、8、3、9、12 ],则最接近的较小值列表为[-1,-1、2、2、3、9]。逻辑如下:对于5,没有较小的先前值,因此到目前为止的列表为[-1]。对于2,也没有较小的先前值,因此列表现在为[-1,-1]。对于8,最接近的较小值为2,因此列表现在为[-1,-1、2]。对于3,最近的较小值也是2,因此列表现在为[-1,-1、2、2]。这继续产生上面的答案。您的程序应使用此最终列表,并以空格分隔的字符串形式返回元素:-1 -1 2 2 3 9
例子:输入:[5、3、1、9、7、3、4、1] 输出:-1 -1 -1 -1 1 1 3 1
输入:[2,4,5,1,7] 输出:-1 2 4 -1 1
解题思路: 数组中的第一个数前面肯定没有比他小的数,所以第一个值直接给-1。然后从第二个数开始遍历数组,查找小于当前元素的最近元素,则直接从前元素向前查找,找到的第一个小于当前元素的就是符合要求的。
function NearestSmallerValues(arr) { var temp; //标志变量,用于确认是否找到符合条件的元素 var list=[]; list.push(-1); for(var i=1;i<arr.length;i++){ for(var j=i-1;j>=0;j--){ //从当前元素向前查找,一直找到数组第一个元素 if(arr[j]<=arr[i]){ //找到小于当前元素的数字,就把数字添加进list,并且跳出当前循环 list.push(arr[j]) break; } if(j==0){temp= true} //判定j是否0,是则代表到数组第一个元素也没有找到,将标志变量置为true } if(temp){ //如果没找到就添加-1,并且把标志变量置为false list.push(-1) temp =false } } str=list.join(' ') return str; }
9.分词
让函数WordSplit(strArr)读取存储在strArr中的字符串数组,该数组将包含2个元素:第一个元素将是一个字符序列,第二个元素将是一个由逗号分隔的长字符串,按字母顺序排列,表示任意长度的字典。例如:strArr可以是:[“ hellocat”,“ apple,bat,cat,再见,hello,黄色,为什么”]。您的目标是确定输入中的第一个元素是否可以分为两个词,其中两个词都存在于第二个输入中提供的字典中。在此示例中,第一个元素可以分为两个词:hello和cat因为这两个词都在字典中。您的程序应返回字典中存在的两个单词,并用逗号分隔。因此,对于上面的示例,您的程序应返回hello,cat。只有一种正确的方法将字符的第一个元素分成两个单词。如果无法将字符串分成字典中存在的两个单词,则不可能返回该字符串。第一个元素本身永远不会在字典中作为真实单词存在。
例子: 输入:[“ baseball”,“ a,all,b,ball,bas,base,cat,code,d,e,quit,z”] 输出:base,ball
输入:[“ abcgefd”,“ a,ab,abc,abcg,b,c,dog,e,efd,zzzz”] 输出:abcg,efd
10.通配符
让函数Wildcards(str)读取str ,其中将包含两个由空格分隔的字符串。第一个字符串将由以下字符集组成:+,*,$和{N},这是可选的。加号(+)表示单个字母字符,($)字符表示1-9之间的数字,星号(*)表示长度为3的相同字符的序列,除非后面跟{N}表示在序列中应该出现多少个字符,其中N至少应为1。您的目标是确定第二个字符串是否与输入中第一个字符串的模式完全匹配。例如:if str是“ ++ * {5} jtggggg”,那么在这种情况下,第二个字符串与模式匹配,因此您的程序应返回字符串true。如果第二个字符串与模式不匹配,则程序应返回字符串false。
例子: 输入:“ +++++ * abcdehhhhhh” 输出:false
输入:“ $ ** + * {2} 9mmmrrrkbb” 输出:true
11.反应电话簿
我们提供了一些简单的React模板代码。您的目标是在顶部创建一个简单的表单,该表单允许用户输入名字,姓氏和电话号码,并且应该有一个提交按钮。按下提交按钮后,该信息应与之前输入的所有信息一起显示在下面的列表中(自动按姓氏排序)。这样,应用程序可以用作简单的电话簿。使用一些基本的CSS样式在表中显示所有信息。
题目分析:考查react中父子组件通信方式,因为我对react不是特别熟悉,所以选择了子-父-子 props的方式,当然还有React Context、redux也可以实现,我就不举例了
import React from 'react'; import ReactDOM from 'react-dom'; const style = { table: { borderCollapse: 'collapse' }, tableCell: { border: '1px solid gray', margin: 0, padding: '5px 10px', width: 'max-content', minWidth: '150px' }, form: { container: { padding: '20px', border: '1px solid #F0F8FF', borderRadius: '15px', width: 'max-content', marginBottom: '40px' }, inputs: { marginBottom: '5px' }, submitBtn: { marginTop: '10px', padding: '10px 15px', border:'none', backgroundColor: 'lightseagreen', fontSize: '14px', borderRadius: '5px' } } } function PhoneBookForm({ addEntryToPhoneBook }) { return ( <form onSubmit={e => { e.preventDefault() }} style={style.form.container}> <label>First name:</label> <br /> <input style={style.form.inputs} className='userFirstname' name='userFirstname' type='text' /> <br/> <label>Last name:</label> <br /> <input style={style.form.inputs} className='userLastname' name='userLastname' type='text' /> <br /> <label>Phone:</label> <br /> <input style={style.form.inputs} className='userPhone' name='userPhone' type='text' /> <br/> <input style={style.form.submitBtn} className='submitButton' type='submit' value='Add User' /> </form> ) } function InformationTable(props) { return ( <table style={style.table} className='informationTable'> <thead> <tr> <th style={style.tableCell}>First name</th> <th style={style.tableCell}>Last name</th> <th style={style.tableCell}>Phone</th> </tr> </thead> </table> ); } function Application(props) { return ( <section> <PhoneBookForm /> <InformationTable /> </section> ); } ReactDOM.render( <Application />, document.getElementById('root') );
12.总结
以上面试题暴露出的问题:算法部分较为薄弱、关于react组件多种通信方式不熟、git命令生疏。继续加油叭!!