前端面試:基礎javascript篇(二)
11. js的new操作符做了哪些事情
new 操作符新建了一個空物件,這個物件原型指向建構函式的prototype,執行建構函式後返回這個物件。
12.
改變函式內部this指標的指向函式(bind,apply,call的區別)
通過apply和call改變函式的this指向,他們兩個函式的第一個引數都是一樣的表示要改變指向的那個物件,第二個引數,apply是陣列,而call則是arg1,arg2...這種形式。
通過bind改變this作用域會返回一個新的函式,這個函式不會馬上執行。
13.js的各種位置,比如clientHeight,scrollHeight,offsetHeight ,
clientHeight:表示的是可視區域的高度,不包含border和滾動條
offsetHeight:表示可視區域的高度,包含了border和滾動條
scrollHeight:表示了所有區域的高度,包含了因為滾動被隱藏的部分。
clientTop:表示邊框border的厚度,在未指定的情況下一般為0
scrollTop:滾動後被隱藏的高度,獲取物件相對於由offsetParent屬性指定的父座標(css定位的元素或body元素)距離頂端的高度。
14. . js拖拽功能的實現
首先是三個事件,分別是mousedown
當滑鼠點選按下的時候,需要一個tag標識此時已經按下,可以執行mousemove裡面的具體方法。
clientX,clientY標識的是滑鼠的座標,分別標識橫座標和縱座標,並且我們用offsetX和offsetY來表示元素的元素的初始座標,移動的舉例應該是:
滑鼠移動時候的座標-滑鼠按下去時候的座標。
也就是說定位資訊為:
滑鼠移動時候的座標-滑鼠按下去時候的座標+元素初始情況下的offetLeft.
還有一點也是原理性的東西,也就是拖拽的同時是絕對定位,我們改變的是絕對定位條件下的left
以及top等等值。
補充:也可以通過html5的拖放(Drag
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>拖拽實現-</title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
html,body{
overflow: hidden;
height: 100%;
}
#warp{
width: 150px;
height: 150px;
background-color: red;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<div id="warp">
</div>
</body>
<script type="text/javascript">
window.onload = function(){
/*
* 拖拽:1:在點選的時候獲取元素的起始位置,滑鼠的位置
* 2:在移動的時候計算滑鼠移動的距離
* 3:設定元素的偏移量
*/
var warp = document.querySelector("#warp");
var startPoint = {x:0,y:0};
var oldPoint = {x:0,y:0};
warp.onmousedown = function(ev){
ev = ev||event;
if(this.setCapture)
{
this.setCapture();//事件的全域性捕獲 相容IE8,阻止IE8的預設行為
}
startPoint.x = this.offsetLeft;
startPoint.y = this.offsetTop;
oldPoint.x = ev.clientX;
oldPoint.y = ev.clientY;
document.onmousemove = function(ev){
ev = ev||event;
newPoint = {x:0,y:0};
newPoint.x = ev.clientX;
newPoint.y = ev.clientY;
var dis = {x:0,y:0};
dis.x = newPoint.x - oldPoint.x ;
dis.y = newPoint.y - oldPoint.y ;
//邊界判斷
var L= startPoint.x +dis.x;
var T= startPoint.y +dis.y;
if(L<0)
{
L = 0;//左邊的標籤
}
if(T<0)
{
T = 0;//左邊的標籤
}
if(T >= document.documentElement.clientHeight - warp.offsetHeight)
{
T = document.documentElement.clientHeight - warp.offsetHeight ;
}
if(L >= document.documentElement.clientWidth - warp.offsetWidth)
{
L = document.documentElement.clientWidth - warp.offsetWidth ;
}
//偏移
warp.style.left = L +"px";
warp.style.top = T +"px";
}
document.onmouseup = function(){
document.onmouseup = document.onmousemove = null;
if(document.releaseCapture){
document.releaseCapture();
}
}
return false ; //阻止預設行為
}
}
</script>
</html>
15. 非同步載入js的方法
defer:只支援IE如果您的指令碼不會改變文件的內容,可將 defer 屬性加入到<script>標籤中,以便加快處理文件的速度。因為瀏覽器知道它將能夠安全地讀取文件的剩餘部分而不用執行指令碼,它將推遲對指令碼的解釋,直到文件已經顯示給使用者為止。
async,HTML5屬性僅適用於外部指令碼,並且如果在IE中,同時存在defer和async,那麼defer的優先順序比較高,指令碼將在頁面完成時執行。
建立script標籤,插入到DOM中
16. Ajax 解決瀏覽器快取問題
在ajax傳送請求前加上 anyAjaxObj.setRequestHeader("If-Modified-Since","0")。
在ajax傳送請求前加上 anyAjaxObj.setRequestHeader("Cache-Control","no-cache")。
在URL後面加上一個隨機數: "fresh=" + Math.random()。
在URL後面加上時間搓:"nowtime=" + new Date().getTime()。
如果是使用jQuery,直接這樣就可以了 $.ajaxSetup({cache:false})。這樣頁面的所有ajax都會執行這條語句就是不需要儲存快取記錄。
17.js的節流和防抖
防抖動:防抖技術即是可以把多個順序地呼叫合併成一次,也就是在一定時間內,規定事件被觸發的次數。
節流函式:只允許一個函式在 X 毫秒內執行一次,只有當上一次函式執行後過了你規定的時間間隔,才能進行下一次該函式的呼叫。
rAF:16.7ms 觸發一次 handler,降低了可控性,但是提升了效能和精確度。
18. JS中的垃圾回收機制
必要性:由於字串、物件和陣列沒有固定大小,所有當他們的大小已知時,才能對他們進行動態的儲存分配。JavaScript程式每次建立字串、陣列或物件時,直譯器都必須分配記憶體來儲存那個實體。只要像這樣動態地分配了記憶體,最終都要釋放這些記憶體以便他們能夠被再用,否則,JavaScript的直譯器將會消耗完系統中所有可用的記憶體,造成系統崩潰。
這段話解釋了為什麼需要系統需要垃圾回收,JS不像C/C++,他有自己的一套垃圾回收機制(Garbage Collection)。JavaScript的直譯器可以檢測到何時程式不再使用一個物件了,當他確定了一個物件是無用的時候,他就知道不再需要這個物件,可以把它所佔用的記憶體釋放掉了。例如:
var a="hello world";
var b="world";
var a=b;
//這時,會釋放掉"hello world",釋放記憶體以便再引用
垃圾回收的方法:標記清除、計數引用。
標記清除
這是最常見的垃圾回收方式,當變數進入環境時,就標記這個變數為”進入環境“,從邏輯上講,永遠不能釋放進入環境的變數所佔的記憶體,永遠不能釋放進入環境變數所佔用的記憶體,只要執行流程進入相應的環境,就可能用到他們。當離開環境時,就標記為離開環境。
垃圾回收器在執行的時候會給儲存在記憶體中的變數都加上標記(所有都加),然後去掉環境變數中的變數,以及被環境變數中的變數所引用的變數(條件性去除標記),刪除所有被標記的變數,刪除的變數無法在環境變數中被訪問所以會被刪除,最後垃圾回收器,完成了記憶體的清除工作,並回收他們所佔用的記憶體。
引用計數法
另一種不太常見的方法就是引用計數法,引用計數法的意思就是每個值沒引用的次數,當聲明瞭一個變數,並用一個引用型別的值賦值給改變數,則這個值的引用次數為1,;相反的,如果包含了對這個值引用的變數又取得了另外一個值,則原先的引用值引用次數就減1,當這個值的引用次數為0的時候,說明沒有辦法再訪問這個值了,因此就把所佔的記憶體給回收進來,這樣垃圾收集器再次執行的時候,就會釋放引用次數為0的這些值。
用引用計數法會存在記憶體洩露,下面來看原因:
function problem() {
var objA = new Object();
var objB = new Object();
objA.someOtherObject = objB;
objB.anotherObject = objA;
}
在這個例子裡面,objA和objB通過各自的屬性相互引用,這樣的話,兩個物件的引用次數都為2,在採用引用計數的策略中,由於函式執行之後,這兩個物件都離開了作用域,函式執行完成之後,因為計數不為0,這樣的相互引用如果大量存在就會導致記憶體洩露。
特別是在DOM物件中,也容易存在這種問題:
var element=document.getElementById(’‘);
var myObj=new Object();
myObj.element=element;
element.someObject=myObj;
這樣就不會有垃圾回收的過程。
19.eval是做什麼的
它的功能是將對應的字串解析成js並執行,應該避免使用js,因為非常消耗效能(2次,一次解析成js,一次執行)
20.如何理解前端模組化
前端模組化就是複雜的檔案程式設計一個一個獨立的模組,比如js檔案等等,分成獨立的模組有利於重用(複用性)和維護(版本迭代),這樣會引來模組之間相互依賴的問題,所以有了commonJS規範,AMD,CMD規範等等,以及用於js打包(編譯等處理)的工具webpack