1、JS的基本數據類型和引用數據類型有哪些,兩者區別
基本數據類型->string、number、Boolean、null、undefined、symbol
引用數據類型->array、object、function
基本數據類型是保存在棧內存中,操作的是值,改變源數據不會影響新的變量
引用數據類型保存在堆內存中,操作的是地址,改變其中一個會影響另一個
2、數據類型中為假的有哪些?
false (布爾型)
0(數值型)
null(定義空的或者不存在,現在沒有,將來可能有)
undefined(未定義,一直不存在)
NaN(不是一個有效數字)
空字符串(空字符串,字符類型)
3、舉例JavaScript的基本規范,以及如何編寫高性能代碼
基本規范
1)代碼縮進,建議使用“四個空格”縮進
2)語句結束使用分號
3)變量和函數在使用前進行聲明
4)以大寫字母開頭命名構造函數,全大寫命名常量
5)使用ID最好先獲取一下
6)規范定義JSON對象,補全雙引號
1)遵循嚴格模式:"use strict";
2)將js腳本放在頁面底部,加快渲染頁面
3)盡量減少使用閉包
4)盡量使用直接量創建對象和數組
5)盡量減少對象成員嵌套
6)最小化重繪(repaint)和回流(reflow)
4、JS有哪些內置對象
Object、Array、Boolean、Number、String、Function、Arguments、Math、Date、RegExp
ES6新增對象:Symbol、Map、Set、Promises、Proxy
5、怎么實現string和number的相互轉換
String 轉換成 Number:Number()、parseInt()、parseFloat()
Number 轉換成 String:String()、toString()
6、怎么創建、添加、替換、克隆、刪除元素
創建-> document.createElement('標簽名')
添加-> parent.appendChild()
parent.insertBefore(新插入的元素,老元素)
替換-> replaceChild(new,old)
克隆-> cloneChild()
刪除->removeChild()
7、什么情況下會轉為字符串
1)基於alert、confirm、document.write等輸出內容時,會先把值轉為字符串后在輸出
2)基於'+'進行字符串拼接時
3)把復合類型值轉換數字時候。首先會轉換字符串然后再轉為數字
4)給對象設置屬性名時候,如果不是字符串 先轉為字符串,然后在作為屬性存儲到對象中(對象屬性只能是字符串和數字)
5)手動調用toString、toFixed(將 Number 四舍五入為指定小數位數的數字)、join、String方法時候,也是為了轉換字符串
8、獲取對象屬性[]和.的區別
.后面的是這個對象的屬性,凡是用.的地方都可以用[]
[]中括號的內容可以是字符串也可以是變量,基本上[]放的是變量
9、null和undefined的區別
Null:代表空對象指針。現在沒有,將來可能會有
undefined:空,未定義。現在沒有,將來也不會有(Js中獨有的數據類型)
10、檢測數據類型的幾種方式,以及他們的對比
typeof、instanceof、constructor、Object.prototype.toString.call()
typeof只針對基本數據類型,遇到引用數據類型是不起作用的(無法細分對象)
instanceof用來判斷對象和函數,不適合判斷字符串和數字
constructor是Object其中的一個屬性。默認指向實例的構造函數
通過Object.prototype.toString方法,判斷某個對象值屬於哪種內置類型
11、in 與 hasOwnProperty
兩者都代表查看某個屬性是不是自己的
in判斷的是對象的所有屬性,包括對象實例及其原型的屬性
hasOwnProperty則是判斷對象實例的是否具有某個屬性
12、innerHTML和innerText區別
innerHTML可以獲取結構和文本
innerText只獲取文本內容
13、如何清除一個定時器?
clearTimeout(timer)
14、說一下倒計時原理及公式
未來時間-現在時間= 剩余時間
let d = Math.floor(t/86400);
t % =86400;
let h = Math.floor(t/3600);
t % = 3600;
let m = Math.floor(t/60);
t % = 60;
15、何時使用 === 何時使用 ==
判斷對象的屬性是否存在可以使用雙等,其余都用全等
===更嚴謹,不僅值相等類型也要相等,不用進行類型轉換,並且比==速度快
16、eval 是做什么的?
它的功能是把對應的字符串解析成JS代碼並運行
由JSON字符串轉換為JSON對象的時候可以用 eval('('+ str +')');
應避免使用eval,因為不安全,耗性能
17、數組常用的一些方法有哪些
push()向數組末尾添加數據
pop()刪除數組最后一項
unshift()向數組首位添加新內容
shift()刪除數組的第一項
slice()按照條件查找出其中的部分內容
splice()對數組進行增刪改
join()用指定的分隔符對數組拼接
concat()用於連接兩個或多個數組
indexOf()/lastIndexOf()當前值在數組中第一次/最后一次出現的位置索引
includes()判斷一個數組是否包含指定的值
sort()對數組進行排序
reverse()把數組倒過來排列
forEach()循環遍歷數組每一項
18、說一下什么是DOM映射機制
通過DOM中方法獲取到的元素,與頁面一一對應的這種關系稱之為DOM映射
querySelectorAll獲取到的元素集合沒有DOM映射,必須是元素的內置屬性發生變化,瀏覽器才能監聽得到
19、一行代碼實現數組去重
[...new Set([1,2,3,4])]
20、節點類型都有哪些,如何判斷當前節點類型
1元素節點,2屬性節點,3文本節點,8注釋節點、9文檔節點
通過nodeObject.nodeType判斷節點類型,其中,nodeObject為節點對象
該屬性返回以數字表示的節點類型,例如,元素節點返回1,屬性節點返回2
21、重繪和回流(重排)區別,什么情況會觸發重排和重繪
當頁面元素(寬高,位置)發生改變,回導致頁面重排,瀏覽器會根據新位置進行重新渲染
回流必將引起重繪,而重繪不一定會引起回流。重繪相對於回流性能消耗較低
任何改變用來構建渲染樹的信息都會導致一次重排或重繪
比如添加、刪除、更新DOM節點,通過display: none隱藏,調整樣式屬性,調整窗口大小,滾動等等
22、如何最小化重繪(repaint)和回流(reflow)
1)需要對元素進行復雜的操作時,可以先display:none隱藏,操作完再顯示
2)需要創建多個DOM節點時,使用DocumentFragment創建完后一次性的加入document
3)盡量避免用table布局
4)避免使用css表達式(expression),每次調用都會重新計算值(包括加載頁面)
5)盡量使用css簡寫,如:用border代替border-width,border-style, border-color
23、什么是自執行函數,用於什么場景
自執行函數,即定義和調用合為一體,比如匿名函數自執行
他可以創建一個獨立作用域,防止作用域污染,防止變量影響到全局,以免產生沖突
多用於框架和插件
24、改變this指向的方法
call、apply、bind
call和apply可以自動執行,bind需要手動調用,返回值為函數
call和bind都有無數個參數,apply只有兩個參數,並且第二個為數組
25、iframe的優缺點
優點:
1)iframe能夠原封不動的把嵌入的網頁展現出來
2)頭部和底部一樣時可以寫成一個頁面,用iframe來嵌套,可以增加代碼的可重用
3)引用多個頁面,只需要修改iframe的內容,就可以實現頁面內容的更改
缺點:
不容易管理、用戶體驗度差、不利於搜索引擎優化、兼容性差、增加服務器的http請求,一般用Ajax來代替iframe
26、類數組轉數組的方法
Array.from
Array.prototype.slice.call
[].slice.call
27、請解釋什么是暫時性死區
let 和 const 聲明的變量不存在變量提升,其作用域都是塊級作用域,凡是在聲明變量之前使用變量就會報錯,
所以,在代碼塊內,使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱為“暫時性死區”
28、嚴格模式與非嚴格模式的區別
非嚴格模式又被被稱為懶散模式
嚴格模式 use strict是一種ECMAscript 5添加的運行模式,這種模式使得 Js在更嚴格的條件下運行,使JS編碼更加規范化
消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為。
嚴格模式中變量必須顯示聲明
在嚴格模式下,arguments和eval是關鍵字,不能被修改
在嚴格模式下,函數的形參也不可以同名
29、驗證手機號碼和郵箱的正則表達式
手機號碼驗證
/^(13[0-9]|14[5-9]|15[012356789]|166|17[0-8]|18[0-9]|19[8-9])[0-9]{8}$/
郵箱驗證
^[A-Za-z]\w{3,17}@[1-9A-Za-z]{2,8}\.(com|cn|net)$
30、window 和document常見的方法和屬性
Window對象常見的屬性:
top 代表當前所有窗口的最頂層窗口
parent 指當前窗口的父窗口
self 指當前窗口
status 指定當前窗口狀態欄中的信息
Window對象常見的方法:
alert 顯示帶有一個“確定”按鈕的對話框
confirm 顯示帶有“確定”和“取消”兩個按鈕的對話框
open 打開一個新的窗口
close 關閉用戶打開的窗口
Document常見屬性:
title 設置文檔標題,也就是html的標簽
bgColor 設置頁面的背景色
URL 設置url屬性
fileSize 文件大小
Document常見的方法:
write() 動態向頁面寫入內容
createElement(Tag) 創建一個HTML標簽
getElementById(ID) 獲得指定id的對象
getElementsByName(Name) 獲得之前Name的對象
31、如何添加HTML元素的事件,有幾種方法
標簽之中直接添加 onclick="fn()"
JS添加 btn.onclick = method
綁定事件 obj.addEventListener('click', method, false)
32、使用js去除字符串空格
str.trim()
使用replace正則匹配:str.replace(/\s*/g,"")
33、什么是閉包,有什么優缺點
在Js中當函數套函數,子函數使用了父函數的參數或者變量,並且子函數被外界所使用(沒有釋放),
此時父函數的參數和變量,是不會被瀏覽器垃圾回收機制立馬收回,這個時候父級形成了閉包環境。
function fn(){ let a = 10; return function(){ console.log(a); } } let f = fn(); console.dir(f);// 控制台中的closure就代表閉包
優點:
保護—閉包會形成私有作用域,保護里面的私有變量不受外界干擾
存儲—閉包可以把父函數的參數或變量存儲起來
缺點:
相對於普通函數要消耗內存,閉包使用不當將會在IE(IE9之前)中造成內存泄漏
34、理解的JavaScript垃圾回收機制
Js具有自動垃圾回收機制。垃圾收集器會按照固定的時間間隔周期性的執行
垃圾回收機制主要有兩種方法:
1、標記清除法
打開頁面時,先把所有的變量打上標記,然后把被使用的變量清除標記。如果下次查詢之前標記的沒有被引用,此時就回收
2、引用計數法
變量每用一次就記錄一次,一開始為0,下次引用+1,每少用一次就-1。當變為0時候 就清空回收
直接給變量賦值一個null的地址可以解決閉包消耗的內存
35、什么情況會引起內存泄漏,產生原因及解決方案?
1)意外的全局變量引起的內存泄漏
原因:全局變量,不會被回收
解決:可以使用嚴格模式避免
2)閉包引起的內存泄漏
原因:閉包可以維持函數內局部變量,使其得不到釋放
解決:將事件處理函數定義在外部,解除閉包,或者在定義事件處理函數的外部函數中,刪除對dom的引用
3)沒有清理的DOM元素引用
原因:雖然別的地方刪除了,但是對象中還存在對dom的引用
解決:手動刪除即可
4) 忘記的定時器或者回調
原因:定時器中有dom的引用,即使dom刪除了,但是定時器還在
解決:手動清除定時器和dom
36、什么是原型,什么是原型鏈,兩者關系
原型(prototype):函數自帶的屬性,函數的實例化對象找不到某個屬性或者方法,一定會去構造函數的原型下去找
原型鏈(__proto__):實例化對象身上自帶一個屬性
原型關系鏈:函數的實例化對象找不到某個屬性或方法,一定會去構造函數的原型下去找,如果還沒有會去原型下的原型鏈查找,直到找到Object.prototype為止
兩者關系:實例化對象的原型鏈 === 構造函數的原型
37、如何合並兩個數組
//第一種 var arr1=[1,2,3]; var arr2=[4,5,6]; arr1 = arr1.concat(arr2); console.log(arr1); //第二種 var arr1=[1,2,3]; ar arr2=[4,5,6]; Array.prototype.push.apply(arr1,arr2); console.log(arr1);
38、簡述this出現的情況
1)全局下的this是window
2)單純的函數名+括號執行,this是window
3)匿名函數自執行,this是window
4)定時器中的this是window
5)事件觸發,觸發誰this就是誰
6)對象方法中,.前面是誰 this就指向誰
7)構造函數中this是實例化對象
8)嚴格模式下this是undefined
9)箭頭函數中this指向上一級
10)箭頭函數中this暴露在外面就指向window
39、函數聲明和函數表達式的區別
fn() //不會報錯 function fn(){ //聲明 } fn1() //會報錯:fn1 is not a function var a = function(){ //表達式 }
40、說一下對變量提升的理解
在某一作用域中,聲明變量的語句會默認解析,在該作用域的最開始就已經聲明了
41、Js有哪些解決異步的方案
1)callback 回調函數
2)promise
3)事件監聽
4)async await
42、new之后發生了什么
使用new之后不用加括號一樣會執行函數
new之后this變為實例化對象
默認返回值就不是undefined而是實例化對象
寫了return,如果return后面是簡單類型,返回結果依然是實例化對象,如果是復合類型,返回結果則是這個復合類型
43、寫一個原生的xhr請求過程,readystate的幾種狀態 分別什么含義?
let xhr = new XMLHttpRequest(); xhr.open('get','./package.json'); xhr.onreadystatechange = function () { if(xhr.readyState == 4 && xhr.status == 200) { let result = JSON.parse(xhr.responseText); console.log(result.name) } }; xhr.send()
readyState的幾種狀態
0:請求未初始化(此時還沒有調用open)
1:服務器連接已建立,已經發送請求開始監聽
2:請求已接收,已經收到服務器返回的內容
3:請求處理中,解析服務器響應內容
4:請求已完成,且響應就緒
44、什么是作用域、作用域鏈
作用域分為全局作用域、局部作用域(包括es6新增塊級作用域)
簡單理解作用域就是一個獨立的空間,讓變量不會暴露。不同作用域下同名變量不會沖突
當前作用域未定義的變量(自由變量)會向父級作用域查找,如果父級沒有再一層層往上找,直到全局作用域,這種一層層的關系稱為作用域鏈
45、淺拷貝和深拷貝,實現的幾種方式
淺拷貝只復制某個對象的指針,而不復制對象本身,新舊對象還是共享同一塊內存
深拷貝會開辟一個新的棧,新對象跟原對象不共享內存,修改新對象不影響原對象
簡單來說假如B復制了A,當修改A時候B如果跟着改變就是淺拷貝,B沒有改變則為深拷貝
淺拷貝實現方式:
Object.assign()、Array.prototype.concat()、Array.prototype.slice()
深拷貝實現方式:
JSON.parse(JSON.stringify())、手寫遞歸、jquery的$.extend
46、聲明變量和聲明函數的提升有什么區別
變量聲明提升:變量申明在進入執行上下文就完成了
只要變量進行聲明,無論在哪個位置,js引擎都會將它的聲明放在作用域的頂部
函數聲明提升:執行代碼之前會先讀取函數聲明,可以把函數申明放在調用它的語句后面
函數聲明會覆蓋變量聲明,但不會覆蓋變量賦值
47、說一下變量提升機制
關於變量提升:
無論條件成不成立都會先進行預解析
匿名函數不會預解析
es6不存在變量提升
預解析的函數只解析一次(再遇到就會跳過)
變量提升機制:
一、變量提升
1)先找var進行提升,賦值undefined,變量名一樣,后者覆蓋前者
2)遇見函數,把函數名提升,賦值整個代碼塊
函數名同名,后者覆蓋前面,只看最后一個函數即可
3)變量名與函數名同名情況下,最終留下代碼塊
如果是函數聲明,就只解讀一次,遇到別的直接跳過
函數表達式是帶等號的所以會解讀
二、逐行解讀代碼
只看帶有等號的,如果有賦值,這個變量就是被賦值的值
就算下面有函數聲明也不會繼續看了
48、平時怎么樣進行數據交互?如果后台沒有提供數據怎么進行開發?mock數據與后台返回的格式不統一怎么辦?
由后台編寫接口文檔、提供數據接口實、前台通過ajax訪問實現數據交互;
在沒有數據的情況下尋找后台提供靜態數據或者自己定義mock數據
返回數據不統一時編寫映射文件 對數據進行映射
49、什么是回調函數
回調函數callback,就是一個函數執行完后立刻執行另一個
它與箭頭函數不一樣的是,它會拿返回的值作為參數
50、什么是構造函數?與普通函數有什么區別
構造函數:是一種特殊的方法、主要用來創建對象時初始化對象,總與new運算符一起使用。創建對象的語句中構造函數的函數名必須與類名完全相同
與普通函數相比只能由new關鍵字調用,構造函數是類的標示
51、ajax 和 jsonp區別
相同點:都是請求一個url
不同點:ajax的核心是通過xmlHttpRequest獲取內容
jsonp的核心則是動態添加<script>標簽來調用服務器 提供的js腳本
52、JavaScript 有哪幾種創建對象的方式?
1)對象字面量的方式
2)用function來模擬無參的構造函數
3)用工廠方式來創建(內置對象)
4)用原型方式來創建
53、舉例ES5數組新增的哪些方法
1)forEach() 專門用來遍歷數組
2)map() 將調用的數組中每個元素傳遞給指定的函數,並返回一個新數組
3)filter() 過濾,返回滿足條件的元素組成的新數組
4)every()所有元素滿足條件就返回true,有一個不滿足條件就返回false
5)some()所有元素只要有一個滿足條件就返回true,都不滿足條件就返回false
6)reduce()累加器,數組中的每個值(從左到右)開始縮減,最終計算為一個值
54、獲取隨機數,要求是長度一致的字符串格式
var random = Math.random() + '0000000000'; var random = random.slice(0,10);
55、移動端點擊事件300ms延遲如何去掉,產生原因
產生原因:
移動端會有雙擊縮放的這個操作,因此瀏覽器在click之后要等待300ms,看用戶有沒有下一次點擊(也就是這次操作是不是雙擊)
解決方法:
1)禁用縮放
<meta name="viewport" content="user-scalable=no"> <meta name="viewport" content="initial-scale=1,maximum-scale=1">
2)更改默認的視口寬度
<meta name="viewport" content="width=device-width"/>
3)使用fastClick插件
window.addEventListener( "load", function() { FastClick.attach( document.body ); }, false );
56、let有什么用,有了var為什么還要用let ?
ES6之前,聲明變量只能用var,他有一些不合理的地方。
let聲明的變量擁有自己的塊級作用域,且修復了var聲明變量帶來的變量提升問題
57、請描述一下對事件冒泡、事件捕獲、事件流的理解,怎么阻止冒泡
事件冒泡:就是從目標元素自下而上一直到window(結束)這樣一個過程
事件捕獲:就是從window自上而下一直到目標元素的這樣一個過程
一般是先執行捕獲,后執行冒泡
事件流:當一個事件觸發時候,一般會經歷3個過程,第一個為捕獲階段,第二個為目標階段,第三個為冒泡階段這么一個過程
使用stopPropagation() 和 cancelBubble阻止冒泡
58、什么是事件委托,有什么好處
事件委托又叫事件代理。利用冒泡的原理,把事件加到父級上,觸發執行效果
好處:新添加的元素還會有之前的事件;提高性能
59、拖拽會用到哪些事件?
使用onmousedown、onmousemove、onmouseup來實現
60、什么是移動端點透事件,如何解決
一個元素下有焦點(比如a 、input)在300毫秒之內讓上層元素消失,這時手機會記錄按下的位置並進行監聽(是否觸發兩次)
因為要監聽是否雙擊,在第一次按下時捕捉到了坐標,正好坐標下有焦點元素,此時就會觸發焦點元素
解決方案:
1、在上層元素消失時候延遲執行
2、不使用焦點元素。比如以div代替a
3、在touch事件里面調用e.preventDefault() 進行阻止
61、簡述一下你理解的面向對象
把相同的代碼抽象出來歸為一類,把描述特征的功能掛在這個類的原型上的一種設計編程思想
面向對象具有封裝性,繼承性,多態性。提高了大型程序的重用性和可維護性
62、如何獲取hash,並設置一個hash
window.location.hash
window.location.hash = 'p=0';
63、js延遲加載的方式有哪些
defer和async、動態創建DOM方式、按需異步載入js
64、什么是事件默認行為,如何阻止
當用戶觸發某個事件的時候,某種行為不是我們主動寫的而是瀏覽器默認就有的事件
阻止:
DOME0:return false
DOME1:ev.preventDefault
65、列舉js常用的事件
onmouseover鼠標移入、onmouseout鼠標移出
onmouseenter鼠標穿過、onmouseleave鼠標離開
onmousemove鼠標移動、onmousewheel 鼠標滾輪
onclick點擊、oncontextmenu右擊菜單
onchange改變內容、onfocus獲取焦點、onblur失去焦點
onresize改變窗口、onload加載完成
onkeyup鍵盤抬起、onkeydown鍵盤按下
66、構造函數、原型對象、實例對象三者的關系
三者的關系是,每個構造函數都有一個原型對象,原型對象上包含着一個指向構造函數的指針,而實例都包含着一個指向原型對象的內部指針。
通俗的說,實例可以通過內部指針訪問到原型對象,原型對象可以通過constructor找到構造函數
67、Js中,有一個函數,執行對象查找時,永遠不會去查找原型,這個函數是哪個
hasOwnProperty
該函數方法返回一個布爾值,指出一個對象是否具有指定名稱的屬性。此方法無法檢查該對象的原型鏈中是否具有該屬性;該屬性必須是對象本身的一個成員
68、Canvas和SVG的比較
canvas是一個標簽(canvas)+一個對象(getcontext),所有圖形圖像都靠ctx繪制
SVG幾十個標簽-每個圖形對應一個標簽
canvas位圖技術,可以保存為.png,SVG矢量圖技術,不能保存為位圖
canvas不能被搜索引擎爬蟲所訪問,SVG可以
只能為整個Canvas綁定監聽函數,SVG每個圖形(標簽)都可以綁定事件監聽函數
69、如何規避javascript多人開發函數重名問題
(1) 可以開發前規定命名規范,根據不同開發人員開發的功能在函數前加前綴
(2) 將每個開發人員的函數封裝到類中,調用的時候就調用類的函數,即使函數重名只要類名不重復即可
70、Cookie、Session、WebStorage的區別
cookie:用來保存客戶瀏覽器請求服務器頁面的請求信息,大小4KB
session:是一種服務器端的機制,服務器使用一種類似於散列表的結構來保存信息
WebStorage提供了localStorage、sessionStorage兩種API,大小都在5M
cookie數據存放在客戶的瀏覽器上,session數據放在服務器上
cookie不是很安全,別人可以分析存放在本地的cookie
session會在一定時間內保存在服務器上。當訪問增多,會占用服務器的性能
cookie:可以通過expires設置失效時間,不設置默認關閉瀏覽器即失效
localStorage:除非手動清除,否則永久保存
sessionStorage:僅在當前會話時候生效,關閉頁面即失效
71、什么是柯里化函數
柯里化(Currying)就是把接收多個參數的函數轉換成一個單個參數的函數
並且返回接收余下的參數。返回結果是一個新函數
函數柯里化的主要作用和特點是參數復用、提前返回和延遲執行
72、如何理解防抖和節流
防抖:短時間內連續觸發的事件,在某個時間期限內事件函數只執行一次
節流:如果短時間內大量觸發同一事件,在函數執行一次之后,在指定的時間期限內不再工作,直至過了這段時間才重新生效
73、什么是單例模式,什么是工廠模式
單例模式:把描述同一個事物的屬性和方法放在一個內存空間下,起到分組的作用
這樣不同事物之間的屬性即使同名也不會沖突。單例模式實例化出來的對象是唯一的
工廠模式:把相同代碼封裝起來,實現批量生產目的的一種模式。減少冗余代碼
74、舉例幾種常用的Object方法
Object.assign()、Object.create()
Object.defineProperty、Object.prototype.hasOwnProperty
75、js實現繼承的幾種方式
1)類式(call)繼承
2)拷貝繼承
3)原型繼承
4)寄生組合式繼承
5)es6中class繼承
