前端面試題及答案(一)

前端

一.對閉包的理解,以及哪些地方用過閉包,以及閉包的缺點
閉包 是指有權訪問另一個函數作用域中的變量的函數,創建閉包的最常見的方式就是在一個函數內創建另一個函數,通過另一個函數訪問這個函數的局部變量

1.函數嵌套函數
2.函數內部可以引用外部的參數和變量
3.參數和變量不會被垃圾回收機制回收
 
優點:可以避免全局變量的污染,變量和方法私有化,不讓外部修改這些屬性
缺點:閉包會常駐內存,會增大內存使用量,使用不當很容易造成內存泄露
<button id="add">1</button>
<span id="span">10</span>
(function(){
	var a = 10;
	add.onclick = function (){
	   a++;
	   span.innerHTML = a;
	}
})()

二.對跨域瞭解嗎,jsonp 的限制

Q:爲什麼要跨域
A:跨域,通常情況下是說在兩個不通過的域名下面無法進行正常的通信,或者說是無法獲取其他域名下面的數據,這個主要的原因是,瀏覽器出於安全問題的考慮,採用了同源策略,通過瀏覽器對JS的限制,防止惡意用戶獲取非法的數據。

Q:同源策略
A:限制從一個源加載的文檔或腳本如何與來自另一個源的資源進行交互。這是一個用於隔離潛在惡意文件的關鍵的安全機制。

Q:“同源”
A:協議相同、域名相同、端口相同

Q:同源政策的目的
A:是爲了保證用戶信息的安全,防止惡意的網站竊取數據。

Q:同源的限制範圍
A:Cookie、LocalStorage 和 IndexDB 無法讀取;DOM 無法獲得;AJAX 請求不能發送

解決辦法
JSONP
1.只支持GET請求而不支持POST等其它類型的HTTP請求(雖然採用post+動態生成iframe是可以達到post 跨域的目的,但這樣做是一個比較極端的方式,不建議採用)。明確說明:jquery使用POST請求jsonp可以成功是由於jquery自動把POST轉化成GET,實際還是GET請求
2. 一般get請求能完成所有功能。如:如果需要給其他域服務器傳送參數可以在請求後掛參數(注意不要掛隱私數據),即
3. JSONP易於實現,但是也會存在一些安全隱患,如果第三方的腳本隨意地執行,那麼它就可以篡改頁面內容,截獲敏感數據。
4.在受信任的雙方傳遞數據,JSONP是非常合適的選擇。
5.可以看出來JSONP跨域一般用於獲取其他域的數據。
6.一般能夠用JSONP實現跨域就用JSONP實現,這也是前端用的最多的跨域方法。

window.name
1、必須與iframe配合使用
2、window.name 傳輸技術,原本是 Thomas Frank 用於解決 cookie 的一些劣勢(每個域名 4 x 20 Kb的限制、數據只能是字符串、設置和獲取 cookie 語法的複雜等等)而發明的。後來 Kris Zyp 在此方法的基礎上強化了 window.name 傳輸 ,用來解決跨域數據傳輸問題。
3.window.name 的美妙之處:name值在不同的頁面(甚至不同域名)加載後依舊存在,並且可以支持非常長的 name 值(2MB)。
特徵:
1.瀏覽器窗口有 window.name 屬性。這個屬性的最大特點是,無論是否同源,只要在同一個窗口裏,前一個網頁設置了這個屬性,後一個網頁可以讀取它。
2.即在一個窗口(window)的生命週期內,窗口載入的所有的頁面都是共享一個window.name的,每個頁面對window.name都有讀寫的權限,window.name是持久存在一個窗口載入過的所有頁面中的,並不會因新頁面的載入而進行重置。

基本原理:
1.當在瀏覽器中打開一個頁面,或者在頁面中添加一個iframe時,即會創建一個對應的window對象,當頁面加載另一個新的頁面時,window的name屬性是不會變的。
2.這樣就可以利用在頁面動態添加一個iframe然後src加載數據頁面,在數據頁面將需要的數據賦值給window.name。
3.然而此時承載iframe的index頁面(也就是請求數據的頁面)還是不能直接訪問,不在同一域下iframe的name屬性,這時只需要將iframe再加載一個與承載頁面同域的空白頁面,即可對window.name進行數據讀取

document.domain 跨域
這個的實現思路跟cookie跨域相似,都是在兩個關聯域名中設置document.domain值,然後讓這兩個值相等,這樣就可以實現跨域操作

cookie跨域

postMessage跨域

三…瀏覽器哪些地方用到了異步

首先確定JS是一門腳本語言,他的執行順序是從上到下逐行執行的,瀏覽器只有一個javascript引擎,所以瀏覽器同事只能執行一個任務,那麼異步操作的實現原理是什麼呢?
瀏覽器的javascript引擎確實是單線程的,但是瀏覽器本身是多線程的,瀏覽器包含
javascript引擎線程、界面渲染線程、瀏覽器事件觸發線程、Http請求線程
所以出發異步操作的時候,會有單獨的線程去做操作,javascript引擎線程不會受到阻塞,依然繼續解析js代碼。

四、CSS 彈性佈局,哪些地方用到過

	flex佈局

五、如何實現不定寬高水平和垂直居中
1.最簡單的flex佈局
display: flex;
justify-content: center;
align-items: center;
2.利用table-cell
外層容器
display:table-cell;
text-align:center;
vertical-align:middle;
內部元素
vertical-align:middle;
display:inline-block;
3.使用CSS3 transform
外層容器
display:relative
內部元素
transform: translate(-50%,-50%);
position: absolute;
top: 50%;
left: 50%;

六、const 和 let 區別,可以改變 const 定義的某個對象的屬性嗎

let與const都是隻在聲明所在的塊級作用域內有效。
let:無變量提升(未到let聲明時,是無法訪問該變量的)
const:無變量提升,聲明一個基本類型的時候爲常量,不可修改;聲明對象可以修改
const arr = {name:'小可愛', age:'21'}
arr.name = '萱萱'
console.log(arr)
因爲對象是引用類型的,arr中保存的僅是對象的指針,這就意味着,const僅保證指針不發生改變,修改對象的屬性不會	  改變				 
 對象的指針,所以是被允許的。也就是說const定義的引用類型只要指針不發生改變,其他的不論如何改變都是允許的。

七、ES6 用到過嗎,新增了哪些東西,你用到過什麼
定義變量加入了 let const
箭頭函數
Array.from() 將類數組對象與可遍歷對象轉換爲數組
類class

八、箭頭函數,箭頭函數的特點, this 的指向
箭頭函數是匿名函數,不綁定自己的this,arguments,super,new.target
箭頭函數會捕獲其所在上下文的this值,作爲自己的this值,在使用call/apply綁定時,相當於只是傳入了參 數,對this沒有影響

九、數組去重
ES6:Array.from(new Set(arr));

	<script type="text/javascript">
	    let arr = ['1',2,1,3,5,6,5]
	    let arrString = arr.toString()
	    console.log(arrString)
	    arrSplit = arr1.split(',') // 把一個字符串分割成字符串數組。
	    //join() 把數組中的所有元素放入一個字符串。
	    console.log(arrSplit)
	    let set = new Set(arrSplit)
	    console.log(set)
	    let newArr = Array.from(set)
	    console.log(newArr)
	</script>

十、哪些方法會改變原數組

shift:將第一個元素刪除並且返回刪除元素,空即爲undefined
unshift:向數組開頭添加元素,並返回新的長度
pop:刪除最後一個並返回刪除的元素
push:向數組末尾添加元素,並返回新的長度
reverse:顛倒數組順序
sort:對數組排序
splice:splice(start,length,item)刪,增,替換數組元素,返回被刪除數組,無刪除則不返回

十一、深拷貝和淺拷貝
淺拷貝: 將原對象或原數組的引用直接賦給新對象,新數組,新對象/數組只是原對象的一個引用
深拷貝: 創建一個新的對象和數組,將原對象的各項屬性的“值”(數組的所有元素)拷貝過來,是“值”而不是“引用”

深拷貝的要求程度
我們在使用深拷貝的時候,一定要弄清楚我們對深拷貝的要求程度:是僅“深”拷貝第一層級的對象屬性或數組元素,還是遞歸拷貝所有層級的對象屬性和數組元素?

深拷貝數組(只拷貝第一級數組元素)
1.直接遍歷
2. slice()
slice() 方法返回一個從已有的數組中截取一部分元素片段組成的新數組(不改變原來的數組!)
用法:array.slice(start,end) start表示是起始元素的下標, end表示的是終止元素的下標
當slice()不帶任何參數的時候,默認返回一個長度和原數組相同的新數組

var array = [1, 2, 3, 4];
var copyArray = array.slice();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]
3. concat()
var array = [1, 2, 3, 4];
var copyArray = array.concat();
copyArray[0] = 100;
console.log(array); // [1, 2, 3, 4]
console.log(copyArray); // [100, 2, 3, 4]

深拷貝對象
1.直接遍歷
2.ES6的Object.assign

var obj = {
  name: '醉霜林',
  job: '前端開發'
}
var copyObj = Object.assign({}, obj);
copyObj.name = '醉霜林2號';
console.log(obj);   // {name: "醉霜林", job: "前端開發"}
console.log(copyObj);  // {name: "醉霜林2號", job: "前端開發"}

Object.assign:用於對象的合併,將源對象(source)的所有可枚舉屬性,複製到目標對象(target),並返回合併後的target
用法: Object.assign(target, source1, source2); 所以 copyObj = Object.assign({}, obj); 這段代碼將會把obj中的一級屬性都拷貝到 {}中,然後將其返回賦給copyObj
3.ES6擴展運算符:
擴展運算符(…)用於取出參數對象的所有可遍歷屬性,拷貝到當前對象之中
對多層嵌套對象,很遺憾,上面三種方法,都會失敗:

var obj = {
   name: {
      firstName: '醉',
      lastName: '霜林'
   },
   job: '前端開發'
}
 
var copyObj = Object.assign({}, obj)
copyObj.name.lastName = '霜林醉';
console.log(obj.name.lastName); // 霜林醉
console.log(copyObj.name.lastName); // 霜林醉

拷貝所有層級

1.不僅拷貝第一層級,還能夠拷貝數組或對象所有層級的各項值
2. 不是單獨針對數組或對象,而是能夠通用於數組,對象和其他複雜的JSON形式的對象
下面這一招可謂是“一招鮮,吃遍天”

(1).JSON.parse(JSON.stringify(XXXX))
var array = [
    { number: 1 },
    { number: 2 },
    { number: 3 }
];
var copyArray = JSON.parse(JSON.stringify(array))
copyArray[0].number = 100;
console.log(array); //  [{number: 1}, { number: 2 }, { number: 3 }]
console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]

2.手動寫遞歸

var array = [
   { number: 1 },
   { number: 2 },
   { number: 3 }
];
function copy (obj) {
        var newobj = obj.constructor === Array ? [] : {};
        if(typeof obj !== 'object'){
            return;
        }
        for(var i in obj){
           newobj[i] = typeof obj[i] === 'object' ?
           copy(obj[i]) : obj[i];
        }
        return newobj
}
var copyArray = copy(array)
copyArray[0].number = 100;
console.log(array); //  [{number: 1}, { number: 2 }, { number: 3 }]
console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }]
 

存在大量深拷貝需求的代碼——immutable提供的解決方案

實際上,即使我們知道了如何在各種情況下進行深拷貝,我們也仍然面臨一些問題: 深拷貝實際上是很消耗性能的。(我們可能只是希望改變新數組裏的其中一個元素的時候不影響原數組,但卻被迫要把整個原數組都拷貝一遍,這不是一種浪費嗎?)所以,當你的項目裏有大量深拷貝需求的時候,性能就可能形成了一個制約的瓶頸了。

immutable的作用:

通過immutable引入的一套API,實現:

1.在改變新的數組(對象)的時候,不改變原數組(對象)

2.在大量深拷貝操作中顯著地減少性能消耗

const { Map } = require('immutable')
const map1 = Map({ a: 1, b: 2, c: 3 })
const map2 = map1.set('b', 50)
map1.get('b') // 2
map2.get('b') // 50

十二、call() 和 apply() 的區別和作用?

區別:apply()與call()作用沒有區別,用法與call()方法稍有區別,就是call()的第二個參數(調用函數使用的參數),是一個一個傳入的;而apply()的第二個參數的值是使用數組的形式傳入的
作用:在Javascript中,每個函數都包含兩個非繼承而來的方法,call和apply。這兩個方法的用途都是在特定的作用域中調用函數,實際上等於設置函數體內的this對象的值。
 
apply方法接收兩個參數,第一個參數是在其中運行函數的作用域,第二個是一個參數數組或者arguments對象。
call方法與apply方法作用相同,第一個參數也相同,區別在於,其餘的參數需要逐個列出。
 
apply(thisArg, argArray);
call(thisArg[,arg1,arg2…]);
 
是使用call還是apply要看具體的情況。如果你知道所有參數或者參數的數量不多,可以使用call;
如果參數的數量不確定,或者數量很大,或者你收到的是一個數組或者是個arguments對象,則需要使用apply。

十三、localStorage sessionStorage Cookie
共同點:都是保存在瀏覽器端,且同源的。
不同點:
webstorage是本地存儲,存儲在客戶端,包括localStorage和sessionStorage。

localStorage:localStorage生命週期是永久,這意味着除非用戶顯示在瀏覽器提供的UI上清除 localStorage信息,否則這些信息將永遠存在。存放數據大小爲一般爲5MB,而且它僅在客戶端(即瀏覽器)中保存,不參與和服務器的通信。

sessionStorage:sessionStorage僅在當前會話下有效,關閉頁面或瀏覽器後被清除。存放數據大小爲一般爲5MB,而且它僅在客戶端(即瀏覽器)中保存,不參與和服務器的通信。源生接口可以接受,亦可再次封裝來對Object和Array有更好的支持。

localStorage和sessionStorage使用時使用相同的API:

	localStorage.setItem("key","value");//以“key”爲名稱存儲一個值“value”
    localStorage.getItem("key");//獲取名稱爲“key”的值
    localStorage.removeItem("key");//刪除名稱爲“key”的信息。
    localStorage.clear();​//清空localStorage中所有信息

作用域不同:
不同瀏覽器無法共享localStorage或sessionStorage中的信息。相同瀏覽器的不同頁面間可以共享相同的 localStorage(頁面屬於相同域名和端口),但是不同頁面或標籤頁間無法共享sessionStorage的信息。這裏需要注意的是,頁面及標 籤頁僅指頂級窗口,如果一個標籤頁包含多個iframe標籤且他們屬於同源頁面,那麼他們之間是可以共享sessionStorage的。

Cookie
生命期爲只在設置的cookie過期時間之前一直有效,即使窗口或瀏覽器關閉。 存放數據大小爲4K左右 。有個數限制(各瀏覽器不同)。與服務器端通信:每次都會攜帶在HTTP頭中,如果使用cookie保存過多數據會帶來性能問題。但Cookie需要程序員自己封裝,源生的Cookie接口不友好。

//Cookie方法
<script src="../js/cookie.js"></script>//Cookie函數自己封裝引入
function haxi(){
        if(getCookie("isClose")){             
            $(".header").hide();
        }else{
            $(".header").show();
        }
        
        $(".close").click(function(){
            $(".header").fadeOut(1000);

            setCookie("isClose", "1","s10");
        })
    }
    haxi();

cookie的優點:具有極高的擴展性和可用性
1.通過良好的編程,控制保存在cookie中的session對象的大小。
2.通過加密和安全傳輸技術,減少cookie被破解的可能性。
3.只有在cookie中存放不敏感的數據,即使被盜取也不會有很大的損失。
4.控制cookie的生命期,使之不會永遠有效。這樣的話偷盜者很可能拿到的就 是一個過期的cookie。

cookie的缺點:
1.cookie的長度和數量的限制。每個domain最多只能有20條cookie,每個cookie長度不能超過4KB。否則會被截掉。
2.安全性問題。如果cookie被人攔掉了,那個人就可以獲取到所有session信息。加密的話也不起什麼作用。
3.有些狀態不可能保存在客戶端。例如,爲了防止重複提交表單,我們需要在服務端保存一個計數器。若吧計數器保存在客戶端,則起不到什麼作用。

瀏覽器允許每個域名所包含的cookie數
Microsoft指出InternetExplorer8增加cookie限制爲每個域名50個,但IE7似乎也允許每個域名50個cookie。
Firefox每個域名cookie限制爲50個。
Opera每個域名cookie限制爲30個。
Safari/WebKit貌似沒有cookie限制。但是如果cookie很多,則會使header大小超過服務器的處理的限制,會導致錯誤發生。
注:“每個域名cookie限制爲20個”將不再正確!

當很多的cookie被設置,瀏覽器如何去響應。
除Safari(可以設置全部cookie,不管數量多少),有兩個方法:
  最少最近使用(leastrecentlyused(LRU))的方法:當Cookie已達到限額,自動踢除最老的Cookie,以使給最新的Cookie一些空間。Internet Explorer和Opera使用此方法。

Firefox很獨特:雖然最後的設置的Cookie始終保留,但似乎隨機決定哪些cookie被保留。似乎沒有任何計劃(建議:在Firefox中不要超過Cookie限制)。

不同瀏覽器間cookie總大小也不同:
 Firefox和Safari允許cookie多達4097個字節,包括名(name)、值(value)和等號。
 Opera允許cookie多達4096個字節,包括:名(name)、值(value)和等號。
 Internet Explorer允許cookie多達4095個字節,包括:名(name)、值(value)和等號。
注:多字節字符計算爲兩個字節。在所有瀏覽器中,任何cookie大小超過限制都被忽略,且永遠不會被設置。

十三、事件機制(太多 百度)

十四、setTimeout機制(推薦:https://www.jianshu.com/p/3e482748369d?from=groupmessage)

十五、遇到過兼容性問題嗎,怎麼處理的
1、內外邊距(初始化樣式或normalize css)
2、圖片默認有間距(display:block/float)
3、標籤最低高度設置min-height不兼容(min-height:200px; height:auto !important; height:200px; overflow:visible;)
4、chrome中文界面下默認會將小於12px的文本強制按照12px顯示 (添加css屬性-webkit-text-size-adjust:none;)
5、一些移動端設備不支持vedio和audio的自動播放(
document.addEventListener(‘touchstart’,function() {
document.getElementsByTagName(‘audio’)[0].play();
document.getElementsByTagName(‘audio’)[0].pause();
});)
6、IE5-IE8不支持opacity(
Opacity:0.8;
Filter:alpha(opacity=80);
-ms-filter:”progid:DXImageTransform.Microsoft.Alpha(opacity=80)”;)

7、Firefox點擊鏈接出現的虛線框(a{outline:none;} a:focus{outline:none;})

8、css3種hack

參考部分面試題目或答案,如有遺漏,請私信補充。
https://blog.csdn.net/zhang6223284/article/details/81273180
https://blog.csdn.net/qq_39207948/article/details/81067482

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章