综合面试题-js深入版

综合面试题-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<arr.length;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<arr1.length-1;i++){
        if(arr1[i][0]<arr1[i+1][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,'a',{
    get(){
        return ++n;
    }
})
if(a==1 && a==2 & a==3){
    console.log('OK')
}


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

  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.length;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.length;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.length;i++){
    // arr[i]:要插入的元素
    let insert=arr[i]
    let j=i-1;
    while(j>=0 && insert<arr[j]){
        arr[j+1]=arr[j];
        j--;
    }
    arr[j+1]=insert;  

}
console.log(arr);

自己总结:

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

所以代码上是:

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

从后往前扫描,j=i-1;并且用一个变量temp保存这张新牌即arr[i],从后往前扫描的同时元素依次往后挪,边比较边往后挪,内层循环的条件是 while j>=0 && temp<arr[j],当出循环的时候,j+1号位置就是我们要插入的位置。

  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<middle) left.push(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 与柯理化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值