热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

综合面试题js深入版

综合面试题-js深入版数组扁平化一维数组:数组中只有一级二维数组:数组中有两级多维数组:数组中有两级及以上变成一维数组的操作——扁平化fl

综合面试题-js深入版

  1. 数组扁平化

一维数组:数组中只有一级

二维数组:数组中有两级

多维数组:数组中有两级及以上

变成一维数组的操作——扁平化

  1. flat

es6中新增的方法

ps.不知道的api找mdn

去重

  1. 对象键值对

  2. 新开一个数组 for循环 indexOf includes来判断

  3. new Set来去重

  4. ……

经典算法

  1. toString

思路:将数组变为字符串

toString是会把一个数组直接变为一个字符串字符串里绝对不会出现中括号[],而把每项用逗号, 分隔

toString会自动扁平化,以逗号连接

这里扩展一下Object.prototype.toString.call({name:'angela',age:18})

Object.prototype.toString() - Javascript | MDN

join也是一样的

ps.map改变每项的值,返回啥就改成啥

  1. JSON.stringify

stringify和toString的区别在于 stringify是有中括号的

let arr=[1,2,[3,8],[35,87,[26,9]]]
let arr1=[{name:'angela',age:18},{name:'tom',age:18}]
// 1.flat方法
console.log('1.flat方法--------------------')
console.log(arr.flat(Infinity));
// 2.toString和join
console.log('2.toString和join--------------------')
console.log(arr.toString().split(',').map(i=>Number(i)));
console.log(arr.join().split(',').map(i=>Number(i))); // join同toString是一样
console.log(arr1.flat(Infinity));
console.log(arr1.toString().split(',')); // 有局限的
console.log(arr.join('|').split(/,|\|/g)); // 有局限的
// 3.JSON.stringify
console.log('3.JSON.stringify--------------------')
console.log(JSON.stringify(arr).replace(/\[|\]/g,'').split(','))
console.log(JSON.stringify(arr1).replace(/\[|\]/g,''));

  1. concat(...array)

前言:

用函数制定一个规则,检测数组中的某一项是否符合这个规则

some做检测

ps.forEach map some find

Array.isArray手动改原型链依然判为false 检测数据类型

...arr:每次只展开一级,展开不了很深

// 4.concat(...arr)
console.log('4.concat(...arr)--------------------')
console.log([].concat(...arr))
while(arr.some(i=>Array.isArray(i))){
arr=[].concat(...arr)
}
console.log(arr);

  1. 递归处理

递归思路:

fn执行的时候又调了自己

循环当前这个数组的每一项:

  • 不是数组,创建一个新数组存起来

  • 当前是数组,再调这个方法(先不管这个),重新进来

// res在外面
let res=[]
function deep(arr){
for(let i=0;i
if(arr[i] instanceof Array){
deep(arr[i]);
continue;
}
res.push(arr[i])
}
}let arr=[1,2,[3,8],[35,87,[26,9]]]
deep(arr);
console.log(res);
// res放在里面
function myFlatter(arr){
let res=[]
arr.forEach(i=>{
if(Array.isArray(i)){
res=res.concat(myFlatter(i))
}else{
res.push(i)
}
})
return res;
}
res=myFlatter(arr);
console.log(res);
function flatter(arr){
return arr.reduce((total,i)=>{
// if(Array.isArray(i)){
// total=total.concat(flatter(i));
// }else{
// total.push(i)
// }
// return total;
return Array.isArray(i)?total.concat(flatter(i)):[...total,i]
},[])
}
res=flatter(arr);
console.log(res);

Javascript数组扁平化的五种方式_二九君的博客-CSDN博客_Javascript数组扁平化

【Javascript】实现数组扁平化_程序媛小y的博客-CSDN博客_js数组扁平化处理

  1. _new方法

作为构造函数执行的步骤:

扩展一下Object.create

+创建一个空对象

+该对象的__proto__指向你传的参数(它所属构造函数的实例)。合理下传入的应该是一个原型对象proto,那么创建出来的空对象就是proto所属构造函数(该proto的constructor指向)的实例。

这里有一点绕口令:

Fn.prototype属于哪个构造函数的原型?Fn

function Dog(name){
this.name=name;
}
Dog.prototype.bark=function(){
console.log('wang wang')
}
Dog.prototype.sayName=function(){
console.log('my name is' + this.name);
}let sanmao=new Dog('sanmao');
console.dir(sanmao);// function _new(Dog,name){
// const obj={};
// obj.name=name;
// obj.__proto__=Dog.prototype;
// return obj;
// }
function _new(Fn,...args){
// let obj={}
// obj.__proto__=Fn.prototype;
let obj=Object.create(Fn.prototype);
Fn.call(obj,...args);
return obj;
}
sanmao=_new(Dog,'liumao')
console.dir(sanmao);

  1. 数组合并?题意本身不是很明确

数组合并concat

(function(){
let arr1=['A1','A2','B1','B2','C1','C2','D1','D2']
let arr2=['A','B','C','D'] let arr=[]
for(let i=0;i
if(arr1[i][0]
let alpha=arr2.find(item=>item===arr1[i][0])
alpha?arr.push(arr2.shift()):null;
continue;
}
arr.push(arr1[i]) } if(arr2.length){
// 如果原来数组是乱序的这里还得改一下
arr=arr.concat(arr2);
} console.log(arr);
console.log(arr1);
console.log(arr2);
})()function method2(){
let arr1=['A1','A2','B1','B2','C1','C2','D1','D2']
let arr2=['A','B','C','D'] let arr=[]
arr2.forEach((alpha)=>{
let index=arr1.findLastIndex(i=>i[0]===alpha)
arr1.splice(index+1,0,alpha);
})
console.log(arr);
console.log(arr1);
console.log(arr2);
}
method2();

  1. 闭包

let形成块级作用域

let形成块级作用域。当前i的值存在当前块级作用域里,定时器回调触发的时候找的i是当前块级作用域中的i

大闭包

  1. 循环体里面整个是一个大函数,保存变量i

for(var i=0;i<10;i++){
(function(i){
// i为参数
setTimeout(()=>{
console.log(i)
},1000)
})(i)}

把回调处理成闭包*

  1. 另一种思路是在setTimeout的回调做文章,这里也是一个函数

for(var i=0;i<10;i++){
// setTimeout((function(i){
// return ()=>console.log(i)
// })(i),1000)
// return一个function是在这里做文章
setTimeout(((i)=>()=>console.log(i))(i),1000)}
function timer(){
return i=>{
setTimeout(()=>console.log(i),1000)
}
}

  • 思路一样,使用bind

for(var i=0;i<10;i++){
var fn=function(i){
console.log(i)
}
setTimeout(fn.bind(null,i),1000)}

  1. 匿名函数

匿名函数如果设置了函数名

  1. 外面反而不能用,里面是能用的

  2. 里面AAA就相当于是一个const变量,

  • 你改这个值是没有效果的,但是它不会报错(非strict)

  • 但是你前面加了var,本身这个函数名就失效了

设置了名字带来的问题:

外面不能用,里面用了还不能改

当一个变量前没有var let const,沿着上级作用域链查找

  1. a==1 & a==2 & a==3

    1. toString类型转换

两个等号叫比较

三个等号叫绝对比较

(一个等号叫赋值)

==:若数据类型不一样,先转换成一样的再进行比较

===:类型一样值也一样

var a={
i:0,
valueOf:function(){
this.i++;
console.log(this.i);
return this.i;
},
[Symbol.toPrimitive]:function(){
return ++this.i;
}
}
console.log(a==1)

这道题思路:

number类型不可能,bool也不行,字符串……

Array.prototype.toString 以逗号连接数组中的每一项

Object.prototype.toString 用来检测数据类型的

所属类原型上的方法

  1. Object.defineProperty

对某个属性的描述,设置某个属性的相关特征

参数:对象 键 描述符

获取这个属性的时候,就会走get函数

// 简单版
let n=0;
Object.defineProperty(window,&#39;a&#39;,{
get(){
return ++n;
}
})
if(a==1 && a==2 & a==3){
console.log(&#39;OK&#39;)
}


Object.defineProperty(window,&#39;a&#39;,{
get(){
// 这时的this代表这个属性
this.value?this.value++:this.value=1;
return this.value;
}
})
if(a==1 && a==2 & a==3){
console.log(&#39;OK&#39;)
}

  1. Array.prototype.push原理

  1. 数组经典排序算法

  1. 冒泡排序

冒泡:越大的气泡越在上。

当前项和后一项进行比较,最大的排在后面

动图效果:

1662627592813.mp4

引申一下:交换

外层循环控制比较的轮数,n个数我只需要比较n-1次,因为我只需要把n-1个数依次放到末尾;

内层循环控制每轮要比较的次数,

整体思路:

外循环控制多少轮,里层循环控制比较次数,不用跟自己比,做多length-1,然后减掉末尾的数;

  1. 插入排序

将抓入的牌依次和手里的牌进行比较;

从后往前看,手上的牌小了,就往前挪;大了就插过去

let arr=[9,16,28,18,98,63,3];
for(let i=1;i
// arr[i]:要插入的元素
let insert=arr[i]
let j=i-1;
for(;j>=0;j--){
// 插入的数大于(等于)比较的元素 j+1
if(insert>=arr[j]){
// j+1 -> i-1 往后挪
for(let p=i-1;p>=j+1;p--){
arr[p+1]=arr[p];
}
arr[j+1]=insert;
break;
}
}
// 出循环没插入
if(j<0){
// 0 -> i-1 往后挪
for(let p=i-1;p>=0;p--){
arr[p+1]=arr[p];
}
arr[0]=insert;
}
}
console.log(arr);

let arr=[9,16,28,18,98,63,3];
for(let i=1;i
// arr[i]:要插入的元素
let insert=arr[i]
let j=i-1;
for(;j>=0;j--){
// 插入的数大于(等于)比较的元素 j+1
if(insert>=arr[j]){
// 用splice一定要先删除再插入// 这里删除的位置一定大于插入的位置,所以不会产生数组塌陷
arr.splice(i,1);
arr.splice(j+1,0,insert)
break;
}
}
// 出循环没插入
if(j<0){
// 用splice一定要先删除再插入
arr.splice(i,1);
arr.splice(0,0,insert)
}
}
console.log(arr);

或者就像视频中新开一个数组,视频中的方法是新开一个数组

https://www.jianshu.com/p/bd0ed19bc158

Javascript插入排序 - 帕图纳克斯 - 博客园

js 实现排序算法 -- 插入排序(Insertion Sort)

网上很多是这样:

let arr=[9,16,28,18,98,63,3];
for(let i=1;i
// arr[i]:要插入的元素
let insert=arr[i]
let j=i-1;
while(j>=0 && insert
arr[j+1]=arr[j];
j--;
}
arr[j+1]=insert; }
console.log(arr);

自己总结:

插入排序其实就是抓牌,将新的牌与手中已有的牌进行比较,从后往前比,当新的牌大于(等于)当前比较的元素时,这个时候插入进去。

所以代码上是:

首先取0号位置作为已排序数组,所以外层循环从1号位置开始循环,i=1;i

从后往前扫描,j=i-1;并且用一个变量temp保存这张新牌即arr[i],从后往前扫描的同时元素依次往后挪,边比较边往后挪,内层循环的条件是 while j>=0 && temp

  1. 快速排序

思路:

let arr=[18,24,56,90,3,7,65]
function quick(arr){
let i=Math.floor(arr.length/2);
let middle=arr[i];
arr.splice(i,0);
let left=[],right=[];
arr.forEach(item=>{
if(item
if(item>=middle) right.push(item)
}) if(left.length>=1) left=quick(left);
if(right.length>=1) right=quick(right)
return left.concat(middle).concat(right)}console.log(quick(arr));

Javascript 实现快速排序 - 知乎

快速排序(Quicksort)的Javascript实现 - 阮一峰的网络日志

diff算法 阮一峰_Javascript实现十大排序算法_短腿胖胖小笨猪的博客-CSDN博客

自己总结:

首先在数组中选一个元素作为基准点,比如一般选中间值,比这个值小的都放到左边,比这个值大的都放到右边,然后分别对左边和右边依次递归,最后返回的是左中右的拼接。

    1. 递归

一门语言:

语法本身,设计模式,底层原理,框架,服务器部署,数据库;

这3个排序是入门级别的,二叉树&三叉树,

  1. 数组填充

let obj={
1:22,
2:333,
12:878,
}let arr=new Array(12).fill(null);
arr.forEach((i,index)=>{
obj[index+1]?arr[index]=obj[index+1]:null;
})
// 这里用map会更好
arr=new Array(12).fill(null).map((_,index)=>{
return obj[index+1] || null;
})
console.log(arr);

map改变之前的值

let obj={
1:22,
2:333,
12:878,
}obj.length=13;
arr=Array.from(obj).slice(1).map(i => i || null)
console.log(arr);

  1. 求交集

注意一下重复元素的情况

let arr1=[1,2,2,76,39,22];
let arr2=[2,39,67,36];
let arr=arr1.reduce((total,item)=>{let index=arr2.indexOf(item)if(index>-1){
arr2.splice(index,1)
total.push(item);}return total;
},[])
console.log(arr);

思考题:交差并补

  1. 旋转数组(其实就是将数组平移k个位置)

k写几就是把最后几位放前面

方法一:slice支持负数作为索引

方法二:splice返回删除的数组

方法三:pop unshift

数组切割再拼接

let arr=[1,2,3,4,5,6,7,8]
function rotate(arr,k){
let length=arr.length;
k=k%length;
arr=arr.map((value,index)=>{
return {
value,
index:(index+k)%length
}
})
arr.sort((a,b)=>{
return a.index-b.index;
})
arr=arr.map(i=>(i.value))
return arr;}arr=rotate(arr,3);
console.log(arr);

  1. 函数柯理化

比较简单的做法,这样也行

function add(n1,n2,n3){return n1+n2+n3;
}
function currying(...args){if(args.length>=3){return add(...args)}return (...arg)=>{return currying(...args,...arg);}
}
console.log(currying(1,2)(3))
console.log(currying(1)(2,3))
console.log(currying(1)(2)(3))
console.log(currying(1,2,3))

call & apply & bind 与柯理化



推荐阅读
  • 本文探讨了利用JavaScript实现集合的对称差集算法的方法。该算法旨在处理多个数组作为输入参数,同时保留每个数组中元素的原始顺序。算法不会移除单个数组内的重复元素,但会删除在不同数组之间出现的重复项。通过这种方式,能够有效地计算出多个数组的对称差集。 ... [详细]
  • 本文将继续探讨 JavaScript 函数式编程的高级技巧及其实际应用。通过一个具体的寻路算法示例,我们将深入分析如何利用函数式编程的思想解决复杂问题。示例中,节点之间的连线代表路径,连线上的数字表示两点间的距离。我们将详细讲解如何通过递归和高阶函数等技术实现高效的寻路算法。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • C++ 异步编程中获取线程执行结果的方法与技巧及其在前端开发中的应用探讨
    本文探讨了C++异步编程中获取线程执行结果的方法与技巧,并深入分析了这些技术在前端开发中的应用。通过对比不同的异步编程模型,本文详细介绍了如何高效地处理多线程任务,确保程序的稳定性和性能。同时,文章还结合实际案例,展示了这些方法在前端异步编程中的具体实现和优化策略。 ... [详细]
  • 深入探索HTTP协议的学习与实践
    在初次访问某个网站时,由于本地没有缓存,服务器会返回一个200状态码的响应,并在响应头中设置Etag和Last-Modified等缓存控制字段。这些字段用于后续请求时验证资源是否已更新,从而提高页面加载速度和减少带宽消耗。本文将深入探讨HTTP缓存机制及其在实际应用中的优化策略,帮助读者更好地理解和运用HTTP协议。 ... [详细]
  • 在探讨P1923问题时,我们发现手写的快速排序在最后两个测试用例中出现了超时现象,这在意料之中,因为该题目实际上要求的是时间复杂度为O(n)的算法。进一步研究题解后,发现有选手使用STL中的`nth_element`函数成功通过了所有测试点。本文将详细分析这一现象,并提出相应的优化策略。 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 在处理大数相加的问题时,有许多方法可以借鉴。本文介绍了两种不同的函数式编程方法:一种是从网络上找到的经典实现,另一种是作者自行设计的创新方案。通过函数式编程的方式重新实现了这两种方法,其中经典实现简洁明了,而创新方案则在性能和可读性方面有所提升。这些方法不仅适用于大数相加,还可以扩展应用于其他数值计算场景。 ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 在2022年11月2日的AcWing每日编程挑战中,任务是计算一个长度为n的整数序列中的逆序对数量。逆序对是指在序列中,若存在两个下标i和j(i < j),且a[i] > a[j],则称这两个元素构成一个逆序对。本题要求实现一个算法来高效地统计这些逆序对的数量。 ... [详细]
  • 作文记录:合并区间的技巧与应用
    本文详细记录了合并区间问题的解题技巧与应用场景。首先介绍了问题背景和题目描述,接着从排序最大值的角度探讨了解决思路,并提供了具体的程序代码及运行结果。此外,还探讨了其他可能的解决方案。最后,对整个解题过程进行了总结,为读者提供了全面的理解和参考。 ... [详细]
  • 本文深入探讨了NoSQL数据库的四大主要类型:键值对存储、文档存储、列式存储和图数据库。NoSQL(Not Only SQL)是指一系列非关系型数据库系统,它们不依赖于固定模式的数据存储方式,能够灵活处理大规模、高并发的数据需求。键值对存储适用于简单的数据结构;文档存储支持复杂的数据对象;列式存储优化了大数据量的读写性能;而图数据库则擅长处理复杂的关系网络。每种类型的NoSQL数据库都有其独特的优势和应用场景,本文将详细分析它们的特点及应用实例。 ... [详细]
  • 本文探讨了使用JavaScript在不同页面间传递参数的技术方法。具体而言,从a.html页面跳转至b.html时,如何携带参数并使b.html替代当前页面显示,而非新开窗口。文中详细介绍了实现这一功能的代码及注释,帮助开发者更好地理解和应用该技术。 ... [详细]
  • 在处理木偶评估函数时,我发现可以顺利传递本机对象(如字符串、列表和数字),但每当尝试将JSHandle或ElementHandle作为参数传递时,函数会拒绝接受这些对象。这可能是由于这些句柄对象的特殊性质导致的,建议在使用时进行适当的转换或封装,以确保函数能够正确处理。 ... [详细]
  • 深入理解 Java 控制结构的全面指南 ... [详细]
author-avatar
少爷自控_592
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有