基於上次騰訊遠端面試的題目總結與回答(精心總結回顧) 上
這篇部落格同步更新於我的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結構如圖:
當點選最裡面的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"})