前言:
🤡 作者简介:我是Morning,计算机的打工人,想要翻身做主人 🙈 🙈 🙈
🏠 个人主页:Morning的主页
📕系列专栏: 前端面试备战
📞 如果小编的内容有欠缺或者有改进,请指正拙著。期待与大家的交流
🔥如果感觉博主的文章还不错的话,👍点赞👍 + 👀关注👀 + 🤏收藏🤏
文章背景:
在9.29🌕🌕🌕那天好多同学都回了家,我下午早早的吃了晚饭回到了自习室学习。挺大的一个考研教室,只有我一个人这么早来学习。(我只是找一个安静的学习环境,其实我不考研哈哈哈)。我是坐在窗户边的位置,看着一年中最圆的月亮,还有空寂的教室,当时的思乡情节达到了巅峰👾 👾 (其实只是太孤寂了哈啊哈哈)。但是还是埋下头来好好学习,写了几道大厂笔试题。
其实大家要知道,前端水准体现在哪里?我认为不是你的Vue、React使用的有多6,而是JS的熟练程度决定了水平。一昧的只知道使用框架做需求,那不就是一个前端切图仔么。💢💢
一定一定要开始重视JS的基础兄弟们,加油👊👊👊
今天呢和大家分享一下最近学习的笔试题。既然是10月1日的国庆节,那么就来11道题吧。只有对祖国没用的人才放假,给我冲!!
如果大家也有好的学习资源希望大家评论区多多留言
目录
十.每隔1s打印当前时间,格式为YYYY-MM-DD hh:mm:ss
十一.能否使用某种方式将下面的语句使用展开运算符而不导致类型错误
一.翻转字符串
var str='sumaolin'
console.log(str.split('').reverse().join(''));//方法一
console.log([...str].reverse().join(''));//方法二
console.log(Array.from(str).reverse().join(''));//方法三
var res=[]
for(var i=str.length-1;i>=0;i--){
res.push(str[i])
}
console.log(res.join(''));//方法四
console.log(str);//sumaolin
在这里使用了四种方式,前三种本质上是先变成数组使用数组的reverse方法,在变回字符串。最后一种是使用了循环,相比就比较复杂一些些。主要是考察大家的数组和字符串方法
此外注意这些数组或者字符串的方法并没有改变原来字符串的值
这几个数组方法会改变原数组,其余的大多不变
push、unShilft//返回值是数组的长度
pop、shilft //返回值是被删掉的值
splice //返回的是被删掉的值组成的一个数组
reverse //返回反转后的数组
sort //返回排序后的数组字符串方法目前据我所知并没有改变原字符串的方法
二.数组去重
1.Set
使用Set去重之后得到的结果是一个Set类型,使用扩展运算符将其变为数组类型
function unique(arr){
return [...new Set(arr)]
}
console.log(unique(arr));
2.双重循环
让数组中的一个元素和前面的所有元素比较,如果相等,就把那个元素删除(因为删除了一个元素,下一个元素的下标就需要-1)。那个元素便是外层循环中的i,与之相比的就是内层循环中的j。
function unique(arr){
for(var i = 1;i<arr.length;i++){
for(var j = 0;j<i;j++){
if(arr[i]===arr[j]){
arr.splice(i,1);//删除1个从索引为i开始的元素
i--;
}
}
}
return arr
}
console.log(unique(arr));
3.indexOf/includes
indexOf:在数组中找到参数第一次出现时的下标,不存在返回-1(其实我个人认为indexOf在字符串中的使用更多一点,不介意在数组中使用indexOf)
function unique(arr){
var newArr=[]
for(var i = 1;i<arr.length;i++){
//如果在新数组中找不到在原数组中遍历的元素的话,就将其加入到新数组
if(newArr.indexOf(arr[i])==-1){
newArr.push(arr[i])
}
}
return newArr
}
console.log(unique(arr));
includes:判断一个数组是否包含一个指定的值,如果是返回 true,否则false。
function unique(arr){
var newArr=[]
for(var i = 1;i<arr.length;i++){
if(!newArr.includes(arr[i])){
newArr.push(arr[i])
}
}
return newArr
}
console.log(unique(arr));
4.filter
通过filter遍历数组的每一个元素,如果该元素的下标==使用indexOf查找该元素返回的下标,则证明是第一次出现。将所有第一次出现的元素收集起来就完成了去重
function unique(arr){
var newArr=[]
arr.filter((item,index)=>{
console.log(item,index);
if(arr.indexOf(item)==index){
newArr.push(item)
}
})
return newArr
}
console.log(unique(arr));
5.reduce
对于reduce不熟悉的小伙伴看我的此篇博客
var names=['Alice','Ben','Cris','Dog','Elephant','Ben']
var obj=names.reduce((pre,cur)=>{
if(!pre.includes(cur)){
return pre.concat(cur)
}else{
return pre
}
},[])
console.log(obj);//['Alice', 'Ben', 'Cris', 'Dog', 'Elephant']
三.找出任意html中的所有不重复的html的标签
😣😣😣第一次看到这个需求的时候我的表情就是这样的,不知道小伙伴写的时候是不是想我一样毫无头绪。但只用两行短短的代码就可以完成这个需求
var arr=[...document.querySelectorAll('*')].map(v=>v.tagName);
console.log([...new Set(arr)]);
<1>使用通配符查找出所有元素(此时结果是伪数组),
<2>使用扩展运算符将其变为数组
<3>使用map方法提取出标签名
<4>使用Set数组去重
console.log('这个代码也可以合并成一行')
[...new Set([...document.querySelectorAll('*')].map(v=>v.tagName))];//报错
但是要注意❗❗❗上面可一定要加分号呀,不然js会认为你下面的代码会拼接到上一行,要养成良好的编程习惯
四.手写实现数组map和filter方法
一提到手写方法,可能很多小伙伴都感觉很难,无从下手
第一,你要熟悉这个方法,明白怎么去使用。在写之前可以使用一下,更有利于书写思路
第二,捋清楚调用者是谁,返回值是什么
第三,要清楚要在原型链上去写方法,会经常使用到this
map和filter方法,调用者都为数组,都是输出一个新数组,参数为回调函数
map
var arr=[1,2,3]
console.log(arr.map(v=>v+1));
//map方法传入的参数是个回调函数,即
function fn(v){
return
}
//开始手写方法
Array.prototype.Mymap=function(fn){
var newArr=[]
for(var i=0;i<this.length;i++){
newArr.push(fn(this[i]))
}
return newArr
}
console.log(arr.Mymap(v=>v+1));
filter
var arr=[1,2,3]
console.log(arr.map(v=>v<3));
//回调函数
function fn(v){
return v<3 //返回的是一个布尔值
}
//开始手写方法
Array.prototype.MyFilter=function(fn){
var newArr=[]
for(var i=0;i<this.length;i++){
if(fn(this[i]))
newArr.push(this[i])
}
return newArr
}
console.log(arr.MyFilter(v=>v<3));
map与filter的区别与区别
首先都将原数组进行了遍历,使用每一个原数组的元素传入回调进行处理
区别:
1.回调函数的不同
map返回的是处理后的值,filter返回的是是否符合条件得出的布尔值
2.传入新数组的值不同。
map传入的是处理后的值,filter传入的是回调返回结果为true的原数组的元素
五.手写call、apply
call
首先捋清楚思路,我们从运用可以看出来,
- getName要执行
- 我们想要getName的this指向man,也就是call的参数(context)
- 是getName调用了call函数,所以我们要写的apply方法中的this就是GetName
- 如果在context里面定义一个函数fn,fn又恰好是我们想要执行的getName的话,那么getName里面的this就变成了context。这个时候 bingo!🔥🔥我们想要的结果就神奇的出来了
其核心思想就是将要调用的函数放到有数据的对象中,将函数中的this指向这个对象。
var person={
getName:function(){
return this.name
}
}
var man={
name:'苏茂林'
}
//call的运用
console.log(person.getName.call(man));
//开始手写call方法
Function.prototype.myCall=function(context){
var result
//不确定是否传了参数,如果没传,就让他指向window
var context=context||window;
//getName要执行,this要指向context
context.fn=this
//不确定传入参数的个数,但是第一个肯定是this要指向的对象,其余的参数就是getName所需要的参数
//将context后面的参数全拿出来。arguments返回的结构是Arguments类型,使用扩展运算符变为数组,再使用slice方法
var args=[...arguments].slice[1]
result=context.fn(...args)
//得出结果后将自己加的context.fn删除,避免改变原先的结构
delete context.fn
return result
}
console.log(person.getName.myCall(man));
apply
相比call,apply的不同在于其第二个参数是以数组的方式传递的,要使用时直接展开传入即可
//开始手写方法
Function.prototype.myApply=function(context){
var result
//不确定是否传了参数,如果没传,就让他指向window
var context=context||window;
//getName要执行,this要指向context
context.fn=this
//判断是否存在第二个参数,存在的话使用扩展运算符展开
if(arguments[1]){
result=context.fn(...[arguments[1]])
}else{
result=context.fn()
}
//得出结果后将自己加的context.fn删除,避免改变原先的结构
delete context.fn
return result
}
console.log(person.getName.myApply(man));
六.获得20~50之间的随机数
在第一时间兄弟们的想法是不是创建一个随机数再使用乘法。但是面试官不想在函数中看到数字怎么办哈哈哈。想一想想一想👽👽
不过确实如此呀兄弟们,那样的写法太low了,显得水平很低哎。总得写点高逼格的嘛。见代码
function randomNum(min,max){
var range=max-min
var rand=Math.random()
return min+Math.round(range*rand)
}
console.log(randomNum(20,50));
七.写一个事件委托
此题算是简简单单吧,但是又有点不简单,需要原生js基础相当扎实,那个判断说实话我是写不出来
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
var ul=document.getElementById('ul')
ul.onclick=function(event){
var target=event.target
if(target.nodeName==='LI'){
console.log(target);
alert(target.innerHTML)
}
}
</script>
八.写一个函数可以返回参数的具体数据类型
此题的考点在typeof的使用,
该方法对于基本类型除了null,都可以返回正确的类型(null会返回object)
对于引用类型都会返回object,除了function会返回function
此题对于引用数据类型的判断可以使用instanceof来解决,更加的简单。在后面的文章中我会出一篇来专门解释typeof于instanceof的区别。
function getType(target){
var ty=null
if(typeof target=='object'){
//此处使用了短路表达式
Object.prototype.toString.call(target)==='[object Object]'&&(ty='Object')
Object.prototype.toString.call(target)==='[object Array]'&&(ty='Array')
}else{
typeof target === 'string' && (ty='string')
typeof target === 'number' && (ty='number')
typeof target === 'boolean' && (ty='boolean')
typeof target === 'undefined' && (ty='undefined')
typeof target === 'function' && (ty='function')
}
return ty
}
console.log(getType(function fn(){}));
console.log(getType(1));
console.log(getType('sss'));
console.log(getType(undefined));
console.log(getType(true));
console.log(getType([1,2,3]));
console.log(getType({a:1,b:2}));
九.写一个函数来计算参数的和
此题难么?不难,但是想要写好并不简单,在于你是否能想到其他的特殊情况。
考点一个是Number的类型转换,一个是出现NaN
1.使用循环
function getSum(){
var length=arguments.length
var s=0
for(var i=0;i<length;i++){
//判断是否是NaN,不是的话进行加法
if(!isNaN(arguments[i])){
//将参数都转换为number类型
s+=Number(arguments[i])
}
}
return s
}
console.log(getSum('1',2,3,NaN));
2.使用reduce
- prev:表示上一次调用回调时的返回值,或者初始值init
- cur:表示当前正在处理的数组元素
- index:表示正在处理的数组元素的索引,若提供init值,则索引为0,否则索引为1
关于reduce的使用我会在之后的文章中来专门说明,大家莫急🔥🔥在赶了
var arr=[1,2,3,4]
var init=1
var sum=arr.reduce((pre,cur,index)=>{
return pre+cur
})
console.log(sum);
十.每隔1s打印当前时间,格式为YYYY-MM-DD hh:mm:ss
此题还是重在考察js基础,需要注意的是月份的+1,以及天数是getDate,而不是getDay
setInterval(()=>{
console.log(timer());
},1000)
function timer(){
var date=new Date()
var year=date.getFullYear()
var month=(date.getMonth()+1).toString().padStart(2,"0")
var day=date.getDate().toString().padStart(2,"0")
var hour=date.getHours().toString().padStart(2,"0")
var minute=date.getMinutes().toString().padStart(2,"0")
var s=date.getSeconds().toString().padStart(2,"0")
return `${year}-${month}-${day} ${hour}:${minute}:${s}`
}
十一.能否使用某种方式将下面的语句使用展开运算符而不导致类型错误
let obj={x:1,y:2,z:3}
console.log(...obj)
此题作为国庆压轴题自然要更有趣有深度一点,其主要考点为迭代器和reflect的使用
- 能否使用展开运算符在于其是否有迭代器(看xxx[Symbol.iterator]是否存在)
- keys的获取使用Reflect.ownKeys而不是Object.keys。因为如果对象里有Symbol类型的话Object.keys是获取不到的。知道Reflect.ownKeys就是你以后装逼的地方了😈在面试中能写出这个肯定会加分的
let obj={x:1,y:2,z:3}
obj[Symbol.iterator]=function(){
return {
next:function(){
let objArr=Reflect.ownKeys(obj)
if(this.index<objArr.length-1){
let key=objArr[this.index]
this.index++
return {value:obj[key]}
}else{
return {done:true}
}
},
index:0
}
}
console.log(...obj);