讓面試中的Ajax、跨域和前端演算法見鬼去吧

Vincent Ko發表於2018-07-25

前言: 小白秋招準備第三彈...這次主要總結和複習了ajax請求以及跨域的一些問題。因為實習後,直接用Jquery或axios傳送請求,原生的方法都有點生疏了,再次複習。另外,還總結了一些面試常見的演算法問題,關於演算法我會堅持練習並記錄下較好的點並不斷在github更新。 一起找工作的、喜歡的小夥伴歡迎Star

GitHub 地址傳送門

Ajax && Jsonp跨域

Ajax

通過Jquery或者axios傳送Ajax請求

//jquery
$.get('//discovery.vip.com',{
    'click':3,
    'name':'job'
},(data) => {
    console.log(data);
})

//  $.get() 與 $.post()基本一致,第一個引數url,第二個引數是資料(可選)
//  第三個引數是回撥函式

//axios 與juqery很相似,只不過它是支援Promise的一種方法
axios.get('//discovery.vip.com').then((data)=>{
    console.log(data);
}).catch(error) {
    console.log(error);
}

//可選請求
axios.get('//discovery.vip.com',{
    params:{
        id:12345
    }
}).then((data)=>{
    console.log(data);
}).catch(err => {
    console.log(err);
})

複製程式碼

原生Ajax方法

原生Ajax是建立在XMLHttpRequest請求上,這個現代瀏覽器支援,不支援的話,得使用ActiveX物件 new一個物件

if(window.XMLHttpRequest) {
    var Req = new XMLHttpRequest();
}else {
    var Req = new ActiveX('Microsoft.XMLHTTP');
}
複製程式碼

物件建立好之後,即使傳送請求了open()send() 其中open規定格式,send()正式傳送

//get方法
//get方法,send不需要加內容,open的第三個參數列示是否非同步,預設為true
Req.open('get','//discovery.vip.com',true);
Req.onreadystatechange = function() {
    if(Req.readyState === 4 && Req.status === 200) {
        document.getElementById('root').innerHtml = Req.responseText;
    }
}
Req.send();

//post
Req.open('post','//discovery.vip.com',true);
Req.setRequestHeader('Content-type','application/x-www-form-urlencoded');
Req.onreadystatechange = function() {
    if(Req.readyState === 4 && Req.status === 200) {
        document.getElementById('root').innerHtml = Req.responseText;
    }
}
Req.send("fname=Henry&lname=Ford");
複製程式碼

注意這裡post的方法設定了請求頭,這裡對請求頭簡單說一下

  1. Content-type,application/x-www-form-urlencoded 的方式

這種方式最常見的方式,原生form表單的提交方式。 提交的時候,將會以key1=value&key2=value&key3=value的方式進行編碼

  1. multipart/form-data

這個看起來也是比較熟悉的,因為的確也很常見呀~ 當要使用檔案上傳元件時,必須讓form的entyped的值等於這個

  1. application/json格式

這個就是json的格式,用來告訴伺服器訊息主體是序列化後的JSON字串

跨域

跨域最簡單、乾淨的方式,應該是W3C規定的CROS跨域了。 這個在使用fidder進行抓包除錯的時候,使用filter來處理跨域的問題,算是很方便了。

方法就是在返回資料上加個頭 set Response header

Access-Control-Allow-Origin,* 這個表示允許任意域名跨域

Access-Control-Allow-Origin,192.168.1.110:8080允許指定域名跨域

當然這個不是重點,下面主要說一下Jsop的跨域

Jsonp

Jsonp跨域也是需要後端伺服器配合的,原來就是雖然Ajax請求不允許跨域,但是<script>、<img>等是可以跨域的

//jquery封裝的跨域

$.ajax({
    url:'//discovery.vip.com',
    method: 'GET',
    dataType: 'jsonp',
    success: function (data) {
        var result = JSON.stringify(data);
        $('#test').val(result);
    }

})

複製程式碼

注意:JSONP的一個限制,就是隻能使用get請求,因為<script src>就支援get請求呀。

好了,以上的方法會返回一個隨機的函式名,Jquery內部處理得到。如果想要自己規定,也是可以的

$.ajax({
    url:'//discovery.vip.com',
    method:'GET',
    dataType:'jsonp',
    jsonpCallback:'showData',
    success:function(data) {
        console.log('success')
    }
})

function showData(data) {
    var result = JSON.stringify(data);
    $("#test").val(result);
}
複製程式碼

這裡就可以看的更清楚一些了,其實返回的資料是showData({...})。 因為我們設定了函式,所以就直接執行函式。

就是因為這樣的道理,我們完全可以自己做一個script標籤,動態新增src來請求資料,實現自己的jsonp

演算法

統計數字

問題描述

計算數字k在0到n中的出現的次數,k可能是0~9的一個值

例如n=12,k=1,在 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],我們發現1出現了5次 (1, 10, 11, 12)

解析: 最簡單的方法就是遍歷了,當然高階方法這裡不探討。那麼簡單的遍歷又有什麼問題呢? 那就是遇到了比如111這樣的數字。

我們可以使用indexOf來判斷是否出現過,但是出現了多少次該怎麼判斷?

說一個思路,使用split方法,具體實現如下

const digitCounts = function (k, n) {
    let num = 0;
    for(let i = 0; i<=n;i++){
        if(String(i).indexOf(k) !== -1) {
            num += (String(i).split(k).length-1)
        }
    }
    return num
}
複製程式碼

題目地址(lintcode)

快速排序和二分查詢

一般的排序,使用Array.sort()可以很方便的解決,所以對於前端來說,主要掌握快排和二分查詢是基礎和必要的。其他的可以有興趣再研究好了

快排

只用遞迴實現,基本思路:

  1. 拿出一個數字;
  2. 逐一和剩下數字比較,比這個數字小的放左邊,大的放右邊
  3. 對左邊和右邊再使用同樣的比較方法
  4. 直到比較結束

程式碼實現如下:

function quickSort(arr) {
    if(arr.length <= 1) {
        return arr;
    }
    let left = [];
    let right = [];
    let cur = arr.splice(0,1);
    for(let i = 0; i<arr.length; i++) {
        if(arr[i] < cur) {
            left.push(arr[i])
        } else {
            right.push(arr[i])
        }
    }
    return quickSort(left).concat(cur,quickSort(right));
}

複製程式碼

二分查詢

原理很簡單了,就是找中間數,複雜度(log(N)),前提是必須在有序數列中查詢

  1. 在一個範圍內,將target與中間值比較
  2. 如果大了,在大的範圍進行查詢;如果小了,在小的範圍查詢;
  3. 重複上面的方法

用兩種方法,一種是迴圈,一種是遞迴來實現

//迴圈實現
function binarySearch(arr,target) {
    let low = 0;
    let high = arr.length - 1;
    while(low <= high) {
        let mid = parseInt((high+low)/2);
        if(target === arr[mid]) {
            return `找到了${target},位置在${mid}`
        } else if (target > Math.floor(high/2)) {
            low = mid+1;
        } else {
            high = mid-1;
        }
    }
    return false;
}
複製程式碼

這裡需要注意low high的取值和變化

  1. 中間值的取法`parseInt((high+low)/2)
  2. 當在另一個區間的時候,不能用low = midhigh=mid,因為這樣邊界值就會進入死迴圈。
//遞迴的方法
function binarySearch(arr,target,low,high) {
    let mid = parseInt((low+high)/2);
    if(arr[mid] === target) {
        return `找到了${target},位置在${mid}`
    } else if(target > arr[mid]) {
        return binarySearch(arr,target,mid+1,high)
    } else {
        return binarySearch(arr,target,low,high-1)
    }
    return -1
}
複製程式碼

二分查詢真題,尋找二維陣列內的值

在一個二維陣列中,每一行都按照從左到右遞增,每一列都從上到下遞增的順序排序,完成一個函式,輸入這個二維陣列和一個整數,判斷陣列中是否含有該整數

思路是一樣的,只不過從一維變成了二維,我們遍歷思路可以這樣子:

  1. 選取第一行的最後一個進行判斷(這個是第一行中最大的)
  2. 如果目標大於該值,行數加1,遍歷第二行(因為每列都是遞增的)
  3. 如果目標小於該值,則在這一行中進行查詢
  4. 迴圈以上步驟
function findTarget(arr,target) {
    let i = 0; 
    let j = arr[i].length -1;
    while(i < arr.length && j>=0) { //i是隻增不減的,j是隻減不增的,就是從矩陣右上角向下查詢的過程
        if(target < arr[i][j]) {
            j--;
        } else if (target > arr[i][j]) {
            i++;
        } else {
            return `找到了,位置在${i},${j}`
        }
    }
    return `(${i},${j})`
}

arr=[
[1,2,3,4],
[5,9,10,11],
[13,20,21,23]]  //測試
複製程式碼

後記

嗯..今天先到這裡吧

演算法算是比較頭疼的,因為非科班出身,對於前端演算法的深度過深對於實際效率而言並不高(為了以後深入發展當然要好好研究,可是如果為了近期秋招、面試,似乎不如適可而止,花更多時間在應該的地方上)

所以後期會積累常見、常考的演算法題目,一一記錄,共同成長... 明天再更

相關文章