一,cookie 和session 的區別:
1、cookie數據存放在客戶的瀏覽器上,session數據放在服務器上。
2、cookie不是很安全,別人可以分析存放在本地的cookie並進行cookie,欺騙考慮到安全應當使用session。
3、session會在一定時間內保存在服務器上。當訪問增多,會比較佔用你服務器的性能 考慮到減輕服務器性能方面,應當使用cookie。
4、單個cookie保存的數據不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。
5、所以個人建議: 將登陸信息等重要信息存放爲cookie其他信息如果需要保留,以放在cookie中
二,說一下js強制轉換隱式類型轉換
強制轉換:parseInt(),parseFloat() ,String(),Number(),Boolean()
隱式轉換:隱式轉換通常發生在運算符加減乘除,等於,還有小於,大於等
三,call apply bind區別
call、apply、bind的作用是改變函數運行時this的指向
call和apply :
二者的作用完全一樣,只是接受參數的方式不太一樣,參數 1 是 this ,all 需要把參數按順序傳遞進去,而 apply 則是把參數放在數組裏,若第一個參數爲 null 那麼函數中的 this 指向 windowb
bind :
bind()方法會創建一個新函數,稱爲綁定函數,當調用這個綁定函數時,綁定函數會以創建它時傳入 bind()方法的第一個參數作爲 this,傳入 bind() 方法的第二個以及以後的參數加上綁定函數運行時本身的參數按照順序作爲原函數的參數來調用原函數
四,JavaScript 原型,原型鏈? 有什麼特點?
- 每一個對象都有一個__proto__ 屬性,該屬性對應該對象的原型.
- 所有的函數對象都有prototype屬性,該屬性的值會被賦值給該函數創建的對象的_proto_屬性.
- 所有的原型對象都有constructor屬性,該屬性對應創建所有指向該原型的實例的構造函數.
- 函數對象和原型對象通過prototype和constructor屬性進行相互關聯.
五,說說你對this的理解
在JavaScript中,this通常指向的是我們正在執行函數本身,或者是指向函數所屬的對象
- 普通函數的this指向window
- 構造函數中this是當前實例對象
- 對象中的this是指向其本身
- 原型對象的方法中this是當前的實例對象
- 定時器中this指向window
- 事件處理函數的this是觸發該事件的對象
六,js中的遞歸函數是什麼
遞歸是程序執行過程中不斷調用自身的編程技巧,當然也必須有一個明確的結束條件,不然就會陷入死循環
七, 什麼是閉包,閉包有什麼優缺點,有哪些應用場景
閉包就是能讀取其他函數內部變量的函數,由於在JavaScript中,只有函數內部的子函數才能讀取局部變量,所有所閉包可以理解爲“定義在函數內部的函數”,所以本質上,閉包是將函數內部和函數外部鏈接起來的橋樑
優點:
閉包可以用在很多地方,它的最大用處有兩個,一個是可以讀取函數內部的變量,另一個是可以讓變量的值始終保持在內存中不被GC清除掉
缺點:
由於閉包會使得函數中的變量都被保存在內存中,內存消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致內存泄露。解決方法是,在退出函數之前,將不使用的局部變量全部刪除。
使用場景
(1)採用函數引用方式的setTimeout調用。
(2)將函數關聯到對象的實例方法。
(3)封裝相關的功能集。
八 ,說一下你對垃圾回收(GC)的理解
Js具有自動垃圾回收機制。垃圾收集器會按照固定的時間間隔週期性的執行。
工作原理:是當變量進入環境時,將這個變量標記爲“進入環境”。當變量離開環境時,則將其標記爲“離開環境”。標記“離開環境”的就回收內存。
標記清除
-
垃圾回收器,在運行的時候會給存儲在內存中的所有變量都加上標記。
-
去掉環境中的變量以及被環境中的變量引用的變量的標記。
-
再被加上標記的會被視爲準備刪除的變量。
-
垃圾回收器完成內存清除工作,銷燬那些帶標記的值並回收他們所佔用的內存空間。
引用計數
-
聲明瞭一個變量並將一個引用類型的值賦值給這個變量,這個引用類型值的引用次數就是1。
-
同一個值又被賦值給另一個變量,這個引用類型值的引用次數加1.
-
當包含這個引用類型值的變量又被賦值成另一個值了,那麼這個引用類型值的引用次數減1.
-
當引用次數變成0時,說明沒辦法訪問這個值了。
-
當垃圾收集器下一次運行時,它就會釋放引用次數是0的值所佔的內存。
九,什麼情況會引起內存泄漏?
雖然有垃圾回收機制但是我們編寫代碼操作不當還是會造成內存泄漏。
- 意外的全局變量引起的內存泄漏。
原因:全局變量,不會被回收。
解決:使用嚴格模式避免。
- 閉包引起的內存泄漏
原因:閉包可以維持函數內局部變量,使其得不到釋放。
解決:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中,刪除對dom的引用。
- 沒有清理的DOM元素引用
原因:雖然別的地方刪除了,但是對象中還存在對dom的引用
解決:手動刪除。
- 被遺忘的定時器或者回調
原因:定時器中有dom的引用,即使dom刪除了,但是定時器還在,所以內存中還是有這個dom。
解決:手動刪除定時器和dom。
- 子元素存在引用引起的內存泄漏
原因:div中的ul li 得到這個div,會間接引用某個得到的li,那麼此時因爲div間接引用li,即使li被清空,也還是在內存中,並且只要li不被刪除,他的父元素都不會被刪除。
十,棧和堆的區別
一、堆棧空間分配區別:
1、棧(操作系統):由操作系統自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧;
2、堆(操作系統): 一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收,分配方式倒是類似於鏈表。
二、堆棧緩存方式區別:
1、棧使用的是一級緩存, 他們通常都是被調用時處於存儲空間中,調用完畢立即釋放;
2、堆是存放在二級緩存中,生命週期由虛擬機的垃圾回收算法來決定(並不是一旦成爲孤兒對象就能被回收)。所以調用這些對象的速度要相對來得低一些。
三、堆棧數據結構區別:
堆(數據結構):堆可以被看成是一棵樹,如:堆排序;
棧(數據結構):一種先進後出的數據結構。
十一,數組和對象有哪些原生方式,列舉一下
1.Array.concat() //數組拼接
2.Array.push() //向數組尾部添加元素
3.Array.pop() //從數組尾部刪除元素
4.Array.shift() //從數組頭部刪除元素
5.Array.unshift() //向數組頭部刪除元素
6.Array.slice() //返回數組的一部分
7.Array.splice() //插入,刪除或替換元素
8.Array.reverse() //顛倒數組中元素的順序數羊戰隊
9.Array.sort() //對數組進行排序
10.Array.toString() //將數組轉換成一個字符串
11.Array.valueOf() //
12.Array.join() //將數組元素連接起來以構建一個字
13.Array.length() //數組的長度
14.Array.toLocalString() //把數組轉換成局部字符串
十二,es6中有哪些新特性,列舉一下
1.變量聲明:const 常量和let 塊級作用域
2.模板字符串 用反引號(`)標識,它可以當作普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量。
3.箭頭函數
4 函數的參數默認值 剩餘參數
5 解構賦值
6.二進制和八進制字面量
7.對象和數組解構
8.ES6中的類 ES6 中支持 class 語法,不過,ES6的class不是新的對象繼承模型,它只是原型鏈的語法糖表現形式。
9.for…of 和 for…in 10.ES6中的類
十三 ,get和post得區別有哪些
1、get參數在url是可見的;post,url參數不可見
2、數據傳輸上:get,通過拼接url進行傳遞參數; post則通過body體傳輸參數
3、緩存性: get請求是可以緩存的 post請求不可以緩存
4、後退頁面的反應 get請求頁面後退時,不產生影響 post請求頁面後退時,會重新提交請求
5、傳輸數據的大小 get一般傳輸數據大小不超過2k-4k(根據瀏覽器不同,限制不一樣,但相差不大)post請求傳輸數據的大小根據php.ini 配置文件設定,也可以無限大。
6、在安全性 上 post比get要安全,因爲傳輸參數時url post是不可見
十四,事件冒泡和事件委託
事件冒泡:當一個元素上的事件被觸發的時候,比如說鼠標點擊了一個按鈕,同樣的事件將會在那個元素的所有祖先元素中被觸發. 這一過程被稱爲事件冒泡;這個事件從原始元素開始一直冒泡到 DOM 樹的最上層.
阻止事件冒泡和捕獲: 標準瀏覽器 e. stopPropagation(); IE9 之前 event.canceBubble=true;
阻止默認事件: 爲了不讓 a 點擊之後跳轉,我們就要給他的點擊事件進行阻止return false; e.preventDefault();
事件委託:讓利用事件冒泡的原理讓自己的所觸發的事件讓他的父元素代替執行!
十五,JavaScript的本地對象,內置對象,宿主對象
本地對象:本地對象爲array,obj,regexp等都可以用new實例化
內置對象:爲 Global、Math 等不可以實例化的(也是本地對象,Global 不存在,但是類似於 isNaN()、parseInt()和 parseFloat()方
法都是他的方法)
宿主對象爲瀏覽器提供的對象,所有的 BOM 和 DOM,如 document,window
十六,JavaScript如何實現繼承
原型鏈繼承 借用構造函數繼承 組合繼承 寄生式繼承 動態原型方式
十七,JavaScript創建對象的幾種方式
工廠方式,構造函數方式 原型模式 混合構造函數模式 動態原型方式
十八函數作爲普通函數和構造函數的區別
1、用new關鍵字調用
2、普通函數的this指向window ,構造函數,this指向的是構造出的新對象。
3、默認不用return返回值
構造函數是不需要用return顯示返回值,默認會返回this,也就是新的實例對象。當然,也可以用return語句,返回值會根據return值的類型而有所不同。
4、函數命名建議首個字母大寫,與普通函數區分開。不是命名規範,但是建議這麼寫。
十九 ,你是如何優化自己的代碼?
1 代碼重用
2 避免使用全局變量
3 拆分函數避免函數過於臃腫(單一職責原則)
4 適當的代碼註釋
5 內存管理,對閉包中的變量釋放
二十,什麼是三次握手,四次揮手?
三次握手
第一次握手:主機A發送同步報文段(SYN)請求建立連接。
第二次握手:主機B聽到連接請求,就將該連接放入內核等待隊列當中,並向主機A發送針對SYN的確認ACK,同時主機B也發送自己的請求建立連接(SYN)。
第三次握手:主機A針對主機BSYN的確認應答ACK。
四次揮手
第一次揮手:當主機A發送數據完畢後,發送FIN結束報文段。
第二次揮手:主機B收到FIN報文段後,向主機A發送一個確認序號ACK(爲了防止在這段時間內,對方重傳FIN報文段)。
第三次揮手:主機B準備關閉連接,向主機A發送一個FIN結束報文段。
第四次揮手:主機A收到FIN結束報文段後,進入TIME_WAIT狀態。並向主機B發送一個ACK表示連接徹底釋放。
對三次握手的通俗理解
第一次握手:客戶端發送網絡包,服務器接收到了,這樣服務器得出結論:客戶端的發送能力正常,服務器的接收能力正常
第二次握手:服務器發包,客戶端收到了,這樣客戶端就能得出結論:服務端的接收、發送能力,客戶端的接收、發送能力是正常的
第三次握手:客戶端發包,服務端收到了。這樣服務端就能得出結論:客戶端的接收、發送能力,服務端的發送、接收能力是正常的。
對 四次揮手的通俗理解
第一次揮手:雙方交流的差不多了,此時客戶端也已經結尾了,接下來要斷開通信連接,所以告訴服務端“我說完了(FIN)”,此時自身形成等待結束連接的狀態。
第二次揮手:服務端知道客戶端已經沒話說了,服務端此時還有兩句心裏話要給客戶端說,“我知道你說完了(ACK),我再給你說兩句,&*……%¥”。
第三次揮手:此時客戶端洗耳恭聽繼續處於等待結束的狀態,服務器端也說完了,自身此時處於等待關閉連接的狀態,並對告訴客戶端,“我說完了,咱們斷了吧(FIN)”。
第四次揮手:客戶端收知道服務端也說完了,也要告訴服務端一聲(ACK),因爲連接和斷開要雙方都按下關閉操作才能斷開,客戶端同時又爲自己定義一個定時器,因爲不知道剛纔說的這句話能不能準確到達服務端(網絡不穩定或者其他因素引起的網絡原因),默認時間定爲兩個通信的最大時間之和,超出這個時間就默認服務器端已經接收到了自己的確認信息,此時客戶端就關閉自身連接,服務器端一旦接收到客戶端發來的確定通知就立刻關閉服務器端的連接。
到此爲止雙方整個通信過程就此終結。這裏要聲明一下:斷開鏈接不一定就是客戶端,誰都可以先發起斷開指令,另外客戶端和服務端是沒有固定標準的,誰先發起請求誰就是客戶端。
二十一 ,http常見狀態碼
狀態 | 意義 |
---|---|
1**信息 | 服務器收到請求,需要請求者繼續執行操作 |
2**成功 | 操作被成功接收並處理 |
3**重定向 | 需要進一步的操作以完成請求 |
4**客戶端錯誤 | 請求包含語法錯誤或無法完成請求 |
5**服務器錯誤 | 服務器在處理請求的過程中發生了錯誤 |
常見狀態碼 https://cloud.tencent.com/developer/news/7987
二十二,跨域問題
所謂跨域
就是跨域名,跨端口,跨協議
所謂同源
就是同域名,同端口,同協議
跨域解決方案
1、 通過jsonp跨域
2、 document.domain + iframe跨域
3、 location.hash + iframe
4、 window.name + iframe跨域
5、 postMessage跨域
6、 跨域資源共享(CORS)
7、 nginx代理跨域
8、 nodejs中間件代理跨域
9、 WebSocket協議跨域
前端常見跨域解決方案(全)https://segmentfault.com/a/1190000011145364
二十三,JavaScript淺拷貝(Shallow Copy) VS 深拷貝(Deep Copy)
淺拷貝:
1、ES6:object.assign()
var a = { name : “hello” };
var b = Object.assign( { },a );
b.name = “hi”;
console.log(a);
2、展開運算符……
var a = { name : “hello” };
var b = { …a}; =>
擴展運算符用三個點號表示,功能是把數組或類數組對象展開成一系列用逗號隔開的值
b.name = “hi”;
console.log(a);
3、自己封裝函數實現for in
var a = { name : “hello” };
var b = copy(a);
b.name = ‘hi’;
console.log(a);
function copy(obj){
var result = { };
for(var attr in obj ){
result [attr] = obj[attr];
}
return result;
}
深拷貝
1,利用window.JSON的方法做深拷貝
缺點:
如果你的對象裏有函數,函數無法被拷貝下來
無法拷貝copyObj對象原型鏈上的屬性和方法
var copyObj = {
name: 'ziwei',
arr : [1,2,3]
}
var targetObj = JSON.parse(JSON.stringify(copyObj))
此時 copyObj.arr !== targetObj.arr 已經實現了深拷貝
2 已封裝函數與實現for in +遞歸
var a = { name: { age: 20 } };//要拷貝的對象
var b = deepcopy(a);//調用封裝好的深拷貝方法
b.name.age = 30;
console.log(a);
function deepcopy(obj) {
var result = {};
for (var attr in obj) { //循環
if (typeof obj[attr] === 'object') {//如果對象的屬性和方法是對象時
result[attr] = deepcopy(obj[attr]);//遞歸
} else {
result[attr] = obj[attr];
}
}
return result;
}
3,通過jQuery的extend方法實現深拷貝
var array = [1,2,3,4];
var newArray = $.extend(true,[],array);
二十四,數組去重
- 雙重for循環
- indexOf
- filter
- ES6的set
//set
function unique (arr) {
return Array.from(new Set(arr))
}
詳細參考:https://segmentfault.com/a/1190000016418021
二十五,箭頭函數與普通函數的區別
- 箭頭函數沒有自己的this,繼承的是外層代碼塊的this。
- 不可以當做構造函數,也就是說不可以使用new命令,否則會報錯的。
- 不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替。
- 不可以使用yield命令,因此箭頭函數不能用作 Generator(生成器) 函數。
- 因爲沒有this,所以不能使用call、bind、apply來改變this的指向。