阅读 38

最近遇到的问题总结(数组去重、扁平化处理、sort 以及Promise等等)

开头,首先谈一谈前几天去 携程 的面试吧,刚开始笔试的题目,坦白说都是比较简单的,开始大概是十道选择题,都是基础的理论题,一般基础还可以的人肯定都会写!接下来是几道程序的运行题,主要考一些变量提升,闭包形式的运行结果,this指向问题,随便举几个例子吧:

1. 首先说的这个题目其实相当经典的,很多地方都遇到过:

    function Foo() {
        var i = 0;
        retunr function() {
            console.log(i++);
        }
    }
    var f1 = Foo(), f2 = Foo();
    f1(); f1(); f2();
复制代码

其实这一题感觉就是考虑变量提升吧,输出结果依此就是 0 1 0;简单来说就是,第一次执行f1() 函数后,函数内部的 i 值就发生了改变,下一次执行f1(), i在原来的基础上做了++ , 所以就输出了 1,当执行f2函数的时候,重新执行了一次函数,所以输出还是原来的0, 我就是这么理解的,所以不多做解释啦....

2. 函数内部的变量问题:

    var bb = 5;
    function aa(bb) {
        bb = 10;
        alert(bb);
    }
    aa(bb);
    alert (bb);
    输出的结果分别就是 10 和 5;
复制代码

刚开始其实我考虑了一下,函数执行输出结果在函数内部改变,所以输出为10 肯定没问题,其实很多人在这个地方考虑的是函数内部的值改变,会不会将外部的值也改变,参考一下函数变量的作用域,你就会发现其实并没有改变!所以alert 的还是 bb = 5;

3. 记忆中还考了一个obj 中的 this 指向问题,也很经典其实!简单写一个类似的吧:

    var name =  'john';
    var obj = {
        name: 'Bob',
        prop:{
            name: 'joyjoy',
            getName:function() {
                return this.name;
            }
        }
    }
    console.log(obj.prop.getName());         // joyjoy
    var test = obj.prop.getName;
    console.log(test());           //   john;
复制代码

其实,对this 指向去研究过的童鞋,应该很好理解这个问题,第一次去直接访问obj.prop.getName,那么作用域很显然就是在obj.prop 这个对象中,那么肯定会直接访问这个对象中的name,所以打印的是joyjoy; 当实例化一个新的function 的时候,

二轮的时候,我一脸懵逼的去了,他们的CTO吧应该是,写了一堆原生的问题,以下面两个经常遇见的举例:

一. 数组去重:

1.首先最简单的写法:

    Array.from(new Set()); 
    但是这种方法一般面试官都不会买账的,然后我想了另外一种方法去实现,如下:
复制代码

2. 新建一个对象,去判断:

例如:

    let arr = [1,2,3,4,'4',5,5,6];
    let obj = {};
    let newArr = [];
    for(let i = 0;i<arr.length;i++) {
        if(!obj[arr[i]]) {
            newArr.push(arr[i]);
            obj[arr[i]] = true;
        }
    }
    // 输出的newArr 为 [1,2,3,4,5,6]
复制代码

通过键值对的形式,也可以实现这个问题,当时面试官质疑了我这种方法,说万一里面number类型,字符串类型都存在,会被默认去重,就像上述数组中的 4 和 '4' 一样;回来想想确实是的,再仔细想了想,还是不知道咋解决,于是便再重新想了一个方法: (ps: 下面这个想法,高度紧张,卡住了,因为他依旧没有解决这个问题啊);

3.双重for 循环去实现:

    var arr=[1,2,3,4,4,4,5,5,5,5,5,6];
    var resultArr = [];
    for(var i = 0;i< arr.length;i++) {
    	for(var j = i+1;j<arr.length;j++) {
    		if(arr[i] == arr[j]) {
    			j = ++i;
    		}
    	}
    	resultArr.push(arr[i]);
    }
    // 输出 [1,2,3,4,5,6]
复制代码

这个方法内部判断条件,其实可以换成splice 在 原数组上直接修改的,具体的就不介绍啦;

想了很多,好像就只有 new Set() 可以区分上面的数值和字符串问题,但我又不了解new Set() 的具体机制和我的第二种方法有啥区别,就很尴尬了;

二: 数组的扁平化处理

刚开始说这个的时候,其实我不懂啥意思,然后试探性的问了一下,是不是就是降维,可能脑海深处突然蹦出来这个思维逻辑吧,但并没有啥卵用,我这个大菜鸟大概都忘了这些东西了,哈哈。。。然后随便写了几行代码,一团糟呢,现在想起来。下面给几个思路:

1. 回来想到最简单的方法,用arr.join() 方法去实现这玩意儿;

    var arr = [1,2,3,4,[5,6],[7,8,]];
    var newArr = Array.from(arr.join());
    for (var i = 0;i<newArr.length;i++) {
    	if(isNaN(newArr[i])){
    		newArr.splice(i,1);
    	} 
    }
    emmm....这就是我想到的最简单的办法啦。。。嘿嘿!
复制代码

2. 其实可能面试官更想要的就是网上的那循规蹈矩的三种方法吧: 简单提一下吧

    第一种: 双重 for 循环: 
    var result = [];
    for(var i=0;i<arr.length;i++){
        for(var j=0;j<arr[i].length;j++){
            result.push(arr[i][j]);
        }
    }
    
    第二种: 用concat代替内层循环
    var result = [];
    for(var i=0;i<arr.length;i++){
        result = result.concat(arr[i]);
    }
    
    第三种:用apply代替外层遍历
    var result = [].concat.apply([],arr);
复制代码

当然了,上面这三个方法就初步实现了简单的二维数组降维,多重数组降维,还需要通过递归的方法去实现的:

一个简单的实现思路:

    var arr = [2, 3, [2, 2],
        [3, 'f', ['w', 3]], { "name": 'Tom' }
    ];
    let result = [];
    arr.forEach(function(val, index) {
        if(Array.isArray(val)) {
            val.forEach(arguments.callee);
        } else {
            result.push(val);
        }
    })
    console.log(result);   // 这个就解决了多重数组得降维了....
    
    ps: 稍微解释一下 arguments.callee, 首先显而易见得就是 callee 就是arguments 中得一个属性,他是一个指针,
    指向拥有arguments 这个对象得函数,常用于递归函数,不过现在一般不使用啦!!!!
复制代码

在携程得这段面试,除了这些,还有一些较为原理得原型链啊,闭包啥的,比较底层得知识,显而易见得就是凉凉了啊.... 感觉携程常年招人,也不缺人呢!

再说一些别的地方遇到得面试题吧,首先数组和字符串得一大堆用法,就不一一细说了,最想说得就是 sort 排序得功能了:

一: sort 排序:

1. 首先,sort() 方法会对数组元素进行排序,并返回这个数组;但是sort() 在默认不传比较函数的时候,会将数组中得所有元素通过toString() 方法 转化,在进行字符串比较,所以在默认对数字数组进行排序的时候,会出现问题,所以引入了比较函数:
var arr = [22,1,12,45,36];
arr.sort(function(a, b){
    return a - b;
})
// 默认为升序;相反得如果return b - a; 就是相反得降序;  
复制代码
2.数组得多条件排序,实例如下:
    var array = [{id:10,age:2},{id:5,age:4},{id:6,age:10},{id:9,age:6},{id:2,age:8},{id:10,age:9}]; array.sort(function(a,b){
    if(a.id === b.id){
        return b.age - a.age  // 如果id的值相等,按照age的值降序 
    }else{ 
        return a.id - b.id  // 如果id的值不相等,按照id的值升序
    }   
    }) 
    输出结果:
    [{"id":2,"age":8},{"id":5,"age":4},{"id":6,"age":10},{"id":9,"age":6},{"id":10,"age":9},{"id":10,"age":2}]
复制代码
3. sort 实现乱序(这个方法不太好,就随口提一下):
    Array.sort(function(){
        return 0.5 - Math.random();
    })
复制代码

二: 在简单的说一下 Promise 操作吧,反正去哪都会被问到.....

promise这个 构造函数 简单的 resolve 、 reject 以及 .all 和 .catch 这几个方法就不详细说了额,写一个简单得demo 去实现图片得资源加载吧...

ps: 首先我们都知道 .all 和 .race 的区别就 .all 就是判断哪一个异步函数执行得慢,就以哪一个函数为准去执行回调, 而.race 恰恰相反, 谁执行得快,就以哪一个函数为准执行回调!所以我们就可以写两个函数分别去实现加载图片和显示延时,具体代码如下:
    //请求某个图片资源
    function requestImg(){
        var p = new Promise(function(resolve, reject){
            var img = new Image();
            img.onload = function(){
                resolve(img);
            }
            img.src = 'xxxxxx';
        });
        return p;
    }
    
    //延时函数,用于给请求计时
    function timeout(){
        var p = new Promise(function(resolve, reject){
            setTimeout(function(){
                reject('图片请求超时');
            }, 5000);
        });
        return p;
    }
    
    Promise
    .race([requestImg(), timeout()])
    .then(function(results){
        console.log(results);
    })
    .catch(function(reason){
        console.log(reason);
    });
复制代码

遇到得问题还有很多很多啊... 在这条求坑之路中摸索前行,其实蛮难的,加油吧!!!希望有大神指点额......

关注下面的标签,发现更多相似文章
评论