Js面试题分享
1. 数组去重(11组方法)
利用includes
function newArr(arr) {
var array = [];
for (var i = 0; i < arr.length; i++) {
if (!array.includes(arr[i])) { //includes 检测数组是否有某个值
array.push(arr[i]);
}
}
return array
}
Es6 利用Set方法去重(Es6中最常用)
我们可以利用Set的特性:对象存储的值总是唯一的来实现数组去重(其中一种作用)
function unique(arr) {
console.log(new Set(arr));
return Array.from(new Set(arr))
}
console.log(unique(arr))
利用for嵌套for,然后splice去重(ES5中最常用)
function unique(arr) {
for (var i = 0; i < arr.length; i++) {
for (var j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j]) { //如果第一个等同于第二个,splice方法删除第二个
arr.splice(j, 1);
j--;
}
}
}
return arr;
}
console.log(unique(arr))
利用indexOf去重
这个方法和第一个includes的做法差不多,就只有使用的方法不一样
function unique(arr) {
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array.indexOf(arr[i]) === -1) {
array.push(arr[i])
}
}
return array;
}
console.log(unique(arr))
利用Sort 排序去重
function unique(arr) {
arr = arr.sort()
var arrry = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i - 1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
console.log(unique(arr))
利用hasOwnProperty
利用hasOwnProperty 判断是否存在对象属性
function unique(arr) {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
console.log(unique(arr))
利用filter
function unique(arr) {
return arr.filter(function(item, index, arr) {
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index;
});
}
console.log(unique(arr))
利用递归去重
function unique(arr) {
var array= arr;
var len = array.length;
array.sort(function(a,b){ //排序后更加方便去重
return a - b;
})
function loop(index){
if(index >= 1){
if(array[index] === array[index-1]){
array.splice(index,1);
}
loop(index - 1); //递归loop,然后数组去重
}
}
loop(len-1);
return array;
}
console.log(unique(arr))
利用Map数据结构去重
function arrayNonRepeatfy(arr) {
let map = new Map();
let array = new Array(); // 数组用于返回结果
for (let i = 0; i < arr.length; i++) {
if(map .has(arr[i])) { // 如果有该key值
map .set(arr[i], true);
} else {
map .set(arr[i], false); // 如果没有该key值
array .push(arr[i]);
}
}
return array ;
}
console.log(unique(arr))
利用reduce + includes去重
function unique(arr){
return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
console.log(unique(arr));
[...new Set(arr)]
[...new Set(arr)]
2.随机数排序
用js实现随机选取10~100之间的10个数字,存入一个数组,按从小到大排序
function getRandom(min, max, total) {
let arr = []
for (let i = 0; i < total; i++) {
// 循环total次,将生成的随机数加入arr
arr.push((Math.floor(Math.random() * (max - min + 1) + min)))
}
// 去重
let arr2 = Array.from(new Set(arr))
// 保证数字有10个
if (arr2.length <= 9) {
arr2 = getRandom(min, max, total)
return arr2
} else {
return arr2
}
}
let newArr = getRandom(10, 100, 10)
// sort排序
newArr.sort((a, b) => {
return a - b
})
console.log(newArr);
3.字符串翻转(2种方式)
请自定义一个函数,实现字符串的反转
方法1:
let str = 'lajsdkljkjelka'
function Fan(string) {
return string.split('').reverse().join('')
}
var str2 = Fan(str)
console.log(str2);
方法2:
function revStr(str){
// 容器
var reStr = ""
// 排序
for(let i = str.length - 1 ; i >= 0 ; i--){
// 将字符串从后以此赋值 charAt()
reStr += str.charAt(i)
}
return reStr
}
let str = 'lajsdkljkjelka'
console.log(revStr(str2));
4.斐波那契数列(递归与不递归)
不递归:
function fn(total){
let a = 1 , b = 1 , c = 0
for(let i = 1 ; i <= total ; i++){
// 判断是否是前两项
if(total <= 2){
c = 1
}else{
// 操作 a,b 的值换成新值
a = b
b = c
c = a + b
}
}
return c
}
let res = fn(3)
console.log(res);
递归:
function fn(n){
if(n==1 || n==2){
return 1;
}else {
return fn(n-1)+fn(n-2);
}
}
5. 统计次数
(注:用面向对象的方式实现,用for循环进行排序)
[1, 4, 2, 1, 3, 2, 1, 4] 作为参数(参数可变)传入js方法中,控制台输出如下结果
1 出现了 3 次
2 出现了 2 次
4 出现了 2 次
3 出现了 1 次
解决:
let newArr = [2,2,1,4,3,2,2,1]
function fn(arr){
let obj = {}
arr.forEach(e=>{
if(obj[e]){
obj[e]++
}else{
obj[e] = 1
}
})
let newArr = []
for(let key in obj){
let obj2 = {num:key , const : obj[key]}
newArr.push(obj2)
}
newArr.sort((a,b)=>{
return b.const-a.const
})
console.log(newArr);
for(let k in obj){
console.log(`${k} 出现了 ${obj[k]} 次`);
}
}
fn(newArr)
6.二维数组行转列(两种方式)
实现效果:
let arr = [
['前端','3人','8-15k','本科'],
['后端','5人','10-25k','研究生'],
['UI','2人','9-11k','大专'],
['ETL工程师','10人','6-12k','大专'],
];
//转换 =>
let newArr = [
['前端','后端','UI','ETL工程师'],
['3人','5人','2人','10人'],
['8-15k','10-25k','9-11k','6-12k'],
['本科','研究生','大专','大专'],
];
方法1:
let arr = [
['前端','3人','8-15k','本科'],
['后端','5人','10-25k','研究生'],
['UI','2人','9-11k','大专'],
['ETL工程师','10人','6-12k','大专'],
];
let newArr = [];
// 遍历行 arr[0]
for (let i = 0; i < arr[0].length; i++) {
// 列的初始化
newArr[i] = [];
// 列转行
for (let j = 0; j < arr.length; j++) {
// 预期数据类型:
// [
// ["前端", "后端", "UI", "ETL工程师"]
// []
// []
// []
// ]
// 4. 列数据 塞进 行内
newArr[i][j]= arr[j][i];
}
}
console.log(newArr);
方法2:
let arr = [
['前端','3人','8-15k','本科'],
['后端','5人','10-25k','研究生'],
['UI','2人','9-11k','大专'],
['ETL工程师','10人','6-12k','大专'],
];
let newArr = arr[0].map((h,i)=>arr.map(l => l[i]))
// 或者是:
let newArr = arr[0].map((col, index) => {
// 这个return 类似于 newArr[i] = [];
return arr.map(row=>{
// 这里return 类似于 ["前端", "后端", "UI", "ETL工程师"]
return row[index];
})
})
7. 对象转数组(3种方法)
需求: 请把下列的数组变成是: [['苹果','胡萝卜', '花生'], ['梨', '西芹', '坚果']....]
var basket = [
{ fruit: "苹果", veg: "胡萝卜", nut: "花生" },
{ fruit: "梨", veg: "西芹", nut: "坚果" },
{ fruit: "香蕉", veg: "土豆", nut: "杏仁" },
{ fruit: "西瓜", veg: "豆芽", nut: "核桃" }
];
方法1:
var newArr = [];
basket.forEach((item,index)=>{
// console.log(item);
// 初始化 二维数组
// 预期数据结构 [[],[],[],[]]
newArr.push([]);
// 3. 对象遍历
for(let key in item){
newArr[index].push(item[key])
}
})
console.log(newArr);
方法2:
var newArr = [];
basket.forEach(item=>{
// console.log(Object.values(item));
// 对象转数组 之后 push 进新数组
newArr.push(Object.values(item))
})
console.log(newArr);
方法3:
var newArr = basket.map(item=>{
return Object.values(item);
})
console.log(newArr);
8. 实现 add(1)(2)(3)
function add (...args) {
//求和
return args.reduce((a, b) => a + b)
}
function currying (fn) {
let args = []
return function temp (...newArgs) {
if (newArgs.length) {
args = [
...args,
...newArgs
]
return temp
} else {
let val = fn.apply(this, args)
args = [] //保证再次调用时清空
return val
}
}
}
let addCurry = currying(add)
console.log(addCurry(1)(2)(3)(4, 5)()) //15
console.log(addCurry(1)(2)(3, 4, 5)()) //15
console.log(addCurry(1)(2, 3, 4, 5)()) //15
9. 将数组扁平化并去除其中重复数据,最终得到一个升序且不重复的数组
Array.from(new Set(arr.flat(Infinity))).sort((a,b)=>{ return a-b})
10. 字符串出现频率最高的字母
let str = 'qwef433eht432qax543456uhgbvf32435465'
// 将字符串转换成数组
var arr = str.split('')
let obj = {};
arr.forEach(item => {
if (obj[item]) {
obj[item]++
} else {
obj[item] = 1
}
})
let arr1 = []
for (let key in obj) {
//对象 转 数组对象
let obj2 = {
num: key,
val: obj[key]
}
arr1.push(obj2)
}
arr1.sort((a, b) => {
return b.val - a.val
})
console.log(`字符串中${arr1[0].num}出现的最多,出现了${arr1[0].val}次`);
11. 如何判断一个对象是否为数组
function isArray(arg) {
if (typeof arg === 'object') {
return Object.prototype.toString.call(arg) === '[object Array]';
}
return false;
}
12. 冒泡排序
对数组 [5,3,9,4,6] , 进行降序排列
var arr = [5,3,9,4,6];
// 轮数
for(var i = 0;i<arr.length-1;i++){
// 次数
for(var j =i+1;j<arr.length;j++){
if(arr[i]<arr[j]){ // 如果是升序arr[i]>arr[j]
// 交换两个变量的值
[arr[i],arr[j]]=[arr[j],arr[i]]
}
}
}
console.log(arr);
13. 快速排序法(递归)
随机获取10到999之间的100个整数,并且要从大到小排序,要求使用快速排序算法
function arrSort(arr) {
// 递归的出口
if(arr.length<=1){
return arr;
}
// 取出中间数
var index = Math.floor(arr.length / 2);
// 需要取出中间数,并且改变原数组
// splice 数组删除常用 从index开始,删一个 返回删除项
var mid = arr.splice(index, 1)[0];
// 将原数组 分左右 (左大右小)
var left = [], right = [];
for (var i = 0; i < arr.length; i++) {
if(arr[i]<mid){
right.push(arr[i]);
}else{
left.push(arr[i]);
}
}
// concat方法 做数组合并
// 进入递归(left right)
return arrSort(left).concat(mid,arrSort(right));
}
console.log(arrSort(arr));
14. 浅拷贝
var p1 = {
name:"张三",
age:20,
favs:["吃饭","睡觉","钓鱼"],
wife:{
name:"翠花",
age:49,
favs:["爱马仕","迪奥","香奈儿"]
}
}
var p2 = {}; // 初始化
// 浅拷贝: 表层的一个复制
for(var key in p1){
p2[key] = p1[key];
}
15. 深拷贝
var p1 = {
name:"张三",
age:20,
favs:["吃饭","睡觉","钓鱼"],
wife:{
name:"翠花",
age:49,
favs:["爱马仕","迪奥","香奈儿"]
}
}
var p2 = {}; // 初始化
// 需要两个参数 cur p1 tar p2
function deepCopy(cur,tar){
for(var key in cur){
// 涉及到枚举性问题, 只需要复制实例成员
// key 的 实例成员的判断 (排除了原型成员里面可枚举的属性)
if(cur.hasOwnProperty(key)){
// 对象的value值类型判断
if(typeof cur[key] == "object"){
// 引用数据类型
// [] 和 {} 的判断
// Array.isArray(cur[key]) 用来判断是不是数组
tar[key]=Array.isArray(cur[key])?[]:{};
// 递归入口 实现深层次拷贝
deepCopy(cur[key],tar[key]);
}else{ // 出口
// 基本数据类型
// 浅拷贝
tar[key] = cur[key];
}
}
}
}
deepCopy(p1,p2);
p2.wife.favs[0] = "好再来";
console.log(p1,p2);
16. 不借助临时变量,进行两个整数的交换
let a = 2,
b = 3;
[b,a] = [a,b]
console.log(a,b) // 3 2
17. 如何把一个字符串的大小写取反(大写变小写,小写变大写),例如'AbC' 变成 'aBc'?
let str = 'aBc';
str = str.replace(/[a-zA-Z]/g, content => {
return content.toUpperCase() === content ? content.toLowerCase() : content.toUpperCase();
})
18. 请写出三种对象合并的方法
let arr1 = {
a:1,
b:2,
c:3
};
let arr2 = {
d:4,
e:5,
a:6
};
方法1: 拓展运算符,后面相同的属性覆盖前一个
let arr3={...arr1,...arr2};
//方法2: Object.assign(),后面相同的属性覆盖前一个
let arr3=Object.assign(arr1,arr2);
//方法3: Object.keys(),相同的属性只取第一个
Object.keys(arr1).forEach(key => {
arr2[key] = arr1[key]
})