1. 程式人生 > >基於上次騰訊遠端面試的題目總結與回答(精心總結回顧) 上

基於上次騰訊遠端面試的題目總結與回答(精心總結回顧) 上

這篇部落格同步更新於我的GitHub部落格:我的GitHub部落格

1.js中ajax傳送請求的步驟

在js中,有一個用於非同步請求的物件,XMLHttpRquest物件,使用該物件可以向服務端傳送請求(post,get,put...)。原生的方法步驟如下:

①建立XMLHttpRequest物件(標準瀏覽器):

if(window.XMLHttpRequest){
  var xhr = new XMLHttpRequest();
}

IE7及以下,這個物件為:ActiveXObject:

if(window.ActiveXObject){
var xhr = new
ActiveXObject('Microsoft.XMLHTTP') }

② 初始化請求

xhr.open('GET','http://www.請求地址.com',是否非同步?true:false);

③傳送請求/傳遞資料

xhr.send();

請求的檔案路徑,如果是GET方式,直接綴在請求地址的後面,以如下的形式:

//資料
xhr.open('GET','http://www.請求地址.com/index.html',true);

如果是POST方法,直接寫 xhr.send('資料') 中。

④設定非同步回撥callback()
先給個錯誤示範:

//xhr.readyState 本地的請求狀態
//xhr.status 伺服器返回的請求狀態碼 if(xhr.readystate==4 && xhr.status == 200){ do something... }

這裡的本質原因是沒有本地xhr物件改變的事件,因此這裡的readystate會一直長等於 1

這裡的非同步方式主要通過一個事件來完成:

xhr.onreadystatechange()=function(){

if(xhr.readystate==4 && xhr.status == 200){
  do something...
}

}

如果在步驟②中請求的方式是同步的,一旦伺服器壓力過大,沒有及時響應,那麼程式碼會一直卡在這裡,一直傻傻的等到伺服器響應200,才會do something。

反之,如果請求方式是非同步的,那麼這裡的響應無論是否及時,都不會阻塞後面的程式碼。

擴充套件:既然 readyState==4 && status ==200 是一個回撥,那麼我們也可以使用其他的http狀態碼來設定不同的回撥~
參考文章 ,我以前的部落格:Ajax初探
上一次的面試中,xhr.open()初始化 xhr.send()傳送請求 xhr.onreadystatechange=function(){}回撥函式 這三點都忘記答了,一定要注意。

2.瀏覽器裡面的事件都會按照一定的規則去傳遞,這個規則是什麼?

事件捕獲、事件響應、事件冒泡。

如圖:

事件捕獲和冒泡

不管body上繫結事件、或者div甚至div的text節點上繫結事件,這個事件必須先從根節點開始遍歷(即Window物件開始),從上往下,傳遞的過程中,發現有的元素綁定了事件,也先放著,等全部事件捕獲完畢(遍歷完畢), 開始處理事件,處理的順序為,從最小的根節點上的事件開始,依次向上冒泡。

一句話概括這種機制:

捕獲:自外而內,從根到葉,從大到小 。

冒泡:自內而外,從葉到根,從小到大。

來做個實驗,有如下的html結構 和 js程式碼:

<!--HTML結構-->
<div id="div1">
        我是DIV1
        <div id="div2">
            我是DIV2
            <button id="btn">
                i am a button
            </button>
        </div>
    </div>


//script程式碼

var div1 = document.getElementById('div1');
var div2 = document.getElementById('div2');
var btn = document.getElementById('btn');

btn.addEventListener('click', function() {console.log(this.id)},false);


div2.addEventListener('click', function(){console.log(this.id)},false);

div1.addEventListener('click', function(){console.log(this.id)},false);

HTML結構如圖:

HTML結構

當點選最裡面的button,會依次出現這種情況:

控制檯輸出

可以看到,事件是在冒泡階段被觸發的。

當改變js API中最後一個Boolean值為true時,又會產生另外一種景觀:

這裡寫圖片描述

這次是從外向內依次觸發的。

總結:
1.addEventListener(事件,函式,boolean?捕獲:冒泡),這個API可以設定事件觸發於捕獲/冒泡階段,而且這個事件可以複寫。
2.普通的API,例如 onclick ,onmouse 預設只能在冒泡階段觸發,而且不能複寫,複寫事件會覆蓋。

3.閉包是怎麼回事?用在什麼場景?

簡而言之:1、閉包就是可以訪問區域性作用域的變數。
並且: 2、 可以使區域性變數常駐記憶體
參考阮一峰老師的閉包部落格: 阮一峰—-閉包

Q:閉包的內部函式為什麼變數不會被銷燬?
A:

function a(){
var a =1;

function b(){
a+=1;
return a;
}
return b();

}

因為此時的子函式b一直對於a函式的變數“a=1”有需求,因此這個變數會常駐記憶體,不會被銷燬。

Q 3.1:什麼時候才能夠銷燬這個記憶體呢?(銷燬機制和人為銷燬方法)

A:瀏覽器中的js引擎有自己的垃圾回收機制,當一個變數或者物件引用為0的時候,會自動回收。
人為的銷燬記憶體的辦法:1.關閉網頁,結束js執行環境。2.銷燬變數,為變數賦值 null;

Q3.2:如何避免記憶體洩漏的問題?
A:減少全域性空間的汙染,良好的變數定義習慣。減少變數的引用。

4.CALL和Apply是幹嘛的?

二者都是為了更改function 的this指標,舉個例子

CALL(新的this物件,原先的引數1,原先的引數2…);
Apply(新的this物件,[原先的引數1,原先的引數2…]);

先傳入新的this物件,再傳入舊方法的傳參。

5.在平時開發中,遇到過跨域的問題嗎?如何處理跨域呢?

1.jsonp跨域
利用<script>標籤的跨域特性,將請求的語句寫在script標籤的src屬性上,然後定義一個方法,用於接受返回值responseText。程式碼如下:

        //在js預先定義好callback()函式  

        function fun(data){

            //use data to do somethings.

        }


        //動態建立script標籤,並在url中說明請求地址
        var body = document.getElementsByTagName('body')[0];

        var script = document.createElement('script');

        script.type = 'text/javasctipt';

        script.src = 'require.php?callback=fun';

        body.appendChild(script);

        //Script插入完成,一旦服務端有響應,傳遞過來的響應文字會直接被當做js程式碼執行。
           //假設傳回的值是 fun({"name":"xiaoming"}),那麼小明這個物件會被當做引數傳遞給早就定義好的fun()函式。

這樣,通過script不受跨域訪問的特性,實現了跨域訪問。

2.CORS跨域(主流瀏覽器及IE10+)
對於客戶端,我們還是正常使用xhr物件傳送ajax請求。
唯一需要注意的是,我們需要設定我們的xhr屬性withCredentials為true,不然的話,cookie是帶不過去的哦,設定: xhr.withCredentials = true;
對於伺服器端,需要在 response header中設定如下兩個欄位:
Access-Control-Allow-Origin: http://www.yourhost.com
Access-Control-Allow-Credentials:true
這樣,我們就可以跨域請求介面了。

3.返回的json和jsonp有什麼區別?
返回的json是json格式的檔案,而返回的jsonp是字串形式的檔案,形如:

callback({"name":"HanMeiMei"})