细品六道JavaScript经典面试题,你品你也会!

前言

在面试的过程中,JS的八股文也是常问的考点,近期鄙人也是在学习八股文,这里就详细分析几道JS的面试题给大家,希望对大家有帮助!

正文

js中数组的常用的API

当被问到JS中数组常用的API,这个我们可以从API的功能上下手.因为数组我们可以进行添加数据,也可以修改,删除等等操作,所以我们也可以从以下几个方面进行说明

scss 复制代码
  push():从尾部插入
  unshift():从头部插入
  splice():指定位置插入
  concat():元素拼接

这里就重点讲一下splice()以及concat()
splice()可以接收三个参数,第一个参数表示下标开始,第二个元素表示要删除几个元素,第三个参数表示要插入的元素。

scss 复制代码
let arr = [1,2,3,4,5,6]

arr.splice(3,0,0)//第一个下标是从哪里插入 第二个参数是删除几个元素,第三个是插入的数据

console.log(arr);

这里arr.splice(3,0,0)表示就是,从下标为3开始,删除0个元素,插入一个元素0,我们看看打印结果

在下标为3的位置,我们确实插入了一个0.
concat()拼接会将一个数组,拼接到一个另一数组后面,并返回一个新数组。这么说可能有点绕,我们就看代码讲

ini 复制代码
let arr = [1,2,3,4]
let arr2 = []

let arr3 = arr2.concat(arr)
console.log(arr,'11111');
console.log(arr2,'222222');
console.log(arr3,'333333');

这里我们将数组arr拼接到arr2后面,并赋值给arr3,我们来看看打印结果会是什么

打印结果表示arr1,arr2并没有被修改,所以concat()是将数组拼接完之后返回一个新的数组,不会修改原数据。

scss 复制代码
 pop():删除数组最后一个元素
 shift():删除数组第一元素
 slice():剪切返回一个新数组
 splice():指定位置删除

删除方法我们着重讲一下slice()

javascript 复制代码
let arr = [1,2,3,4,5,6]
let newArr = arr.slice(2,4)
console.log(arr,'-----');

console.log(newArr,'======');

slice()可以接收两个参数,第一表示从哪里开始剪切,第二个参数表示到哪里截止。注意哦,这是左闭右开的方法,可以取到开始剪切位置的元素,不会取到截止位置的元素.这个方法会将需要剪切的部分剪切下来,然后返回一个新的数组,不会影响原数组。

scss 复制代码
indexOf():查找元素,存在返回下标
includes();查找元素,存在返回true否则false
lastIndexOf():从右边开始查找
find():遍历数组,会返回在一定条件下,符合条件的第一个元素

关于查找,我们就讲讲相对来说用的比较少的find,find((val,i arr)=>{return})接收一个回调函数,函数接收三个参数,值,下标,原数组。

javascript 复制代码
let arr = [1,2,3,4,5,6]
const res = arr.find((val,i,arr)=>{
    return val > 3
})

console.log(res);

这里我们的条件就会值大于3,从第一个值开始判断,第一个符合条件的值是4对吧,所以这里res的值就会是4

迭代
scss 复制代码
forEach()
map()
reduce()
every()
some()
filter()

啊哈,到了迭代,是不是发现很多没见过的'陌生人'?害,没事的,作者我第一次看到也是内心有句话不知当不当讲,但是肯定是不敢讲的。
refuce()的是一个比较特殊的遍历方法,接收一个回调函数,一个初始默认值

javascript 复制代码
let sum = arr.reduce((pre,item,i,arr)=>{
    return pre + item
},0)

这里初始默认值是给pre的,然后这里return pre + item会把值返回给下一次的pre,也可以这么理解,数组里面的值求和,每一次我们遍历到一个元素,就会做一次求和的操作。

ini 复制代码
let arr = [1,2,3,4,5,6]
let sum = 0
for(let i = 0;i<arr.length;i++){
    sum = sum + arr[i]
}

这里的sum就跟pre差不多。事实上,reduce()就是可以用于数组求和
every()用于判断整个数组中的元素,是否全部符合条件,全部符合,就返回true

javascript 复制代码
let arr = [1,2,3,4,5,6]
let res = arr.every((val,i,arr)=>{
    return val < 10
})
console.log(res);

some()则是相反,只要存在部分(包括一个)符合条件,就会返回true

ini 复制代码
let arr = [1,2,3,4,5,6]
let res = arr.some((val,i,arr)=>{//判断是否存在一项满足条件 满足返回true 不满足返回false
    return val > 5
})
console.log(res);

filter()过滤器,返回满足条件的数组 返回一个新数组

ini 复制代码
let arr = [1,2,3,4,5,6]
let newArr = arr.filter((val,i,arr)=>{
    return val %2 === 0
})
其他
scss 复制代码
join():数组变成字符串
reverse():反转数组
sort():数组排序
toReversed():拿着原数组,创建一个新数组

这里的toReversed()也是会创建一个新的数组返回给变量的

js中字符串的常用的API

在js中字符串身上的API和数组其实非常的像,基本雷同

scss 复制代码
  '+':使用加号
  concat():拼接
删除
scss 复制代码
  substring(),slice(),substr():三个都是剪切,用法都是一直的左闭右开
scss 复制代码
  replace():替换
  trim():去除两端的空格
  trimLeft(),trimRight():去除左右空格
  toUpperCase():转换成大写
  toLowerCase():转换成小写
  padStart():从头部开始填充
  padEnd():从尾部开始填充
  

padStart()padEnd()的用法是一致的,都是填充。比如现有两个数num1 = 12345679 num2=123我们要让这两个数对位相加,但是num2的长度不够,我们就可以采取填充让他们对齐

ini 复制代码
let str1 = '123456789'
let str2 = '123'
console.log(str1);
console.log(str2.padStart(9,'0'));

这样我们可以看到str2.padStart(9,'0')也会是9

scss 复制代码
charAt():第几个字符,其实也就是str[i]
startWidth():是否以xxx(API里面接收的参数)开头
endWidth():是否以xxx结尾
indexOf()
includes()
lastIndexOf()
match():正则匹配,匹配到了返回一个数组,没有返回null
search():正则匹配,匹配到了返回下标,没有返回-1

我们来看看,这比较少用到的match()以及search()

ini 复制代码
let str = 'abcd'
let res = str.match(/ab/)
console.log(res);

返回起始下标给我们,以及input从哪个字符串匹配查找

search()则是会返回下标,没有找到就会返回-1

ini 复制代码
let str = 'abcd'
let res = str.search(/abd/)
console.log(res);
其他
scss 复制代码
split():将字符串变成数组

谈谈js中的类型转换机制

基本数据类型(Primitive Types)
javascript 复制代码
Number - 用于表示整数和浮点数
String - 用于表示文本
Boolean - 用于表示逻辑值,只有两个可能的值:true 和 false
Undefined - 表示尚未赋值的变量或对象属性
Null - 表示一个空的值或者对象引用
Symbol - 引入于 ES6 (ECMAScript 2015),用于创建唯一的键标识符。
BigInt - 引入于 ES10 (ECMAScript 2019),用于表示任意精度的大整数
复合数据类型(Complex Types)
javascript 复制代码
Object - 对象是键值对的集合,可以包含任何类型的数据
Array - 数组是一种特殊的对象,用于存储多个值。
Function - 函数也是对象的一种,可以被调用执行一段代码。
Date 日期
RegExp 正则表达式

介绍

Js中有七种原始类型,和引用类型之分,在开发过程中有时需要我们人为的将一个变量的类型转换为其他类型,<这种称之为类型转换,转换分为显示转换和隐式转换。

方式

scss 复制代码
1.显示:NUmber() String() Boolean() parseInt()
2.隐式:四则运算 if() 比较运算

下面我们看一道例题判断[] == ![],我们来分析一下,首先!的优先级会比较高,右边就会发生隐式类型转换,首先[]是一个对象,任何对象转换成布尔值都是true,那么式子就会变[] == false,我们一般来说比较运算符一般都是使用数字比较,false转换成数字就是0,左边也是需要转换的,但是引用类型转换成Number类型首先会调用ToNumber([]),再ToPrimitive([],Number),这里会先执行valueof() 只能转换包装类对象 []不是包装类,就返回执行toString(),变成一个空字符串,空字符串转换成Number类型,就会转化成0.所以答案是true.你答对了吗?

== VS ===

== 值相等 不在乎类型 V8会发生隐式类型转换

=== 值和类型都相等 V8不会发生隐式类型转换

聊聊js中拷贝问题

是什么?

xml 复制代码
开发中经常需要面对一个要根据原对象得到一个新对象的场景,这种场景我们称之为拷贝<br>

特点

  1. 浅拷贝:得到的新对象受原对象修改的影响 浅拷贝会复制对象的第一层属性,但对于对象中的引用类型(如数组、对象等),它只会复制这些引用类型的引用,而不是其实际的内容。这意味着如果原始对象和拷贝对象中的引用类型指向同一个内存地址,那么对其中一个对象的修改会影响到另一个对象。
  2. 深拷贝:得到的新对象不受原对象修改的影响 深拷贝会递归地复制对象的所有层级,包括所有的引用类型属性,确保拷贝的对象和原始对象之间没有共享的引用。这意味着修改拷贝对象不会影响到原始对象,反之亦然。

方法:

typescript 复制代码
        浅拷贝:Object.create Object.assign {...Object}
        Array.concat Array.slice() Array.toReversed.reverser [...Array]
        
        
        深拷贝:JSON.parse(JSON.stringify(obj))
        无法处理 bigint Symbol undefined 类型 无法处理循环引用
        structuredClone() 无法拷贝函数 Symbol
        管道通信 MessageChannel()
        递归拷贝

这里我们介绍两种少见的方式实现深拷贝 管道通信 MessageChannel()

javascript 复制代码
const obj = {
    a: 1,
    b: {
      n: 2
    }
  }
  
  function deepClone(obj) {
    return new Promise((resolve) => {
      const { port1, port2 } = new MessageChannel();
      port1.postMessage(obj)
      port2.onmessage = (msg) => {
        resolve(msg.data)
      }
    })
  }
  
  deepClone(obj).then(res => {
    obj.b.n = 20
    
    console.log(res, '---');
  })

new MessageChannel()中,我们解构出两个端口port1port2这里由port1发送信息,由port2接收信息,我们将obj作为信息传给port2,然后obj会被传入在port2.onmessage()的回调函数的参数msg.data中,这里由于这个方法时一个异步方法,我们需要使用Promise处理

第二种就是递归拷贝

vbnet 复制代码
const obj = {
    a: 1,
    b: {
      n: 2
    }
  }
  
  function deepClone(obj) {
    const newObj = {}
    for(let key in obj){
        if(obj.hasOwnProperty(key)){
            if(typeof obj[key] === 'object' && obj[key] !== null){
                newObj[key] = deepClone(obj[key])
            }else{
                newObj[key] = obj[key]
            }
        }
    }

    return newObj
  }
  
const obj2 = deepClone(obj);

hasOwnProperty()可以保证我们拷贝的值,不是隐式原型上的数据。当我们遇见要拷贝值本身也会是一个引用数据时,我们也要保证我们使用的typeof判断出来的值,不会是一个NaN.是个引用类型数据的话,我们就继续调用这个函数。

说说闭包

是什么?

在js中根据词法作用域的规则,内部函数可以访问外部函数的变量。当内部函数被拿到外部调用时,即使外部函数已经执行完毕,内部函数对外部函数的变量访问依旧存在引用,那这些被引用的变量就会以一个集合的形式保存在内存中,这种集合就是闭包。

优缺点

1.内存泄漏

2.定义私有变量,防止全局变量污染,便于封装模块

应用场景

1.防抖节流

2.单例模式 做了一个全局弹出框

3.柯里化 把一个接受多个参数的函数,变成多个接受一个参数的函数

希望这几道题会帮助到你,感谢大家阅读!!!

相关推荐
dr李四维4 分钟前
iOS构建版本以及Hbuilder打iOS的ipa包全流程
前端·笔记·ios·产品运营·产品经理·xcode
ifanatic4 分钟前
[面试]-golang基础面试题总结
面试·职场和发展·golang
I_Am_Me_18 分钟前
【JavaEE进阶】 JavaScript
开发语言·javascript·ecmascript
雯0609~25 分钟前
网页F12:缓存的使用(设值、取值、删除)
前端·缓存
℘团子এ28 分钟前
vue3中如何上传文件到腾讯云的桶(cosbrowser)
前端·javascript·腾讯云
学习前端的小z33 分钟前
【前端】深入理解 JavaScript 逻辑运算符的优先级与短路求值机制
开发语言·前端·javascript
程序猿进阶1 小时前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
前端百草阁1 小时前
【TS简单上手,快速入门教程】————适合零基础
javascript·typescript
彭世瑜1 小时前
ts: TypeScript跳过检查/忽略类型检查
前端·javascript·typescript
FØund4041 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html