最近遇到的問題總結(陣列去重、扁平化處理、sort 以及Promise等等)

Summer_xiazi發表於2018-09-11

開頭,首先談一談前幾天去 攜程 的面試吧,剛開始筆試的題目,坦白說都是比較簡單的,開始大概是十道選擇題,都是基礎的理論題,一般基礎還可以的人肯定都會寫!接下來是幾道程式的執行題,主要考一些變數提升,閉包形式的執行結果,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的時候,test只代表物件中的一個函式,所以執行的時候會直接去需找所定義的name這個變數,所以肯定是全域性變數john 了;

二輪的時候,我一臉懵逼的去了,他們的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);
    });
複製程式碼

遇到得問題還有很多很多啊... 在這條求坑之路中摸索前行,其實蠻難的,加油吧!!!希望有大神指點額......

相關文章