JavaScript 的組成
ES,DOM,BOMjavascript
轉Boolean
在條件判斷時,除了 undefined
, null
, false
, NaN
, ''
, 0
, -0
,其餘全部值都轉爲 true
,包括全部對象。css
對象轉基本類型
對象在轉換基本類型時,首先會調用 valueOf
而後調用 toString
。java
JS 的基本數據類型和引用數據類型
基本:null,underfined,number,string,symbol,booleanajax
引用:Array,Object,Functionexpress
檢測瀏覽器版本版本有哪些方式?
- 根據 navigator.userAgent
- 根據 window 對象的成員 // 'ActiveXObject' in window
介紹 JS 有哪些內置對象?
- 數據封裝類對象:Object、Array、Boolean、Number、String
- 其餘對象:Function、Arguments、Math、Date、RegExp、Error
- ES6 新增對象:Symbol、Map、Set、Promises、Proxy、Reflect
如何編寫高性能的 JavaScript?
- 遵循嚴格模式:"use strict";
- 將 js 腳本放在頁面底部,加快渲染頁面
- 將 js 腳本將腳本成組打包,減小請求
- 儘可能使用局部變量來保存全局變量
- 儘可能減小使用閉包
- 緩存 DOM 節點的訪問
- 給 setTimeout() 和 setInterval() 傳遞函數而不是字符串做爲參數
- 最小化重繪(repaint)和迴流(reflow)
offsetWidth/offsetHeight,clientWidth/clientHeight 與 scrollWidth/scrollHeight 的區別
- offsetWidth/offsetHeight 返回值包含 content + padding + border,效果與 e.getBoundingClientRect()相同
- clientWidth/clientHeight 返回值只包含 content + padding,若是有滾動條,也不包含滾動條
- scrollWidth/scrollHeight 返回值包含 content + padding + 溢出內容的尺寸
描述瀏覽器的渲染過程
- 解析 HTML 構建 DOM(DOM 樹),並行請求 css/image/js
- CSS 文件下載完成,開始構建 CSSOM(CSS 樹)
- CSSOM 構建結束後,和 DOM 一塊兒生成 Render Tree(渲染樹)
- 佈局(Layout):計算出每一個節點在屏幕中的位置
- 顯示(Painting):經過顯卡把頁面畫到屏幕上
DOM 樹 和 渲染樹 的區別:設計模式
- DOM 樹與 HTML 標籤一一對應,包括 head 和隱藏元素
- 渲染樹不包括 head 和隱藏元素,每個節點都有對應的 css 屬性
重繪和迴流(重排)的區別和關係?
- 重繪:當渲染樹中的元素外觀(如:顏色)發生改變,不影響佈局時,產生重繪
- 迴流:當渲染樹中的元素的佈局(如:尺寸、位置、隱藏/狀態狀態)發生改變時,產生重繪迴流
- 注意:JS 獲取 Layout 屬性值(如:offsetLeft、scrollTop、getComputedStyle 等)也會引發迴流。由於瀏覽器須要經過迴流計算最新值
- 迴流必將引發重繪,而重繪不必定會引發迴流
如何最小化重繪(repaint)和迴流(reflow)?
- 須要要對元素進行復雜的操做時,能夠先隱藏(display:"none"),操做完成後再顯示
- 須要建立多個 DOM 節點時,使用 DocumentFragment 建立完後一次性的加入 document
- 緩存 Layout 屬性值,如:var left = elem.offsetLeft; 這樣,屢次使用 left 只產生一次迴流
- 儘可能避免用 table 佈局(table 元素一旦觸發迴流就會致使 table 裏全部的其它元素迴流)
- 避免使用 css 表達式(expression),由於每次調用都會從新計算值(包括加載頁面)
- 儘可能使用 css 屬性簡寫,如:用 border 代替 border-width, border-style, border-color 批量修改元素樣式:elem.className 和 elem.style.cssText 代替 elem.style.xxx
script 的位置是否會影響首屏顯示時間?
- 瀏覽器解析 HTML 是自上而下的線性過程,script 做爲 HTML 的一部分一樣遵循這個原則
- 所以,script 會延遲 DomContentLoad,只顯示其上部分首屏內容,從而影響首屏顯示的完成時間
解釋 JavaScript 中的做用域與變量聲明提高?
Js中做用域是函數做用域,瀏覽器
函數聲明與變量聲明常常被 JavaScript 引擎隱式地提高到當前做用域的頂部。緩存
函數聲明的優先級高於變量安全
JavaScript 的原型,原型鏈?
原型鏈:多線程
- 當一個對象調用的屬性/方法自身不存在時,就會去本身 [proto] 關聯的前輩 prototype 對象上去找
- 若是沒找到,就會去該 prototype 原型 [proto] 關聯的前輩 prototype 去找。依次類推,直到找到屬性/方法或 undefined 爲止。從而造成了所謂的「原型鏈」
原型特色:
- JavaScript 對象是經過引用來傳遞的,當修改原型時,與之相關的對象也會繼承這一改變
JavaScript 如何實現一個類,怎麼實例化這個類?
1.new
2.Object.create
3.class
javascript 建立對象的幾種方式?
- 對象字面量的方式
- 構造函數
- 工廠模式
- 混合方式
Javascript 如何實現繼承?
- 構造函數綁定:使用 call 或 apply 方法,將父對象的構造函數綁定在子對象上
- 實例繼承:將子對象的 prototype 指向父對象的一個實例
- 拷貝繼承:若是把父對象的全部屬性和方法,拷貝進子對象
- 原型繼承:將子對象的 prototype 指向父對象的 prototype
- ES6 語法糖 extends:class ColorPoint extends Point {}
js 繼承方式及其優缺點
原型鏈繼承的缺點
- 一是字面量重寫原型會中斷關係,使用引用類型的原型,而且子類型還沒法給超類型傳遞參數。
借用構造函數(類式繼承)
- 借用構造函數雖然解決了剛纔兩種問題,但沒有原型,則複用無從談起。因此咱們須要原型鏈+借用構造函數的模式,這種模式稱爲組合繼承
組合式繼承
- 組合式繼承是比較經常使用的一種繼承方法,其背後的思路是使用原型鏈實現對原型屬性和方法的繼承,而經過借用構造函數來實現對實例屬性的繼承。這樣,既經過在原型上定義方法實現了函數複用,又保證每一個實例都有它本身的屬性。
Javascript 做用鏈域?
- 若是當前做用域沒有找到屬性或方法,會向上層做用域查找,直至全局函數,這種形式就是做用域鏈
在一個 DOM 上同時綁定兩個點擊事件:一個用捕獲,一個用冒泡。事件會執行幾回,先執行冒泡仍是捕獲?
- 該 DOM 上的事件若是被觸發,會執行兩次(執行次數等於綁定次數)
- 若是該 DOM 是目標元素,則按事件綁定順序執行,不區分冒泡/捕獲
- 若是該 DOM 是處於事件流中的非目標元素,則先執行捕獲,後執行冒泡
談談 this 對象的理解
1.是否在new中調用,this=>新建立的對象
2.時候經過apply,call或者硬綁定,this=>指定對象
3.時候有某個上下文對象中調用obj.foo(),this=>obj
4.this=>window(underfined)
事件的代理/委託
事件委託是指將事件綁定目標元素的到父元素上,利用冒泡機制觸發該事件
優勢:
- 能夠減小事件註冊,節省大量內存佔用
- 能夠將事件應用於動態添加的子元素上
如何派發事件(dispatchEvent)?(如何進行事件廣播?)
- W3C: 使用 dispatchEvent 方法
- IE: 使用 fireEvent 方法
var fireEvent = function(element, event){ if (document.createEventObject){ var mockEvent = document.createEventObject(); return element.fireEvent('on' + event, mockEvent) }else{ var mockEvent = document.createEvent('HTMLEvents'); mockEvent.initEvent(event, true, true); return !element.dispatchEvent(mockEvent); } }
什麼是函數節流?介紹一下應用場景和原理?
- 函數節流(throttle)是指阻止一個函數在很短期間隔內連續調用。 只有當上一次函數執行後達到規定的時間間隔,才能進行下一次調用。 但要保證一個累計最小調用間隔(不然拖拽類的節流都將無連續效果)
- 函數節流用於 onresize, onscroll 等短期內會屢次觸發的事件
- 函數節流的原理:使用定時器作時間節流。 當觸發一個事件時,先用 setTimout 讓這個事件延遲一小段時間再執行。 若是在這個時間間隔內又觸發了事件,就 clearTimeout 原來的定時器, 再 setTimeout 一個新的定時器重複以上流程。
函數節流簡單實現:
function throttle(method, context) { clearTimeout(methor.tId); method.tId = setTimeout(function(){ method.call(context); }, 100); // 兩次調用至少間隔 100ms } // 調用 window.onresize = function(){ throttle(myFunc, window); }
區分什麼是「客戶區座標」、「頁面座標」、「屏幕座標」?
- 客戶區座標:鼠標指針在可視區中的水平座標(clientX)和垂直座標(clientY)
- 頁面座標:鼠標指針在頁面佈局中的水平座標(pageX)和垂直座標(pageY)
- 屏幕座標:設備物理屏幕的水平座標(screenX)和垂直座標(screenY)
如何得到一個 DOM 元素的絕對位置?
- elem.offsetLeft:返回元素相對於其定位父級左側的距離
- elem.offsetTop:返回元素相對於其定位父級頂部的距離
- elem.getBoundingClientRect():返回一個 DOMRect 對象,包含一組描述邊框的只讀屬性,單位像素
new 操做符具體幹了什麼?
1.創造一個全新的對象
2.這個新對象會被執行[[Prototype]]鏈接
3.這個新對象會綁定到函數調用的this
4.若是函數沒有返回其餘對象,自動返回這個新對象
new會改變硬綁定函數的this,使用new硬綁定函數主要是爲了預先設置函數的一些參數
function create() {
// 建立一個空的對象
let obj = new Object()
// 得到構造函數
let Con = [].shift.call(arguments)
// 連接到原型
obj.__proto__ = Con.prototype
// 綁定 this,執行構造函數
let result = Con.apply(obj, arguments)
// 確保 new 出來的是個對象
return typeof result === 'object' ? result : obj
}
什麼是閉包(closure),爲何要用它?
閉包是指有權訪問另外一個函數做用域中變量的函數,建立閉包的最多見的方式就是在一個函數內建立另外一個函數,經過另外一個函數訪問這個函數的局部變量,利用閉包能夠突破做用鏈域
閉包的特性:
- 函數內再嵌套函數
- 內部函數能夠引用外層的參數和變量
- 參數和變量不會被垃圾回收機制回收
用過哪些設計模式?
- 工廠模式:
- 主要好處就是能夠消除對象間的耦合,經過使用工程方法而不是 new 關鍵字。將全部實例化的代碼集中在一個位置防止代碼重複
- 工廠模式解決了重複實例化的問題 ,但還有一個問題,那就是識別問題,由於根本沒法 搞清楚他們究竟是哪一個對象的實例
- 構造函數模式
請解釋一下 JavaScript 的同源策略
這裏的同源策略指的是:協議,域名,端口相同,同源策略是一種安全協議
實現一個函數 clone,能夠對 JavaScript 中的 5 種主要的數據類型(包括 Number、String、Object、Array、Boolean)進行值複製(常考)
function deepClone(obj) { if (!isObject(obj)) { throw new Error('obj 不是一個對象!') } let isArray = Array.isArray(obj) let cloneObj = isArray ? [] : {} for (let key in obj) { cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key] } return cloneObj }
哪些操做會形成內存泄漏?
- JavaScript 內存泄露指對象在不須要使用它時仍然存在,致使佔用的內存不能使用或回收
- 未使用 var 聲明的全局變量
- 閉包函數(Closures)
- 循環引用(兩個對象相互引用)
- 控制檯日誌(console.log)
- 移除存在綁定事件的 DOM 元素(IE)
爲何 JS 是單線程,而不是多線程 [常考]
- 單線程是指 JavaScript 在執行的時候,有且只有一個主線程來處理全部的任務。
- 目的是爲了實現與瀏覽器交互。
- 咱們設想一下,若是 JavaScript 是多線程的,如今咱們在瀏覽器中同時操做一個 DOM,一個線程要求瀏覽器在這個 DOM 中添加節點,而另外一個線程卻要求瀏覽器刪掉這個 DOM 節點,那這個時候瀏覽器就會很鬱悶,他不知道應該以哪一個線程爲準。因此爲了不此類現象的發生,下降複雜度,JavaScript 選擇只用一個主線程來執行代碼,以此來保證程序執行的一致性。
瀏覽器中的 Event Loop
![](http://static.javashuo.com/static/loading.gif)
- 主線程運行的時候會生成堆(heap)和棧(stack);
- js 從上到下解析方法,將其中的同步任務按照執行順序排列到執行棧中;
- 當程序調用外部的 API 時,好比 ajax、setTimeout 等,會將此類異步任務掛起,繼續執行執行棧中的任務,等異步任務返回結果後,再按照執行順序排列到事件隊列中;
- 主線程先將執行棧中的同步任務清空,而後檢查事件隊列中是否有任務,若是有,就將第一個事件對應的回調推到執行棧中執行,若在執行過程當中遇到異步任務,則繼續將這個異步任務排列到事件隊列中。
- 主線程每次將執行棧清空後,就去事件隊列中檢查是否有任務,若是有,就每次取出一個推到執行棧中執行,這個過程是循環往復的... ...,這個過程被稱爲「Event Loop 事件循環」