1.javaScript的數據類型有什麼
Undefined、Null、Boolean、Number、String、Object、Symbol(es6--原始數據類型)。javascript
2.檢測數據類型有什麼方法
typeof
typeof xxx獲得的值有如下幾種類型:undefined boolean number string object function、symbol ,比較簡單,再也不一一演示了。
這裏須要注意的有三點:css
typeof null結果是object ,實際這是typeof的一個bug,null是原始值,非引用類型
typeof [1, 2]結果是object,結果中沒有array這一項,引用類型除了function其餘的所有都是object
typeof Symbol() 用typeof獲取symbol類型的值獲得的是symbol,這是 ES6 新增的知識點
instanceof
用於實例和構造函數的對應。例如判斷一個變量是不是數組,使用typeof沒法判斷,但可使用[1, 2] instanceof Array來判斷。由於,[1, 2]是數組,它的構造函數就是Array。同理:html
function Foo(name) {
this.name = name
}
var foo = new Foo('bar’)
console.log(foo instanceof Foo) // true
3.介紹js有哪些內置對象?
Object 是 JavaScript 中全部對象的父對象
數據封裝類對象:Object、Array、Boolean、Number 和 String
其餘對象:Function、Arguments、Math、Date、RegEx、Error前端
4.如何區分數組和對象?
(1)從原型入手,Array.prototype.isPrototypeOf(obj); 利用isPrototypeOf()方法,斷定Array是否是在obj的原型鏈中,若是是,則返回true,不然false。Array.prototype.isPrototype([]) //true
(2)也能夠從構造函數入手,利用對向的constructor屬性
(3)根據對象的class屬性(類屬性),跨原型鏈調用toString()方法。Object.prototype.toString.call(Window);
(4)Array.isArray()方法。vue
5.null,undefined 的區別?
null 表示一個對象被定義了,值爲「空值」;
undefined 表示不存在這個值。java
typeof undefined //"undefined"
undefined :是一個表示"無"的原始值或者說表示"缺乏值",就是此處應該有一個值,可是尚未定義。當嘗試讀取時會返回 undefined;
例如變量被聲明瞭,但沒有賦值時,就等於undefinedjquery
typeof null //"object"
null : 是一個對象(空對象, 沒有任何屬性和方法);
例如做爲函數的參數,表示該函數的參數不是對象;webpack
注意:
在驗證null時,必定要使用 === ,由於 == 沒法分別 null 和 undefined
undefined表示"缺乏值",就是此處應該有一個值,可是尚未定義。典型用法是:
1)變量被聲明瞭,但沒有賦值時,就等於undefined。
2) 調用函數時,應該提供的參數沒有提供,該參數等於undefined。
3)對象沒有賦值的屬性,該屬性的值爲undefined。
4)函數沒有返回值時,默認返回undefined。程序員
null表示"沒有對象",即該處不該該有值。
典型用法是:
1) 做爲函數的參數,表示該函數的參數不是對象。
2) 做爲對象原型鏈的終點。es6
6.聲明變量和聲明函數的提高有什麼區別?
(1) 變量聲明提高:變量申明在進入執行上下文就完成了。
只要變量在代碼中進行了聲明,不管它在哪一個位置上進行聲明, js引擎都會將它的聲明放在範圍做用域的頂部;
(2) 函數聲明提高:執行代碼以前會先讀取函數聲明,意味着能夠把函數申明放在調用它的語句後面。
只要函數在代碼中進行了聲明,不管它在哪一個位置上進行聲明, js引擎都會將它的聲明放在範圍做用域的頂部;
(3) 變量or函數聲明:函數聲明會覆蓋變量聲明,但不會覆蓋變量賦值。
同一個名稱標識a,即有變量聲明var a,又有函數聲明function a() {},無論兩者聲明的順序,函數聲明會覆蓋變量聲明,也就是說,此時a的值是聲明的函數function a() {}。注意:若是在變量聲明的同時初始化a,或是以後對a進行賦值,此時a的值變量的值。eg: var a; var c = 1; a = 1; function a() { return true; } console.log(a);
原型,原型鏈
1.JavaScript原型,原型鏈 ? 有什麼特色?
原型
每一個對象都會在其內部初始化一個屬性,就是prototype(原型)
使用hasOwnProperty() 能夠判斷這個屬性是否是對象自己的屬性
問題:Javascript中,有一個函數,執行時對象查找時,永遠不會去查找原型,這個函數是?
hasOwnProperty
javaScript中hasOwnProperty函數方法是返回一個布爾值,指出一個對象是否具備指定名稱的屬性。此方法沒法檢查該對象的原型鏈中是否具備該屬性;該屬性必須是對象自己的一個成員。
使用方法:
object.hasOwnProperty(proName)
其中參數object是必選項。一個對象的實例。
proName是必選項。一個屬性名稱的字符串值。
若是 object 具備指定名稱的屬性,那麼JavaScript中hasOwnProperty函數方法返回 true,反之則返回 false。
原型鏈
當咱們在訪問一個對象的屬性時,若是這個對象內部不存在這個屬性,那麼他就會去prototype裏找這個屬性,這個prototype又會有本身的prototype,因而就這樣一直找下去,找到Object.__proto__爲止,找不到就返回unde也就是咱們平時所說的原型鏈的概念。
關係:instance.constructor.prototype = instance.__proto__
特色:
JavaScript對象是經過引用來傳遞的,咱們建立的每一個新對象實體中並無一份屬於本身的原型副本。當咱們修改原型時,與之相關的對象也會繼承這一改變。
當咱們須要一個屬性的時,Javascript引擎會先看當前對象中是否有這個屬性, 若是沒有的話,就會查找他的Prototype對象是否有這個屬性,如此遞推下去,一直檢索到 Object 內建對象。
全部的引用類型(數組、對象、函數),都具備對象特性,便可自由擴展屬性(null除外)
全部的引用類型(數組、對象、函數),都有一個__proto__屬性,屬性值是一個普通的對象
全部的函數,都有一個prototype屬性,屬性值也是一個普通的對象
全部的引用類型(數組、對象、函數),__proto__屬性值指向它的構造函數的prototype屬性值
原型鏈中的this
全部從原型或更高級原型中獲得、執行的方法,其中的this在執行時,就指向了當前這個觸發事件執行的對象。
閉包
閉包的造成與變量的做用域以及變量的生存週期有密切的關係
1.變量的做用域
在js中咱們把做用域分爲全局做用域和局部做用域,全局做用域就是window,在沒有塊級做用域概念的時候,每個函數都是一個局部做用域。
其實變量的做用域,就說指變量的有效範圍。咱們最長說的就是在函數中聲明的變量做用域。
當在函數中聲明一個變量的時候,若是改變量沒有用var關鍵字去定義那麼該變量就是一個全局變量,可是這樣作最容易形成命名衝突。
另外一種狀況就是使用var聲明的變量,這時候的變量就是局部變量,只有在該函數內部能夠訪問,在函數外面是訪問不到的
在javascript中,函數能夠用來創造函數做用域。在函數中搜索變量的時候,若是該函數當中沒有這個變量,那麼此次搜索過程會隨着代碼執行環境建立的做用域鏈往外層逐層搜索,一直搜索到window對象爲止,找不到就會拋出一個爲定義的錯誤。而這種從內到外逐層查找的關係在js中咱們稱爲做用域鏈
2.變量的生存週期
除了變量做用域以外,另一個跟閉包有關的概念就是變量的生存週期,對於全局變量來講,全局變量的生存週期是永久的,除非咱們主動銷燬這個全局變量,而對於函數內部的使用var聲明的變量來講,當退出函數是,這些變量就會隨着函數的結束而銷燬。
3.閉包的造成
Javascript容許使用內部函數,能夠將函數定義和函數表達式放在另外一個函數的函數體內。並且,內部函數能夠訪問它所在的外部函數聲明的局部變量、參數以及聲明的其餘內部函數。當其中一個這樣的內部函數在包含它們的外部函數以外被調用時,就會造成閉包。常見的閉包寫法就是簡單的函數套函數,經過另外一個函數訪問這個函數的局部變量,利用閉包能夠突破做用域鏈,將函數內部的變量和方法傳遞到外部,延續變量的生命。使用閉包能夠減小全局環境的污染,也可用延續變量的生命。
4.閉包的適用場景
閉包的適用場景很是普遍,首先從閉包的優勢出發就是:
減小全局環境的污染生成獨立的運行環境
模塊化就是利用這個特色對不一樣的模塊都有本身獨立的運行環境,不會和全局衝突,模塊和模塊之間經過拋出的接口進行依賴使用
以及像咱們經常使用的jquery類庫(避免和全局衝突使用閉包實現本身獨立的環境)
能夠經過返回其餘函數的方式突破做用域鏈
能夠利用這個功能作一些值的緩存工做,例如常見的設計模式(單例模式),以及如今比較火的框架vue中的計算屬性
其實當遇到如下場景的時候均可以使用閉包
1) 維護函數內的變量安全,避免全局變量的污染。
2) 維持一個變量不被回收。
3) 封裝模塊
5.閉包的缺點
因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大。因此在閉包不用以後,將不使用的局部變量刪除,使其被回收。在IE中可能致使內存泄露,即沒法回收駐留在內存中的元素,這時候須要手動釋放。
6.內存泄露
內存泄漏指一塊被分配的內存既不能使用,又不能回收,直到瀏覽器進程結束。
出現緣由:
1) 循環引用:含有DOM對象的循環引用將致使大部分當前主流瀏覽器內存泄露。循環 引用,簡單來講假如a引用了b,b又引用了a,a和b就構成了循環引用。
2) JS閉包:閉包,函數返回了內部函數還能夠繼續訪問外部方法中定義的私有變量。
3) Dom泄露,當原有的DOM被移除時,子結點引用沒有被移除則沒法回收。
7.JavaScript垃圾回收機制
Javascript中,若是一個對象再也不被引用,那麼這個對象就會被GC(garbage collection)回收。若是兩個對象互相引用,而再也不被第3者所引用,那麼這兩個互相引用的對象也會被回收。垃圾回收不是時時的,由於其開銷比較大,因此垃圾回收器會按照固定的時間間隔週期性的執行。
函數a被b引用,b又被a外的c引用,這就是爲何函數a執行後不會被回收的緣由。
8.垃圾回收的兩個方法:
標記清除法:
1) 垃圾回收機制給存儲在內存中的全部變量加上標記,而後去掉環境中的變量以及被環境中變量所引用的變量(閉包)。
2) 操做1以後內存中仍存在標記的變量就是要刪除的變量,垃圾回收機制將這些帶有標記的變量回收。
引用計數法:
1) 垃圾回收機制給一個變量一個引用次數,當聲明瞭一個變量並將一個引用類型賦值給該變量的時候這個值的引用次數就加1。
2) 當該變量的值變成了另一個值,則這個值得引用次數減1。
3) 當這個值的引用次數變爲0的時候,說明沒有變量在使用,垃圾回收機制會在運行的時候清理掉引用次數爲0的值佔用的空間。
JS運行機制
JavaScript引擎是單線程運行的,瀏覽器不管在何時都只且只有一個線程在運行JavaScript程序.瀏覽器的內核是多線程的,它們在內核制控下相互配合以保持同步,一個瀏覽器至少實現三個常駐線程:javascript引擎線程,GUI渲染線程,瀏覽器事件觸發線程。這些異步線程都會產生不一樣的異步的事件.
1) javascript引擎是基於事件驅動單線程執行的,JS引擎一直等待着任務隊列中任務的到來,而後加以處理,瀏覽器不管何時都只有一個JS線程在運行JS程序。
2) GUI渲染線程負責渲染瀏覽器界面,當界面須要重繪(Repaint)或因爲某種操做引起迴流(reflow)時,該線程就會執行。但須要注意 GUI渲染線程與JS引擎是互斥的,當JS引擎執行時GUI線程會被掛起,GUI更新會被保存在一個隊列中等到JS引擎空閒時當即被執行。
3) 事件觸發線程,當一個事件被觸發時該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理。這些事件可來自JavaScript引擎當前執行的代碼塊如setTimeOut、也可來自瀏覽器內核的其餘線程如鼠標點擊、AJAX異步請求等,但因爲JS的單線程關係全部這些事件都得排隊等待JS引擎處理。(當線程中沒有執行任何同步代碼的前提下才會執行異步代碼)
當程序啓動時, 一個進程被建立,同時也運行一個線程, 即爲主線程,js的運行機制爲單線程
程序中跑兩個線程,一個負責程序自己的運行,做爲主線程; 另外一個負責主線程與其餘線程的的通訊,被稱爲「Event Loop 線程" 。每當遇到異步任務,交給 EventLoop 線程,而後本身日後運行,等到主線程運行完後,再去 EventLoop 線程拿結果。
1)全部任務都在主線程上執行,造成一個執行棧(execution context stack)。
2)主線程以外,還存在一個"任務隊列"(task queue)。系統把異步任務放到"任務隊列"之中,而後繼續執行後續的任務。
3)一旦"執行棧"中的全部任務執行完畢,系統就會讀取"任務隊列"。若是這個時候,異步任務已經結束了等待狀態,就會從"任務隊列"進入執行棧,恢復執行。
4)主線程不斷重複上面的第三步。
"回調函數"(callback),就是那些會被主線程掛起來的代碼。異步任務必須指定回調函數,當異步任務從"任務隊列"回到執行棧,回調函數就會執行。"任務隊列"是一個先進先出的數據結構,排在前面的事件,優先返回主線程。主線程的讀取過程基本上是自動的,只要執行棧一清空,"任務隊列"上第一位的事件就自動返回主線程。
主線程從"任務隊列"中讀取事件,這個過程是循環不斷的,因此整個的這種運行機制又稱爲Event Loop。
從主線程的角度看,一個異步過程包括下面兩個要素:
發起函數(或叫註冊函數)A
回調函數callbackFn
它們都是在主線程上調用的,其中註冊函數用來發起異步過程,回調函數用來處理結果。
異步進程有:
相似onclick等,由瀏覽器內核的DOM binding模塊處理,事件觸發時,回調函數添加到任務隊列中;
setTimeout等,由瀏覽器內核的Timer模塊處理,時間到達時,回調函數添加到任務隊列中;
Ajax,由瀏覽器內核的Network模塊處理,網絡請求返回後,添加到任務隊列中。
例如setTimeout(fn, 1000),其中的setTimeout就是異步過程的發起函數,fn是回調函數。用一句話歸納:工做線程將消息放到消息隊列,主線程經過事件循環過程去取消息。
消息隊列:消息隊列是一個先進先出的隊列,它裏面存放着各類消息。
事件循環:事件循環是指主線程重複從消息隊列中取消息、執行的過程。
流程以下:
1) 主線程讀取js代碼, 造成相應的堆和執行棧, 執行同步任務
2) 當主線程遇到異步任務,,指定給異步進程處理, 同時繼續執行同步任務
3) 當異步進程處理完畢後, 將相應的異步任務推入到任務隊列首部
4) 主線程任務處理完畢後,,查詢任務隊列,則取出一個任務隊列推入到主線程的執行棧
5) 重複執行第二、三、4步,這就稱爲事件循環
JS-Web-API 知識點與高頻考題解析
BOM
BOM(瀏覽器對象模型)是瀏覽器自己的一些信息的設置和獲取,例如獲取瀏覽器的寬度、高度,設置讓瀏覽器跳轉到哪一個地址。
navigator: 獲取瀏覽器特性(即俗稱的UA)而後識別客戶端
location: 獲取網址、協議、path、參數、hash 等
history: 操做瀏覽器的歷史紀錄,(前進,後退等功能)
1.什麼是window對象? 什麼是document對象?
window:它是一個頂層對象,而不是另外一個對象的屬性,即瀏覽器的窗口。
document:表明整個HTML 文檔,可用來訪問頁面中的全部元素
Window 對象表示當前瀏覽器的窗口,是JavaScript的頂級對象。咱們建立的全部對象、函數、變量都是 Window 對象的成員。
Window 對象的方法和屬性是在全局範圍內有效的。
Document 對象是 HTML 文檔的根節點與全部其餘節點(元素節點,文本節點,屬性節點, 註釋節點)
Document 對象使咱們能夠經過腳本對 HTML 頁面中的全部元素進行訪問
Document 對象是 Window 對象的一部分,可經過 window.document 屬性對其進行訪問
2.事件是?IE與火狐的事件機制有什麼區別? 如何阻止冒泡?
1) 咱們在網頁中的某個操做(有的操做對應多個事件)。例如:當咱們點擊一個按鈕就會產生一個事件。是能夠被 JavaScript 偵測到的行爲。
2) 事件處理機制:IE是事件冒泡、Firefox同時支持兩種事件模型,也就是:捕獲型事件和冒泡型事件;
3) ev.stopPropagation();(舊ie的方法 ev.cancelBubble = true;)
3.解釋一下事件代理
事件代理的原理其實就和做用域鏈的原理差很少,可是事件代理是利用事件的冒泡原理來實現的,事件代理就是經過給祖先元素添加事件,經過事件目標對象開始向上查找找到匹配的子節點爲止,若是找不到則到綁定事件的那個祖先元素爲止,找到了就觸發事件,而且能夠經過js中call和apply來改變觸發事件函數中的this爲當前綁定節點,也是經過一層一層逐層向上的方式進行匹配查找而觸發對應事件,好處就是可使後添加的dom元素也一樣有以前存在元素的事件,jquery中可使用on,delegate,live實現的,不過在jquery1.7版本之後吧live給廢除了,緣由就是live綁定事件的祖先元素是整個html頁面的根節點,因此性能消耗比較大,在後邊的版本中給刪除了,使用on,delegate代替
優勢:
使代碼簡潔
減小瀏覽器的內存佔用
缺點:
使用不當會形成事件在不該該觸發時觸發
function bindEvent(elem, type, selector, fn) {
// 這樣處理,可接收兩種調用方式 bindEvent(div1, 'click', 'a', function () {...}) 和 bindEvent(div1, 'click', function () {...}) 這兩種 if (fn == null) { fn = selector selector = null } // 綁定事件 elem.addEventListener(type, function (e) { var target if (selector) { // 有 selector 說明須要作事件代理 // 獲取觸發時間的元素,即 e.target target = e.target // 看是否符合 selector 這個條件 if (target.matches(selector)) { fn.call(target, e) } } else { // 無 selector ,說明不須要事件代理 fn(e) } })
}
// 使用代理,bindEvent 多一個 'a' 參數
var div1 = document.getElementById('div1')
bindEvent(div1, 'click', 'a', function (e) {
console.log(this.innerHTML)
})
// 不使用代理
var a = document.getElementById('a1')
bindEvent(div1, 'click', function (e) {
console.log(a.innerHTML)
})
4.offsetWidth/offsetHeight,clientWidth/clientHeight與scrollWidth/scrollHeight的區別
offsetWidth/offsetHeight返回值包含content + padding + border,效果與e.getBoundingClientRect()相同
clientWidth/clientHeight返回值只包含content + padding,若是有滾動條,也不包含滾動條
scrollWidth/scrollHeight返回值包含content + padding + 溢出內容的尺寸
5.focus/blur與focusin/focusout的區別與聯繫
focus/blur不冒泡,focusin/focusout冒泡
focus/blur兼容性好,focusin/focusout在除FireFox外的瀏覽器下都保持良好兼容性,如需使用事件託管,可考慮在FireFox下使用事件捕獲elem.addEventListener('focus', handler, true)
可得到焦點的元素:
window
連接被點擊或鍵盤操做
表單空間被點擊或鍵盤操做
設置tabindex屬性的元素被點擊或鍵盤操做
6.mouseover/mouseout與mouseenter/mouseleave的區別與聯繫
mouseover/mouseout是標準事件,全部瀏覽器都支持;mouseenter/mouseleave是IE5.5引入的特有事件後來被DOM3標準採納,現代標準瀏覽器也支持
mouseover/mouseout是冒泡事件;mouseenter/mouseleave不冒泡。須要爲多個元素監聽鼠標移入/出事件時,推薦mouseover/mouseout託管,提升性能
標準事件模型中event.target表示發生移入/出的元素,vent.relatedTarget對應移出/如元素;在老IE中event.srcElement表示發生移入/出的元素,event.toElement表示移出的目標元素,event.fromElement表示移入時的來源元素
7.介紹DOM0,DOM2,DOM3事件處理方式區別
DOM0級事件處理方式:
btn.onclick = func;
btn.onclick = null;
DOM2級事件處理方式:
btn.addEventListener('click', func, false);
btn.removeEventListener('click', func, false);
btn.attachEvent("onclick", func);
btn.detachEvent("onclick", func);
DOM3級事件處理方式:
eventUtil.addListener(input, "textInput", func);
eventUtil 是自定義對象,textInput 是DOM3級事件
8.事件的三個階段
捕獲、目標、冒泡
js的冒泡(Bubbling Event)和捕獲(Capture Event)的區別
冒泡型事件:事件按照從最特定的事件目標到最不特定的事件目標(document對象)的順序觸發。
捕獲型事件(event capturing):事件從最不精確的對象(document 對象)開始觸發,而後到最精確(也能夠在窗口級別捕獲事件,不過必須由開發人員特別指定)。
DOM事件流:同時支持兩種事件模型:捕獲型事件和冒泡型事件,可是,捕獲型事件先發生。兩種事件流會觸及DOM中的全部對象,從document對象開始,也在document對象結束。
事件捕獲
當你使用事件捕獲時,父級元素先觸發,子級元素後觸發,即div先觸發,p後觸發。
事件冒泡
當你使用事件冒泡時,子級元素先觸發,父級元素後觸發,即p先觸發,div後觸發。
阻止冒泡
在W3c中,使用stopPropagation()方法
在IE下設置cancelBubble = true;
在捕獲的過程當中stopPropagation();後,後面的冒泡過程也不會發生了。
阻止捕獲
阻止事件的默認行爲,例如click 後的跳轉
在W3c中,使用preventDefault()方法;
在IE下設置window.event.returnValue = false;
9.介紹事件「捕獲」和「冒泡」執行順序和事件的執行次數?
按照W3C標準的事件:首是進入捕獲階段,直到達到目標元素,再進入冒泡階段
事件執行次數(DOM2-addEventListener):元素上綁定事件的個數
注意1:前提是事件被確實觸發
注意2:事件綁定幾回就算幾個事件,即便類型和功能徹底同樣也不會「覆蓋」
事件執行順序:判斷的關鍵是否目標元素
非目標元素:根據W3C的標準執行:捕獲->目標元素->冒泡(不依據事件綁定順序)
目標元素:依據事件綁定順序:先綁定的事件先執行(不依據捕獲冒泡標準)
最終順序:父元素捕獲->目標元素事件1->目標元素事件2->子元素捕獲->子元素冒泡->父元素冒泡
注意:子元素事件執行前提 事件確實「落」到子元素佈局區域上,而不是簡單的具備嵌套關係
在一個DOM上同時綁定兩個點擊事件:一個用捕獲,一個用冒泡。事件會執行幾回,先執行冒泡仍是捕獲?
該DOM上的事件若是被觸發,會執行兩次(執行次數等於綁定次數)
若是該DOM是目標元素,則按事件綁定順序執行,不區分冒泡/捕獲
若是該DOM是處於事件流中的非目標元素,則先執行捕獲,後執行冒泡
10.window.onload 和 document.DOMContentLoaded (注:$(document).ready()) 的區別?
通常狀況下,DOMContentLoaded事件要在window.onload以前執行,當DOM樹構建完成的時候就會執行DOMContentLoaded事件,而window.onload是在頁面載入完成的時候,才執行,這其中包括圖片等元素。大多數時候咱們只是想在DOM樹構建完成後,綁定事件到元素,咱們並不須要圖片元素,加上有時候加載外域圖片的速度很是緩慢。
DOM
講 DOM 先從 HTML 講起,講 HTML 先從 XML 講起。XML 是一種可擴展的標記語言,所謂可擴展就是它能夠描述任何結構化的數據,它是一棵樹!
1.documen.write和 innerHTML的區別
document.write只能重繪整個頁面
innerHTML能夠重繪頁面的一部分
2.DOM操做——怎樣添加、移除、移動、複製、建立和查找節點?
1)建立新節點
createDocumentFragment() //建立一個DOM片斷
createElement() //建立一個具體的元素
createTextNode() //建立一個文本節點
2)添加、移除、替換、插入
appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子節點前插入一個新的子節點
3)查找
getElementsByTagName() //經過標籤名稱
getElementsByName() //經過元素的Name屬性的值(IE容錯能力較強,會獲得一個數組,其中包括id等於name值的)
getElementById() //經過元素Id,惟一性
3.attribute和property的區別是什麼?
attribute是dom元素在文檔中做爲html標籤擁有的屬性;
property就是dom元素在js中做爲對象擁有的屬性。
因此:
對於html的標準屬性來講,attribute和property是同步的,是會自動更新的,
可是對於自定義的屬性來講,他們是不一樣步的,
4.src和href的區別
src用於替換當前元素,href用於在當前文檔和引用資源之間確立聯繫。
src是source的縮寫,指向外部資源的位置,指向的內容將會嵌入到文檔中當前標籤所在位置;在請求src資源時會將其指向的資源下載並應用到文檔內,當瀏覽器解析到該元素時,會暫停其餘資源的下載和處理,直到將該資源加載、編譯、執行完畢,圖片和框架等元素也如此,相似於將所指向資源嵌入當前標籤內。這也是爲何將js腳本放在底部而不是頭部。
Src source,指向外部資源的位置,若是咱們添加<script src ="js.js"></script>瀏覽器會暫停其餘資源的下載和處理,直到該資源加載,編譯,執行完畢(圖片和框架也是如此),這也就是爲何js腳本要放在底部。
src用於替換當前元素,href用於在當前文檔和引入資源之間創建聯繫。
對象
1,JavaScript繼承的幾種實現方式?
1)構造函數繼承,使用call和apply兩個方法的特性能夠實現,改變方法中的this
2)原型鏈繼承
3)組合式繼承
2.javascript建立對象的幾種方式?
javascript建立對象簡單的說,無非就是使用內置對象或各類自定義對象,固然還能夠用JSON;但寫法有不少種,也能混合使用。
1) 對象字面量的方式 person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
2) 用function來模擬無參的構造函數
function Person(){}
var person=new Person();//定義一個function,若是使用new"實例化",該function能夠看做是一個Class person.name=「Mark"; person.age="25"; person.work=function(){ alert(person.name+" hello..."); } person.work();
3) 用function來模擬參構造函數來實現(用this關鍵字定義構造的上下文屬性)
function Pet(name,age,hobby){
this.name=name;//this做用域:當前對象 this.age=age; this.hobby=hobby; this.eat=function(){ alert("我叫"+this.name+",我喜歡"+this.hobby+",是個程序員"); } } var maidou =new Pet("麥兜",25,"coding");//實例化、建立對象 maidou.eat();//調用eat方法
4) 用工廠方式來建立(內置對象)
var wcDog =new Object();
wcDog.name="旺財"; wcDog.age=3; wcDog.work=function(){ alert("我是"+wcDog.name+",汪汪汪......"); } wcDog.work();
五、用原型方式來建立
function Dog(){ } Dog.prototype.name="旺財"; Dog.prototype.eat=function(){alert(this.name+"是個吃貨");} var wangcai =new Dog(); wangcai.eat();
5) 用混合方式來建立
function Car(name,price){
this.name=name; this.price=price; } Car.prototype.sell=function(){ alert("我是"+this.name+",我如今賣"+this.price+"萬元"); } var camry =new Car("凱美瑞",27); camry.sell();
3.談談This對象的理解。
this分爲幾個不一樣的使用場景,在function中this指的的是window,若是是實用new 調用的話this指的是當前的實例化對象,在事件調用函數中this指的調用事件的window特殊的是在IE中的attachEvent中的this老是指向全局對象Window;,在定時器中this指的是window,在es6中有一個箭頭函數,在箭頭函數中this永遠指向的是父級對象,this也是能夠改變的,在js中call, apply, bind均可以改變this的指向, call, apply都是執行一個函數而且改變this,區別就是參數傳遞不同,而bind是返回一個綁定this以後的新函數
4.javascript 代碼中的"use strict";是什麼意思 ? 使用它區別是什麼?
use strict是一種ECMAscript 5 添加的(嚴格)運行模式,這種模式使得 Javascript 在更嚴格的條件下運行,
使JS編碼更加規範化的模式,消除Javascript語法的一些不合理、不嚴謹之處,減小一些怪異行爲。
默認支持的糟糕特性都會被禁用,好比不能用with,也不能在乎外的狀況下給全局變量賦值;
全局變量的顯示聲明,函數必須聲明在頂層,不容許在非函數代碼塊內聲明函數,arguments.callee也不容許使用;
消除代碼運行的一些不安全之處,保證代碼運行的安全,限制函數中的arguments修改,嚴格模式下的eval函數的行爲和非嚴格模式的也不相同;
提升編譯器效率,增長運行速度;
爲將來新版本的Javascript標準化作鋪墊。
5.JSON 的瞭解?
JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。
它是基於JavaScript的一個子集。數據格式簡單, 易於讀寫, 佔用帶寬小
如:{"age":"12", "name":"back"}
JSON字符串轉換爲JSON對象:
var obj =eval('('+ str +')');
var obj = str.parseJSON();
var obj = JSON.parse(str);
JSON對象轉換爲JSON字符串:
var last=obj.toJSONString();
var last=JSON.stringify(obj);
7.什麼是函數節流?介紹一下應用場景和原理?
函數節流(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);
}
8.new 操做符具體幹了什麼?
建立實例對象,this 變量引用該對象,同時還繼承了構造函數的原型
屬性和方法被加入到 this 引用的對象中
新建立的對象由 this 所引用,而且最後隱式的返回 this
new共經歷了四個過程。
var fn = function () { };
var fnObj = new fn();
1)建立了一個空對象
var obj = new object();
2)設置原型鏈
obj._proto_ = fn.prototype;
3)讓fn的this指向obj,並執行fn的函數體
var result = fn.call(obj);
4)判斷fn的返回值類型,若是是值類型,返回obj。若是是引用類型,就返回這個引用類型的對象。
if (typeof(result) == "object"){
fnObj = result;
} else {
fnObj = obj;}
兼容與優化
1.頁面重構怎麼操做?
網站重構:在不改變外部行爲的前提下,簡化結構、添加可讀性,而在網站前端保持一致的行爲。
也就是說是在不改變UI的狀況下,對網站進行優化,在擴展的同時保持一致的UI。
對於傳統的網站來講重構一般是:
表格(table)佈局改成DIV+CSS
使網站前端兼容於現代瀏覽器(針對於不合規範的CSS、如對IE6有效的)
對於移動平臺的優化
針對於SEO進行優化
深層次的網站重構應該考慮的方面
減小代碼間的耦合
讓代碼保持彈性
嚴格按規範編寫代碼
設計可擴展的API
代替舊有的框架、語言(如VB)
加強用戶體驗
一般來講對於速度的優化也包含在重構中
壓縮JS、CSS、image等前端資源(一般是由服務器來解決)
程序的性能優化(如數據讀寫)
採用CDN來加速資源加載
對於JS DOM的優化
HTTP服務器的文件緩存
2.列舉IE與其餘瀏覽器不同的特性?
1)事件不一樣之處:
1-1,觸發事件的元素被認爲是目標(target)。而在 IE 中,目標包含在 event 對象的 srcElement 屬性;
1-2,獲取字符代碼、若是按鍵表明一個字符(shift、ctrl、alt除外),IE 的 keyCode 會返回字符代碼(Unicode),DOM 中按鍵的代碼和字符是分離的,要獲取字符代碼,須要使用 charCode 屬性;
1-3,阻止某個事件的默認行爲,IE 中阻止某個事件的默認行爲,必須將 returnValue 屬性設置爲 false,Mozilla 中,須要調用 preventDefault() 方法;
1-4,中止事件冒泡,IE 中阻止事件進一步冒泡,須要設置 cancelBubble 爲 true,Mozzilla 中,須要調用 stopPropagation();
3.什麼叫優雅降級和漸進加強?
優雅降級:Web站點在全部新式瀏覽器中都能正常工做,若是用戶使用的是老式瀏覽器,則代碼會針對舊版本的IE進行降級處理了,使之在舊式瀏覽器上以某種形式降級體驗卻不至於徹底不能用。
如:border-shadow
漸進加強:從被全部瀏覽器支持的基本功能開始,逐步地添加那些只有新版本瀏覽器才支持的功能,向頁面增長不影響基礎瀏覽器的額外樣式和功能的。當瀏覽器支持時,它們會自動地呈現出來併發揮做用。
如:默認使用flash上傳,但若是瀏覽器支持 HTML5 的文件上傳功能,則使用HTML5實現更好的體驗;
4.說說嚴格模式的限制
嚴格模式主要有如下限制:
變量必須聲明後再使用
函數的參數不能有同名屬性,不然報錯
不能使用with語句
不能對只讀屬性賦值,不然報錯
不能使用前綴0表示八進制數,不然報錯
不能刪除不可刪除的屬性,不然報錯
不能刪除變量delete prop,會報錯,只能刪除屬性delete global[prop]
eval不會在它的外層做用域引入變量
eval和arguments不能被從新賦值
arguments不會自動反映函數參數的變化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局對象
不能使用fn.caller和fn.arguments獲取函數調用的堆棧
增長了保留字(好比protected、static和interface)
設立"嚴格模式"的目的,主要有如下幾個:
消除Javascript語法的一些不合理、不嚴謹之處,減小一些怪異行爲;
消除代碼運行的一些不安全之處,保證代碼運行的安全;
提升編譯器效率,增長運行速度;
爲將來新版本的Javascript作好鋪墊。
注:通過測試IE6,7,8,9均不支持嚴格模式。
5.檢測瀏覽器版本版本有哪些方式?
根據 navigator.userAgent // UA.toLowerCase().indexOf('chrome')
根據 window 對象的成員 // 'ActiveXObject' in window
6.總結前端性能優化的解決方案
優化原則和方向
性能優化的原則是以更好的用戶體驗爲標準,具體就是實現下面的目標:
多使用內存、緩存或者其餘方法
減小 CPU 和GPU 計算,更快展示
優化的方向有兩個:
減小頁面體積,提高網絡加載
優化頁面渲染
減小頁面體積,提高網絡加載
靜態資源的壓縮合並(JS 代碼壓縮合並、CSS 代碼壓縮合並、雪碧圖)
靜態資源緩存(資源名稱加 MD5 戳)
使用 CDN 讓資源加載更快
優化頁面渲染
CSS 放前面,JS 放後面
懶加載(圖片懶加載、下拉加載更多)
減小DOM 查詢,對 DOM 查詢作緩存
減小DOM 操做,多個操做盡可能合併在一塊兒執行(DocumentFragment)
事件節流
儘早執行操做(DOMContentLoaded)
使用 SSR 後端渲染,數據直接輸出到 HTML 中,減小瀏覽器使用 JS 模板渲染頁面 HTML 的時間
7.圖片懶加載與預加載
圖片懶加載的原理就是暫時不設置圖片的src屬性,而是將圖片的url隱藏起來,好比先寫在data-src裏面,等某些事件觸發的時候(好比滾動到底部,點擊加載圖片)再將圖片真實的url放進src屬性裏面,從而實現圖片的延遲加載
圖片預加載是指在一些須要展現大量圖片的網站,實現圖片的提早加載。從而提高用戶體驗。經常使用的方式有兩種,一種是隱藏在css的background的url屬性裏面,一種是經過javascript的Image對象設置實例對象的src屬性實現圖片的預加載。相關代碼以下:
CSS預加載圖片方式:
Javascript預加載圖片的方式:
function preloadImg(url) {
var img = new Image();
img.src = url;
if(img.complete) {
//接下來可使用圖片了 //do something here
} else {
img.onload = function() { //接下來可使用圖片了 //do something here };
}
}
5.描述瀏覽器的渲染過程,DOM樹和渲染樹的區別?
瀏覽器的渲染過程:
解析HTML構建 DOM(DOM樹),並行請求 css/image/js
CSS 文件下載完成,開始構建 CSSOM(CSS樹)
CSSOM 構建結束後,和 DOM 一塊兒生成 Render Tree(渲染樹)
佈局(Layout):計算出每一個節點在屏幕中的位置
顯示(Painting):經過顯卡把頁面畫到屏幕上
DOM樹 和 渲染樹 的區別:
DOM樹與HTML標籤一一對應,包括head和隱藏元素
渲染樹不包括head和隱藏元素,大段文本的每個行都是獨立節點,每個節點都有對應的css屬性
7.重繪和迴流(重排)的區別和關係?
重繪:當渲染樹中的元素外觀(如:顏色)發生改變,不影響佈局時,產生重繪
迴流:當渲染樹中的元素的佈局(如:尺寸、位置、隱藏/狀態狀態)發生改變時,產生重繪迴流
注意:JS獲取Layout屬性值(如:offsetLeft、scrollTop、getComputedStyle等)也會引發迴流。由於瀏覽器須要經過迴流計算最新值
迴流必將引發重繪,而重繪不必定會引發迴流
8.如何最小化重繪(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
9.script 的位置是否會影響首屏顯示時間?
在解析 HTML 生成 DOM 過程當中,js 文件的下載是並行的,不須要 DOM 處理到 script 節點。所以,script的位置不影響首屏顯示的開始時間。
瀏覽器解析 HTML 是自上而下的線性過程,script做爲 HTML 的一部分一樣遵循這個原則
所以,script 會延遲 DomContentLoad,只顯示其上部分首屏內容,從而影響首屏顯示的完成時間
存儲
cookie
cookie 自己不是用來作服務器端存儲的(計算機領域有不少這種「狗拿耗子」的例子,例如 CSS 中的 float),它是設計用來在服務器和客戶端進行信息傳遞的,所以咱們的每一個 HTTP 請求都帶着 cookie。可是 cookie 也具有瀏覽器端存儲的能力(例如記住用戶名和密碼),所以就被開發者用上了。
使用起來也很是簡單,document.cookie = ....便可。
可是 cookie 有它致命的缺點:
存儲量過小,只有 4KB
全部 HTTP 請求都帶着,會影響獲取資源的效率
API 簡單,須要封裝才能用
locationStorage 和 sessionStorage
後來,HTML5 標準就帶來了sessionStorage和localStorage,先拿localStorage來講,它是專門爲了瀏覽器端緩存而設計的。
其優勢有:
存儲量增大到 5MB
不會帶到 HTTP 請求中
API 適用於數據存儲 localStorage.setItem(key, value) localStorage.getItem(key)
sessionStorage的區別就在於它是根據 session 過去時間而實現,而localStorage會永久有效,應用場景不一樣。例如,一些須要及時失效的重要信息放在sessionStorage中,一些不重要可是不常常設置的信息,放在localStorage中。
es6/7
1.說說對es6的理解(說一下es6,知道es6嗎)
語法糖(箭頭函數,類的定義,繼承),以及一些新的擴展(數組,字符串,對象,方法等),對做用域的從新定義,以及異步編程的解決方案(promise,async,await)、解構賦值的出現
2.ES6經常使用特性
變量定義(let和const,可變與不可變,const定義對象的特殊狀況)
解構賦值
模板字符串
數組新API(例:Array.from(),entries(),values(),keys())
箭頭函數(rest參數,擴展運算符,::綁定this)
Set和Map數據結構(set實例成員值惟一存儲key值,map實例存儲鍵值對(key-value))
Promise對象(前端異步解決方案進化史,generator函數,async函數)
Class語法糖(super關鍵字)
3.說說你對Promise的理解
Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件監聽——更合理和更強大。Promise 有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。可是沒法獲取到pending狀態,在promise中接受兩個內置參數分別是resolve(成功)和reject(失敗),Promise實例生成之後,能夠用then方法分別指定resolved狀態和rejected狀態的回調函數。then方法能夠傳遞兩個回調函數第一個是成功,第二個是失敗,失敗回調也可使用promise的catch方法回調,promise還有一個強大的功能那就是all方法能夠組合多個promise實例,包裝成一個新的 Promise 實例。
4.介紹一下async和await;
async 會將其後的函數(函數表達式或 Lambda)的返回值封裝成一個 Promise 對象,而 await 會等待這個 Promise 完成,並將其 resolve 的結果返回出來。
async / await是ES7的重要特性之一,也是目前社區裏公認的優秀異步解決方案。目前async / await 在 IE edge中已經能夠直接使用了,可是chrome和Node.js尚未支持。幸運的是,babel已經支持async的transform了,因此咱們使用的時候引入babel就行。在開始以前咱們須要引入如下的package,preset-stage-3裏就有咱們須要的async/await的編譯文件。
5.es6中的Module
ES6 中模塊化語法更加簡潔,使用export拋出,使用import from 接收,
若是隻是輸出一個惟一的對象,使用export default便可
// 建立 util1.js 文件,內容如
export default {
a: 100
}
// 建立 index.js 文件,內容如
import obj from './util1.js'
若是想要輸出許多個對象,就不能用default了,且import時候要加{...},代碼以下
// 建立 util2.js 文件,內容如
export function fn1() {
alert('fn1')
}
export function fn2() {
alert('fn2')
}
// 建立 index.js 文件,內容如
import { fn1, fn2 } from './util2.js’
6.ES6 class 和普通構造函數的區別
class 其實一直是 JS 的關鍵字(保留字),可是一直沒有正式使用,直到 ES6 。 ES6 的 class 就是取代以前構造函數初始化對象的形式,從語法上更加符合面向對象的寫法
1)class 是一種新的語法形式,是class Name {...}這種形式,和函數的寫法徹底不同
2)二者對比,構造函數函數體的內容要放在 class 中的constructor函數中,constructor即構造器,初始化實例時默認執行
3)class 中函數的寫法是add() {...}這種形式,並無function關鍵字
並且使用 class 來實現繼承就更加簡單了
在class中直接extends關鍵字就能夠實現繼承,而不像以前的繼承實現有多種不一樣的實現方式,在es6中就只有一種
注意如下兩點:
使用extends便可實現繼承,更加符合經典面嚮對象語言的寫法,如 Java
子類的constructor必定要執行super(),以調用父類的constructor
7.ES6 中新增的數據類型有哪些?
Set 和 Map 都是 ES6 中新增的數據結構,是對當前 JS 數組和對象這兩種重要數據結構的擴展。因爲是新增的數據結構
1)Set 相似於數組,但數組能夠容許元素重複,Set 不容許元素重複
2)Map 相似於對象,但普通對象的 key 必須是字符串或者數字,而 Map 的 key 能夠是任何數據類型
8.箭頭函數的做用域上下文和 普通函數做用域上下文 的區別
箭頭函數其實只是一個密名函數的語法糖,區別在於普通函數做用域中的this有特定的指向,通常指向window,而箭頭函數中的this只有一個指向那就是指當前函數所在的對象,其實現原理其實就是相似於以前編程的時候在函數外圍定義that同樣,用了箭頭函數就不用定義that了直接使用this
9.es6如何轉爲es5?
使用Babel 轉碼器,Babel 的配置文件是.babelrc,存放在項目的根目錄下。使用 Babel 的第一步,就是配置這個文件。
算法
1.淺拷貝vs深拷貝
拷貝其實就是對象複製,爲了解決對象複製是產生的引用類型問題
淺拷貝:利用迭代器,循環對象將對象中的全部可枚舉屬性複製到另外一個對象上,可是淺拷貝的有一個問題就是隻是拷貝了對象的一級,其餘級還若是是引用類型的值的話依舊解決不了
深拷貝:深拷貝解決了淺拷貝的問題,利用遞歸的形勢便利對象的每一級,實現起來較爲複雜,得判斷值是數組仍是對象,簡單的說就是,在內存中存在兩個數據結構徹底相同又相互獨立的數據,將引用型類型進行復制,而不是隻複製其引用關係。
2.常見的幾種數組排序算法JS實現
1)快速排序
從給定的數據中,隨機抽出一項,這項的左邊放全部比它小的,右邊放比它大的,而後再分別這兩邊執行上述操做,採用的是遞歸的思想,總結出來就是 實現一層,分別給兩邊遞歸,設置好出口
function fastSort(array,head,tail){
//考慮到給每一個分區操做的時候都是在原有的數組中進行操做的,因此這裏head,tail來肯定分片的位置
/生成隨機項/
var randomnum = Math.floor(ranDom(head,tail));
var random = array[randomnum];
/將小於random的項放置在其左邊 策略就是經過一個臨時的數組來儲存分好區的結果,再到原數組中替換/
var arrayTemp = [];
var unshiftHead = 0;
for(var i = head;i <= tail;i++){
if(array[i]<random){ arrayTemp.unshift(array[i]); unshiftHead++; }else if(array[i]>random){ arrayTemp.push(array[i]); } /*當它等於的時候放哪,這裏我想選擇放到隊列的前面,也就是從unshift後的第一個位置放置*/ if(array[i]===random){ arrayTemp.splice(unshiftHead,0,array[i]); }
}
/將對應項覆蓋原來的記錄/
for(var j = head , u=0;j <= tail;j++,u++){
array.splice(j,1,arrayTemp[u]);
}
/尋找中間項所在的index/
var nowIndex = array.indexOf(random);
/設置出口,當要放進去的片斷只有2項的時候就能夠收工了/
if(arrayTemp.length <= 2){
return;
}
/遞歸,同時應用其左右兩個區域/
fastSort(array,head,nowIndex);
fastSort(array,nowIndex+1,tail);
}
2)插入排序
思想就是在已經排好序的數組中插入到相應的位置,以從小到大排序爲例,掃描已經排好序的片斷的每一項,如大於,則繼續日後,直到他小於一項時,將其插入到這項的前面
function insertSort(array){
/start根據已排列好的項數決定/
var start=1;
/按順序,每一項檢查已排列好的序列/
for(var i=start; i<array.length; start++,i++){
/*跟已排好序的序列作對比,並插入到合適的位置*/ for(var j=0; j<start; j++){ /*小於或者等於時(咱們是升序)插入到該項前面*/ if(array[i]<=array[j]){ console.log(array[i]+' '+array[j]); array.splice(j,0,array[i]); /*刪除原有項*/ array.splice(i+1,1); break; } }
}
}
3)冒泡排序
故名思意 ,就是一個個冒泡到最前端或者最後端,主要是經過兩兩依次比較,以升序爲例,若是前一項比後一項大則交換順序,一直比到最後一對
function bubbleSort(array){
/給每一個未肯定的位置作循環/
for(var unfix=array.length-1; unfix>0; unfix--){
/*給進度作個記錄,比到未肯定位置*/ for(var i=0; i<unfix;i++){ if(array[i]>array[i+1]){ var temp = array[i]; array.splice(i,1,array[i+1]); array.splice(i+1,1,temp); } }
}
}
4)選擇排序
將當前未肯定塊的min或者max取出來插到最前面或者後面
function selectSort(array){
/*給每一個插入後的未肯定的範圍循環,初始是從0開始*/ for(var unfixed=0; unfixed<array.length; unfixed++){ /*設置當前範圍的最小值和其索引*/ var min = array[unfixed]; var minIndex = unfixed; /*在該範圍內選出最小值*/ for(var j=unfixed+1; j<array.length; j++){ if(min>array[j]){ min = array[j]; minIndex = j; } } /*將最小值插入到unfixed,而且把它所在的原有項替換成*/ array.splice(unfixed,0,min); array.splice(minIndex+1,1); } }
3.寫一個數組去重的方法
/** 方法一:
*/
function unique(array){
var result = [];
for(var i = 0;i < array.length; i++){
if(result.indexOf(array[i]) == -1) { result.push(array[i]); }
}
return result;
}
// [1,2,1,2,'1','2',0,'1','你好','1','你好',NaN,NaN] => [1, 2, "1", "2", 0, "你好",NaN,NaN]
// [{id: '1'}, {id: '1'}] => [{id: '1'}, {id: '1’}]
//方法二:ES6
Array.from(new Set(array))
// [1,2,1,2,'1','2',0,'1','你好','1','你好',NaN,NaN] => [1, 2, "1", "2", 0, "你好", NaN]
4.說一下js模板引擎
模板引擎原理總結起來就是:先獲取html中對應的id下得innerHTML,利用開始標籤和關閉標籤進行字符串切分,實際上是將模板劃分紅兩部分內容,一部分是html部分,一部分是邏輯部分,經過區別一些特殊符號好比each、if等來將字符串拼接成函數式的字符串,將兩部分各自通過處理後,再次拼接到一塊兒,最後將拼接好的字符串採用new Function()的方式轉化成所須要的函數。
經常使用的模版引擎主要有,Template.js,handlebars.js
5.是否瞭解公鑰加密和私鑰加密。
通常狀況下是指私鑰用於對數據進行簽名,公鑰用於對簽名進行驗證;
HTTP網站在瀏覽器端用公鑰加密敏感數據,而後在服務器端再用私鑰解密。
6.js深度複製的方式
1)使用jq的$.extend(true, target, obj)
2)newobj = Object.create(sourceObj),// 可是這個是有個問題就是 newobj的更改不會影響到 sourceobj可是 sourceobj的更改會影響到newObj
3)newobj = JSON.parse(JSON.stringify(sourceObj))
7.js設計模式
整體來講設計模式分爲三大類:
建立型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行爲型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模
詳細:詳情
http://www.alloyteam.com/2012...
8.圖片懶加載與預加載?
1)圖片懶加載的原理就是暫時不設置圖片的src屬性,而是將圖片的url隱藏起來,好比先寫在data-src裏面,等某些事件觸發的時候(好比滾動到底部,點擊加載圖片)再將圖片真實的url放進src屬性裏面,從而實現圖片的延遲加載
Javascript預加載圖片的方式:
function preloadImg(url) {
var img = new Image(); img.src = url; if(img.complete) { //接下來可使用圖片了 //do something here } else { img.onload = function() { //接下來可使用圖片了 //do something here }; }
}
2)圖片預加載,是指在一些須要展現大量圖片的網站,實現圖片的提早加載。從而提高用戶體驗。經常使用的方式有兩種,一種是隱藏在css的background的url屬性裏面,一種是經過javascript的Image對象設置實例對象的src屬性實現圖片的預加載。
CSS預加載圖片方式:
9.統計字符串中次數最多字母
function findMaxDuplicateChar(str) {
if(str.length == 1) {
return str;
}
var charObj = {};
for(var i = 0; i < str.length; i++) {
if(!charObj[str.charAt(i)]) { charObj[str.charAt(i)] = 1; } else { charObj[str.charAt(i)] += 1; }
}
var maxChar = '',
maxValue = 1;
for(var k in charObj) {
if(charObj[k] >= maxValue) { maxChar = k; maxValue = charObj[k]; }
}
return maxChar + ':' + maxValue;
}
19.變態題目解析
https://juejin.im/entry/58ada...
11.對Node的優勢和缺點提出了本身的見解?
(優勢)由於Node是基於事件驅動和無阻塞的,因此很是適合處理併發請求,所以構建在Node上的代理服務器相比其餘技術實現(如Ruby)的服務器表現要好得多。此外,與Node代理服務器交互的客戶端代碼是由javascript語言編寫的,所以客戶端和服務器端都用同一種語言編寫,這是很是美妙的事情。
(缺點)Node是一個相對新的開源項目,因此不太穩定,它老是一直在變,並且缺乏足夠多的第三方庫支持。看起來,就像是Ruby/Rails當年的樣子。
模塊化
1.commonjs?requirejs?AMD|CMD|UMD?
1)CommonJS就是爲JS的表現來制定規範,NodeJS是這種規範的實現,webpack 也是以CommonJS的形式來書寫。由於js沒有模塊的功能,因此CommonJS應運而生。但它不能在瀏覽器中運行。 CommonJS定義的模塊分爲:{模塊引用(require)} {模塊定義(exports)} {模塊標識(module)}
2)RequireJS 是一個JavaScript模塊加載器。 RequireJS有兩個主要方法(method): define()和require()。這兩個方法基本上擁有相同的定義(declaration) 而且它們都知道如何加載的依賴關係,而後執行一個回調函數(callback function)。與require()不一樣的是, define()用來存儲代碼做爲一個已命名的模塊。 所以define()的回調函數須要有一個返回值做爲這個模塊定義。這些相似被定義的模塊叫做AMD (Asynchronous Module Definition,異步模塊定義)。
3)AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出 AMD異步加載模塊。它的模塊支持對象 函數 構造器 字符串 JSON等各類類型的模塊。 適用AMD規範適用define方法定義模塊。
4)CMD是SeaJS 在推廣過程當中對模塊定義的規範化產出
AMD與CDM的區別:
(1)對於於依賴的模塊,AMD 是提早執行(好像如今也能夠延遲執行了),CMD 是延遲執行。
(2)AMD 推崇依賴前置,CMD 推崇依賴就近。
(3)AMD 推崇複用接口,CMD 推崇單用接口。
(4)書寫規範的差別。
5)umd是AMD和CommonJS的糅合。
AMD 瀏覽器第一的原則發展 異步加載模塊。
CommonJS模塊以服務器第一原則發展,選擇同步加載,它的模塊無需包裝(unwrapped modules)。這迫令人們又想出另外一個更通用的模式UMD ( Universal Module Definition ), 但願解決跨平臺的解決方案。UMD先判斷是否支持Node.js的模塊( exports )是否存在,存在則使用Node.js模塊模式。
2.模塊化的理解
模塊化的話其實主要就是對於js功能邏輯的劃分,在js中咱們通常都吧一個js文件定義成一個模塊,模塊主要的職責就是(封裝實現,暴露接口,聲明依賴)
3.AMD和CMD的區別
AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出。
CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出。
對於依賴的模塊,AMD 是提早執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不一樣)。CMD 推崇 as lazy as possible.
CMD 推崇依賴就近,AMD 推崇依賴前置。
AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。好比 AMD 裏,require 分全局 require 和局部 require,都叫 require。CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。
前端安全
1.XSS(Cross Site Scripting,跨站腳本攻擊)
這是前端最多見的攻擊方式,不少大型網站(如 Facebook)都被 XSS 攻擊過。
舉一個例子,我在一個博客網站正常發表一篇文章,輸入漢字、英文和圖片,徹底沒有問題。可是若是我寫的是惡意的 JS 腳本,例如獲取到document.cookie而後傳輸到本身的服務器上,那我這篇博客的每一次瀏覽都會執行這個腳本,都會把訪客 cookie 中的信息偷偷傳遞到個人服務器上來。
其實原理上就是黑客經過某種方式(發佈文章、發佈評論等)將一段特定的 JS 代碼隱蔽地輸入進去。而後別人再看這篇文章或者評論時,以前注入的這段 JS 代碼就執行了。JS 代碼一旦執行,那可就不受控制了,由於它跟網頁原有的 JS 有一樣的權限,例如能夠獲取 server 端數據、能夠獲取 cookie 等。因而,攻擊就這樣發生了。
XSS的危害
XSS 的危害至關大,若是頁面能夠隨意執行別人不安全的 JS 代碼,輕則會讓頁面錯亂、功能缺失,重則會形成用戶的信息泄露。
好比早些年社交網站常常爆出 XSS 蠕蟲,經過發佈的文章內插入 JS,用戶訪問了感染不安全 JS 注入的文章,會自動從新發布新的文章,這樣的文章會經過推薦系統進入到每一個用戶的文章列表面前,很快就會形成大規模的感染。
還有利用獲取 cookie 的方式,將 cookie 傳入入侵者的服務器上,入侵者就能夠模擬 cookie 登陸網站,對用戶的信息進行篡改。
XSS的預防
那麼如何預防 XSS 攻擊呢?—— 最根本的方式,就是對用戶輸入的內容進行驗證和替換,須要替換的字符有:
& 替換爲:&
< 替換爲:<
替換爲:>
」 替換爲:"
‘ 替換爲:'
/ 替換爲:/
替換了這些字符以後,黑客輸入的攻擊代碼就會失效,XSS 攻擊將不會輕易發生。
除此以外,還能夠經過對 cookie 進行較強的控制,好比對敏感的 cookie 增長http-only限制,讓 JS 獲取不到 cookie 的內容。
2.CSRF(Cross-site request forgery,跨站請求僞造)
CSRF 是借用了當前操做者的權限來偷偷地完成某個操做,而不是拿到用戶的信息。
例如,一個支付類網站,給他人轉帳的接口是http://buy.com/pay?touid=999&...,而這個接口在使用時沒有任何密碼或者 token 的驗證,只要打開訪問就直接給他人轉帳。一個用戶已經登陸了http://buy.com,在選擇商品時,忽然收到一封郵件,而這封郵件正文有這麼一行代碼,他訪問了郵件以後,其實就已經完成了購買。
CSRF 的發生實際上是藉助了一個 cookie 的特性。咱們知道,登陸了http://buy.com以後,cookie 就會有登陸過的標記了,此時請求http://buy.com/pay?touid=999&... cookie 的,所以 server 端就知道已經登陸了。而若是在http://buy.com去請求其餘域名的 API 例如http://abc.com/api時,是不會帶 cookie 的,這是瀏覽器的同源策略的限制。可是 —— 此時在其餘域名的頁面中,請求http://buy.com/pay?touid=999&...,會帶着buy.com的 cookie ,這是發生 CSRF 攻擊的理論基礎。
Undefined、Null、Boolean、Number、String
typeof xxx獲得的值有如下幾種類型:undefined boolean number string object function、symbol ,比較簡單,再也不一一演示了。
這裏須要注意的有三點:
用於實例和構造函數的對應。例如判斷一個變量是不是數組,使用typeof沒法判斷,但可使用[1, 2] instanceof Array來判斷。由於,[1, 2]是數組,它的構造函數就是Array。同理:
function Foo(name) { this.name = name } var foo = new Foo('bar’) console.log(foo instanceof Foo) // true
Object 是 JavaScript 中全部對象的父對象
數據封裝類對象:Object、Array、Boolean、Number 和 String
其餘對象:Function、Arguments、Math、Date、RegEx、Error
(1)從原型入手,Array.prototype.isPrototypeOf(obj); 利用isPrototypeOf()方法,斷定Array是否是在obj的原型鏈中,若是是,則返回true,不然false。Array.prototype.isPrototype([]) //true
(2)也能夠從構造函數入手,利用對向的constructor屬性
(3)根據對象的class屬性(類屬性),跨原型鏈調用toString()方法。Object.prototype.toString.call(Window);
(4)Array.isArray()方法。
null 表示一個對象被定義了,值爲「空值」;
undefined 表示不存在這個值。
typeof undefined //"undefined"
undefined :是一個表示"無"的原始值或者說表示"缺乏值",就是此處應該有一個值,可是尚未定義。當嘗試讀取時會返回 undefined;
例如變量被聲明瞭,但沒有賦值時,就等於undefined
typeof null //"object"
null : 是一個對象(空對象, 沒有任何屬性和方法);
例如做爲函數的參數,表示該函數的參數不是對象;
在驗證null時,必定要使用 === ,由於 == 沒法分別 null 和 undefined
undefined表示"缺乏值",就是此處應該有一個值,可是尚未定義。典型用法是:
1)變量被聲明瞭,但沒有賦值時,就等於undefined。
2) 調用函數時,應該提供的參數沒有提供,該參數等於undefined。
3)對象沒有賦值的屬性,該屬性的值爲undefined。
4)函數沒有返回值時,默認返回undefined。
典型用法是:
1) 做爲函數的參數,表示該函數的參數不是對象。
2) 做爲對象原型鏈的終點。
(1) 變量聲明提高:變量申明在進入執行上下文就完成了。
只要變量在代碼中進行了聲明,不管它在哪一個位置上進行聲明, js引擎都會將它的聲明放在範圍做用域的頂部;
(2) 函數聲明提高:執行代碼以前會先讀取函數聲明,意味着能夠把函數申明放在調用它的語句後面。
只要函數在代碼中進行了聲明,不管它在哪一個位置上進行聲明, js引擎都會將它的聲明放在範圍做用域的頂部;
(3) 變量or函數聲明:函數聲明會覆蓋變量聲明,但不會覆蓋變量賦值。
同一個名稱標識a,即有變量聲明var a,又有函數聲明function a() {},無論兩者聲明的順序,函數聲明會覆蓋變量聲明,也就是說,此時a的值是聲明的函數function a() {}。注意:若是在變量聲明的同時初始化a,或是以後對a進行賦值,此時a的值變量的值。eg: var a; var c = 1; a = 1; function a() { return true; } console.log(a);
每一個對象都會在其內部初始化一個屬性,就是prototype(原型)
使用hasOwnProperty() 能夠判斷這個屬性是否是對象自己的屬性
問題:Javascript中,有一個函數,執行時對象查找時,永遠不會去查找原型,這個函數是?
hasOwnProperty
javaScript中hasOwnProperty函數方法是返回一個布爾值,指出一個對象是否具備指定名稱的屬性。此方法沒法檢查該對象的原型鏈中是否具備該屬性;該屬性必須是對象自己的一個成員。
使用方法:
object.hasOwnProperty(proName)
其中參數object是必選項。一個對象的實例。
proName是必選項。一個屬性名稱的字符串值。
若是 object 具備指定名稱的屬性,那麼JavaScript中hasOwnProperty函數方法返回 true,反之則返回 false。
當咱們在訪問一個對象的屬性時,若是這個對象內部不存在這個屬性,那麼他就會去prototype裏找這個屬性,這個prototype又會有本身的prototype,因而就這樣一直找下去,找到Object.__proto__爲止,找不到就返回unde也就是咱們平時所說的原型鏈的概念。
關係:instance.constructor.prototype = instance.__proto__
特色:
JavaScript對象是經過引用來傳遞的,咱們建立的每一個新對象實體中並無一份屬於本身的原型副本。當咱們修改原型時,與之相關的對象也會繼承這一改變。
當咱們須要一個屬性的時,Javascript引擎會先看當前對象中是否有這個屬性, 若是沒有的話,就會查找他的Prototype對象是否有這個屬性,如此遞推下去,一直檢索到 Object 內建對象。
全部的引用類型(數組、對象、函數),都具備對象特性,便可自由擴展屬性(null除外)
全部的引用類型(數組、對象、函數),都有一個__proto__屬性,屬性值是一個普通的對象
全部的函數,都有一個prototype屬性,屬性值也是一個普通的對象
全部的引用類型(數組、對象、函數),__proto__屬性值指向它的構造函數的prototype屬性值
全部從原型或更高級原型中獲得、執行的方法,其中的this在執行時,就指向了當前這個觸發事件執行的對象。
閉包的造成與變量的做用域以及變量的生存週期有密切的關係
除了變量做用域以外,另一個跟閉包有關的概念就是變量的生存週期,對於全局變量來講,全局變量的生存週期是永久的,除非咱們主動銷燬這個全局變量,而對於函數內部的使用var聲明的變量來講,當退出函數是,這些變量就會隨着函數的結束而銷燬。
Javascript容許使用內部函數,能夠將函數定義和函數表達式放在另外一個函數的函數體內。並且,內部函數能夠訪問它所在的外部函數聲明的局部變量、參數以及聲明的其餘內部函數。當其中一個這樣的內部函數在包含它們的外部函數以外被調用時,就會造成閉包。常見的閉包寫法就是簡單的函數套函數,經過另外一個函數訪問這個函數的局部變量,利用閉包能夠突破做用域鏈,將函數內部的變量和方法傳遞到外部,延續變量的生命。使用閉包能夠減小全局環境的污染,也可用延續變量的生命。
閉包的適用場景很是普遍,首先從閉包的優勢出發就是:
減小全局環境的污染生成獨立的運行環境
模塊化就是利用這個特色對不一樣的模塊都有本身獨立的運行環境,不會和全局衝突,模塊和模塊之間經過拋出的接口進行依賴使用
以及像咱們經常使用的jquery類庫(避免和全局衝突使用閉包實現本身獨立的環境)
能夠經過返回其餘函數的方式突破做用域鏈
能夠利用這個功能作一些值的緩存工做,例如常見的設計模式(單例模式),以及如今比較火的框架vue中的計算屬性
其實當遇到如下場景的時候均可以使用閉包
1) 維護函數內的變量安全,避免全局變量的污染。
2) 維持一個變量不被回收。
3) 封裝模塊
因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大。因此在閉包不用以後,將不使用的局部變量刪除,使其被回收。在IE中可能致使內存泄露,即沒法回收駐留在內存中的元素,這時候須要手動釋放。
內存泄漏指一塊被分配的內存既不能使用,又不能回收,直到瀏覽器進程結束。
1) 循環引用:含有DOM對象的循環引用將致使大部分當前主流瀏覽器內存泄露。循環 引用,簡單來講假如a引用了b,b又引用了a,a和b就構成了循環引用。
2) JS閉包:閉包,函數返回了內部函數還能夠繼續訪問外部方法中定義的私有變量。
3) Dom泄露,當原有的DOM被移除時,子結點引用沒有被移除則沒法回收。
Javascript中,若是一個對象再也不被引用,那麼這個對象就會被GC(garbage collection)回收。若是兩個對象互相引用,而再也不被第3者所引用,那麼這兩個互相引用的對象也會被回收。垃圾回收不是時時的,由於其開銷比較大,因此垃圾回收器會按照固定的時間間隔週期性的執行。
函數a被b引用,b又被a外的c引用,這就是爲何函數a執行後不會被回收的緣由。
1) 垃圾回收機制給存儲在內存中的全部變量加上標記,而後去掉環境中的變量以及被環境中變量所引用的變量(閉包)。
2) 操做1以後內存中仍存在標記的變量就是要刪除的變量,垃圾回收機制將這些帶有標記的變量回收。
1) 垃圾回收機制給一個變量一個引用次數,當聲明瞭一個變量並將一個引用類型賦值給該變量的時候這個值的引用次數就加1。
2) 當該變量的值變成了另一個值,則這個值得引用次數減1。
3) 當這個值的引用次數變爲0的時候,說明沒有變量在使用,垃圾回收機制會在運行的時候清理掉引用次數爲0的值佔用的空間。
JavaScript引擎是單線程運行的,瀏覽器不管在何時都只且只有一個線程在運行JavaScript程序.瀏覽器的內核是多線程的,它們在內核制控下相互配合以保持同步,一個瀏覽器至少實現三個常駐線程:javascript引擎線程,GUI渲染線程,瀏覽器事件觸發線程。這些異步線程都會產生不一樣的異步的事件.
1) javascript引擎是基於事件驅動單線程執行的,JS引擎一直等待着任務隊列中任務的到來,而後加以處理,瀏覽器不管何時都只有一個JS線程在運行JS程序。
2) GUI渲染線程負責渲染瀏覽器界面,當界面須要重繪(Repaint)或因爲某種操做引起迴流(reflow)時,該線程就會執行。但須要注意 GUI渲染線程與JS引擎是互斥的,當JS引擎執行時GUI線程會被掛起,GUI更新會被保存在一個隊列中等到JS引擎空閒時當即被執行。
3) 事件觸發線程,當一個事件被觸發時該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理。這些事件可來自JavaScript引擎當前執行的代碼塊如setTimeOut、也可來自瀏覽器內核的其餘線程如鼠標點擊、AJAX異步請求等,但因爲JS的單線程關係全部這些事件都得排隊等待JS引擎處理。(當線程中沒有執行任何同步代碼的前提下才會執行異步代碼)
當程序啓動時, 一個進程被建立,同時也運行一個線程, 即爲主線程,js的運行機制爲單線程
程序中跑兩個線程,一個負責程序自己的運行,做爲主線程; 另外一個負責主線程與其餘線程的的通訊,被稱爲「Event Loop 線程" 。每當遇到異步任務,交給 EventLoop 線程,而後本身日後運行,等到主線程運行完後,再去 EventLoop 線程拿結果。
1)全部任務都在主線程上執行,造成一個執行棧(execution context stack)。
2)主線程以外,還存在一個"任務隊列"(task queue)。系統把異步任務放到"任務隊列"之中,而後繼續執行後續的任務。
3)一旦"執行棧"中的全部任務執行完畢,系統就會讀取"任務隊列"。若是這個時候,異步任務已經結束了等待狀態,就會從"任務隊列"進入執行棧,恢復執行。
4)主線程不斷重複上面的第三步。
"回調函數"(callback),就是那些會被主線程掛起來的代碼。異步任務必須指定回調函數,當異步任務從"任務隊列"回到執行棧,回調函數就會執行。"任務隊列"是一個先進先出的數據結構,排在前面的事件,優先返回主線程。主線程的讀取過程基本上是自動的,只要執行棧一清空,"任務隊列"上第一位的事件就自動返回主線程。
主線程從"任務隊列"中讀取事件,這個過程是循環不斷的,因此整個的這種運行機制又稱爲Event Loop。
從主線程的角度看,一個異步過程包括下面兩個要素:
發起函數(或叫註冊函數)A
回調函數callbackFn
它們都是在主線程上調用的,其中註冊函數用來發起異步過程,回調函數用來處理結果。
異步進程有:
相似onclick等,由瀏覽器內核的DOM binding模塊處理,事件觸發時,回調函數添加到任務隊列中;
setTimeout等,由瀏覽器內核的Timer模塊處理,時間到達時,回調函數添加到任務隊列中;
Ajax,由瀏覽器內核的Network模塊處理,網絡請求返回後,添加到任務隊列中。
例如setTimeout(fn, 1000),其中的setTimeout就是異步過程的發起函數,fn是回調函數。用一句話歸納:工做線程將消息放到消息隊列,主線程經過事件循環過程去取消息。
消息隊列:消息隊列是一個先進先出的隊列,它裏面存放着各類消息。
事件循環:事件循環是指主線程重複從消息隊列中取消息、執行的過程。
流程以下:
1) 主線程讀取js代碼, 造成相應的堆和執行棧, 執行同步任務
2) 當主線程遇到異步任務,,指定給異步進程處理, 同時繼續執行同步任務
3) 當異步進程處理完畢後, 將相應的異步任務推入到任務隊列首部
4) 主線程任務處理完畢後,,查詢任務隊列,則取出一個任務隊列推入到主線程的執行棧
5) 重複執行第二、三、4步,這就稱爲事件循環
BOM(瀏覽器對象模型)是瀏覽器自己的一些信息的設置和獲取,例如獲取瀏覽器的寬度、高度,設置讓瀏覽器跳轉到哪一個地址。
navigator: 獲取瀏覽器特性(即俗稱的UA)而後識別客戶端
location: 獲取網址、協議、path、參數、hash 等
history: 操做瀏覽器的歷史紀錄,(前進,後退等功能)
window:它是一個頂層對象,而不是另外一個對象的屬性,即瀏覽器的窗口。
document:表明整個HTML 文檔,可用來訪問頁面中的全部元素
Window 對象表示當前瀏覽器的窗口,是JavaScript的頂級對象。咱們建立的全部對象、函數、變量都是 Window 對象的成員。
Window 對象的方法和屬性是在全局範圍內有效的。
Document 對象是 HTML 文檔的根節點與全部其餘節點(元素節點,文本節點,屬性節點, 註釋節點)
Document 對象使咱們能夠經過腳本對 HTML 頁面中的全部元素進行訪問
Document 對象是 Window 對象的一部分,可經過 window.document 屬性對其進行訪問
1) 咱們在網頁中的某個操做(有的操做對應多個事件)。例如:當咱們點擊一個按鈕就會產生一個事件。是能夠被 JavaScript 偵測到的行爲。
2) 事件處理機制:IE是事件冒泡、Firefox同時支持兩種事件模型,也就是:捕獲型事件和冒泡型事件;
3) ev.stopPropagation();(舊ie的方法 ev.cancelBubble = true;)
事件代理的原理其實就和做用域鏈的原理差很少,可是事件代理是利用事件的冒泡原理來實現的,事件代理就是經過給祖先元素添加事件,經過事件目標對象開始向上查找找到匹配的子節點爲止,若是找不到則到綁定事件的那個祖先元素爲止,找到了就觸發事件,而且能夠經過js中call和apply來改變觸發事件函數中的this爲當前綁定節點,也是經過一層一層逐層向上的方式進行匹配查找而觸發對應事件,好處就是可使後添加的dom元素也一樣有以前存在元素的事件,jquery中可使用on,delegate,live實現的,不過在jquery1.7版本之後吧live給廢除了,緣由就是live綁定事件的祖先元素是整個html頁面的根節點,因此性能消耗比較大,在後邊的版本中給刪除了,使用on,delegate代替
使代碼簡潔
減小瀏覽器的內存佔用
使用不當會形成事件在不該該觸發時觸發
function bindEvent(elem, type, selector, fn) { // 這樣處理,可接收兩種調用方式 bindEvent(div1, 'click', 'a', function () {...}) 和 bindEvent(div1, 'click', function () {...}) 這兩種 if (fn == null) { fn = selector selector = null } // 綁定事件 elem.addEventListener(type, function (e) { var target if (selector) { // 有 selector 說明須要作事件代理 // 獲取觸發時間的元素,即 e.target target = e.target // 看是否符合 selector 這個條件 if (target.matches(selector)) { fn.call(target, e) } } else { // 無 selector ,說明不須要事件代理 fn(e) } }) } // 使用代理,bindEvent 多一個 'a' 參數 var div1 = document.getElementById('div1') bindEvent(div1, 'click', 'a', function (e) { console.log(this.innerHTML) }) // 不使用代理 var a = document.getElementById('a1') bindEvent(div1, 'click', function (e) { console.log(a.innerHTML) })
offsetWidth/offsetHeight返回值包含content + padding + border,效果與e.getBoundingClientRect()相同
clientWidth/clientHeight返回值只包含content + padding,若是有滾動條,也不包含滾動條
scrollWidth/scrollHeight返回值包含content + padding + 溢出內容的尺寸
focus/blur不冒泡,focusin/focusout冒泡
focus/blur兼容性好,focusin/focusout在除FireFox外的瀏覽器下都保持良好兼容性,如需使用事件託管,可考慮在FireFox下使用事件捕獲elem.addEventListener('focus', handler, true)
window
連接被點擊或鍵盤操做
表單空間被點擊或鍵盤操做
設置tabindex屬性的元素被點擊或鍵盤操做
mouseover/mouseout是標準事件,全部瀏覽器都支持;mouseenter/mouseleave是IE5.5引入的特有事件後來被DOM3標準採納,現代標準瀏覽器也支持
mouseover/mouseout是冒泡事件;mouseenter/mouseleave不冒泡。須要爲多個元素監聽鼠標移入/出事件時,推薦mouseover/mouseout託管,提升性能
標準事件模型中event.target表示發生移入/出的元素,vent.relatedTarget對應移出/如元素;在老IE中event.srcElement表示發生移入/出的元素,event.toElement表示移出的目標元素,event.fromElement表示移入時的來源元素
btn.onclick = func;
btn.onclick = null;
btn.addEventListener('click', func, false); btn.removeEventListener('click', func, false); btn.attachEvent("onclick", func); btn.detachEvent("onclick", func);
eventUtil.addListener(input, "textInput", func);
eventUtil 是自定義對象,textInput 是DOM3級事件
捕獲、目標、冒泡
冒泡型事件:事件按照從最特定的事件目標到最不特定的事件目標(document對象)的順序觸發。
捕獲型事件(event capturing):事件從最不精確的對象(document 對象)開始觸發,而後到最精確(也能夠在窗口級別捕獲事件,不過必須由開發人員特別指定)。
DOM事件流:同時支持兩種事件模型:捕獲型事件和冒泡型事件,可是,捕獲型事件先發生。兩種事件流會觸及DOM中的全部對象,從document對象開始,也在document對象結束。
當你使用事件捕獲時,父級元素先觸發,子級元素後觸發,即div先觸發,p後觸發。
當你使用事件冒泡時,子級元素先觸發,父級元素後觸發,即p先觸發,div後觸發。
在捕獲的過程當中stopPropagation();後,後面的冒泡過程也不會發生了。
阻止事件的默認行爲,例如click 後的跳轉
按照W3C標準的事件:首是進入捕獲階段,直到達到目標元素,再進入冒泡階段
事件執行次數(DOM2-addEventListener):元素上綁定事件的個數
注意1:前提是事件被確實觸發
注意2:事件綁定幾回就算幾個事件,即便類型和功能徹底同樣也不會「覆蓋」
事件執行順序:判斷的關鍵是否目標元素
非目標元素:根據W3C的標準執行:捕獲->目標元素->冒泡(不依據事件綁定順序)
目標元素:依據事件綁定順序:先綁定的事件先執行(不依據捕獲冒泡標準)
最終順序:父元素捕獲->目標元素事件1->目標元素事件2->子元素捕獲->子元素冒泡->父元素冒泡
注意:子元素事件執行前提 事件確實「落」到子元素佈局區域上,而不是簡單的具備嵌套關係
在一個DOM上同時綁定兩個點擊事件:一個用捕獲,一個用冒泡。事件會執行幾回,先執行冒泡仍是捕獲?
該DOM上的事件若是被觸發,會執行兩次(執行次數等於綁定次數)
若是該DOM是目標元素,則按事件綁定順序執行,不區分冒泡/捕獲
若是該DOM是處於事件流中的非目標元素,則先執行捕獲,後執行冒泡
通常狀況下,DOMContentLoaded事件要在window.onload以前執行,當DOM樹構建完成的時候就會執行DOMContentLoaded事件,而window.onload是在頁面載入完成的時候,才執行,這其中包括圖片等元素。大多數時候咱們只是想在DOM樹構建完成後,綁定事件到元素,咱們並不須要圖片元素,加上有時候加載外域圖片的速度很是緩慢。
講 DOM 先從 HTML 講起,講 HTML 先從 XML 講起。XML 是一種可擴展的標記語言,所謂可擴展就是它能夠描述任何結構化的數據,它是一棵樹!
document.write只能重繪整個頁面
innerHTML能夠重繪頁面的一部分
1)建立新節點
createDocumentFragment() //建立一個DOM片斷 createElement() //建立一個具體的元素 createTextNode() //建立一個文本節點
2)添加、移除、替換、插入
appendChild() removeChild() replaceChild() insertBefore() //在已有的子節點前插入一個新的子節點
3)查找
getElementsByTagName() //經過標籤名稱 getElementsByName() //經過元素的Name屬性的值(IE容錯能力較強,會獲得一個數組,其中包括id等於name值的) getElementById() //經過元素Id,惟一性
attribute是dom元素在文檔中做爲html標籤擁有的屬性;
property就是dom元素在js中做爲對象擁有的屬性。
因此:
對於html的標準屬性來講,attribute和property是同步的,是會自動更新的,
可是對於自定義的屬性來講,他們是不一樣步的,
src用於替換當前元素,href用於在當前文檔和引用資源之間確立聯繫。
src是source的縮寫,指向外部資源的位置,指向的內容將會嵌入到文檔中當前標籤所在位置;在請求src資源時會將其指向的資源下載並應用到文檔內,當瀏覽器解析到該元素時,會暫停其餘資源的下載和處理,直到將該資源加載、編譯、執行完畢,圖片和框架等元素也如此,相似於將所指向資源嵌入當前標籤內。這也是爲何將js腳本放在底部而不是頭部。
Src source,指向外部資源的位置,若是咱們添加<script src ="js.js"></script>瀏覽器會暫停其餘資源的下載和處理,直到該資源加載,編譯,執行完畢(圖片和框架也是如此),這也就是爲何js腳本要放在底部。
src用於替換當前元素,href用於在當前文檔和引入資源之間創建聯繫。
1,JavaScript繼承的幾種實現方式?
1)構造函數繼承,使用call和apply兩個方法的特性能夠實現,改變方法中的this 2)原型鏈繼承 3)組合式繼承
javascript建立對象簡單的說,無非就是使用內置對象或各類自定義對象,固然還能夠用JSON;但寫法有不少種,也能混合使用。
1) 對象字面量的方式 person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
2) 用function來模擬無參的構造函數
function Person(){}
var person=new Person();//定義一個function,若是使用new"實例化",該function能夠看做是一個Class
person.name=「Mark";
person.age="25";
person.work=function(){
alert(person.name+" hello...");
}
person.work();
3) 用function來模擬參構造函數來實現(用this關鍵字定義構造的上下文屬性)
function Pet(name,age,hobby){
this.name=name;//this做用域:當前對象
this.age=age;
this.hobby=hobby;
this.eat=function(){
alert("我叫"+this.name+",我喜歡"+this.hobby+",是個程序員");
}
}
var maidou =new Pet("麥兜",25,"coding");//實例化、建立對象
maidou.eat();//調用eat方法
4) 用工廠方式來建立(內置對象)
var wcDog =new Object(); wcDog.name="旺財"; wcDog.age=3; wcDog.work=function(){ alert("我是"+wcDog.name+",汪汪汪......"); } wcDog.work(); 五、用原型方式來建立 function Dog(){ } Dog.prototype.name="旺財"; Dog.prototype.eat=function(){alert(this.name+"是個吃貨");} var wangcai =new Dog(); wangcai.eat();
5) 用混合方式來建立
function Car(name,price){ this.name=name; this.price=price; } Car.prototype.sell=function(){ alert("我是"+this.name+",我如今賣"+this.price+"萬元"); } var camry =new Car("凱美瑞",27); camry.sell();
this分爲幾個不一樣的使用場景,在function中this指的的是window,若是是實用new 調用的話this指的是當前的實例化對象,在事件調用函數中this指的調用事件的window特殊的是在IE中的attachEvent中的this老是指向全局對象Window;,在定時器中this指的是window,在es6中有一個箭頭函數,在箭頭函數中this永遠指向的是父級對象,this也是能夠改變的,在js中call, apply, bind均可以改變this的指向, call, apply都是執行一個函數而且改變this,區別就是參數傳遞不同,而bind是返回一個綁定this以後的新函數
use strict是一種ECMAscript 5 添加的(嚴格)運行模式,這種模式使得 Javascript 在更嚴格的條件下運行,
使JS編碼更加規範化的模式,消除Javascript語法的一些不合理、不嚴謹之處,減小一些怪異行爲。
默認支持的糟糕特性都會被禁用,好比不能用with,也不能在乎外的狀況下給全局變量賦值;
全局變量的顯示聲明,函數必須聲明在頂層,不容許在非函數代碼塊內聲明函數,arguments.callee也不容許使用;
消除代碼運行的一些不安全之處,保證代碼運行的安全,限制函數中的arguments修改,嚴格模式下的eval函數的行爲和非嚴格模式的也不相同;
提升編譯器效率,增長運行速度;
爲將來新版本的Javascript標準化作鋪墊。
JSON(JavaScript Object Notation) 是一種輕量級的數據交換格式。
它是基於JavaScript的一個子集。數據格式簡單, 易於讀寫, 佔用帶寬小
如:{"age":"12", "name":"back"}
JSON字符串轉換爲JSON對象:
var obj =eval('('+ str +')'); var obj = str.parseJSON(); var obj = JSON.parse(str);
JSON對象轉換爲JSON字符串:
var last=obj.toJSONString(); var last=JSON.stringify(obj);
函數節流(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); }
建立實例對象,this 變量引用該對象,同時還繼承了構造函數的原型
屬性和方法被加入到 this 引用的對象中
新建立的對象由 this 所引用,而且最後隱式的返回 this
var fn = function () { }; var fnObj = new fn();
1)建立了一個空對象
var obj = new object();
2)設置原型鏈
obj._proto_ = fn.prototype;
3)讓fn的this指向obj,並執行fn的函數體
var result = fn.call(obj);
4)判斷fn的返回值類型,若是是值類型,返回obj。若是是引用類型,就返回這個引用類型的對象。
if (typeof(result) == "object"){ fnObj = result; } else { fnObj = obj;}
網站重構:在不改變外部行爲的前提下,簡化結構、添加可讀性,而在網站前端保持一致的行爲。
也就是說是在不改變UI的狀況下,對網站進行優化,在擴展的同時保持一致的UI。
對於傳統的網站來講重構一般是:
表格(table)佈局改成DIV+CSS
使網站前端兼容於現代瀏覽器(針對於不合規範的CSS、如對IE6有效的)
對於移動平臺的優化
針對於SEO進行優化
深層次的網站重構應該考慮的方面
減小代碼間的耦合
讓代碼保持彈性
嚴格按規範編寫代碼
設計可擴展的API
代替舊有的框架、語言(如VB)
加強用戶體驗
一般來講對於速度的優化也包含在重構中
壓縮JS、CSS、image等前端資源(一般是由服務器來解決)
程序的性能優化(如數據讀寫)
採用CDN來加速資源加載
對於JS DOM的優化
HTTP服務器的文件緩存
1)事件不一樣之處:
1-1,觸發事件的元素被認爲是目標(target)。而在 IE 中,目標包含在 event 對象的 srcElement 屬性;
1-2,獲取字符代碼、若是按鍵表明一個字符(shift、ctrl、alt除外),IE 的 keyCode 會返回字符代碼(Unicode),DOM 中按鍵的代碼和字符是分離的,要獲取字符代碼,須要使用 charCode 屬性;
1-3,阻止某個事件的默認行爲,IE 中阻止某個事件的默認行爲,必須將 returnValue 屬性設置爲 false,Mozilla 中,須要調用 preventDefault() 方法;
1-4,中止事件冒泡,IE 中阻止事件進一步冒泡,須要設置 cancelBubble 爲 true,Mozzilla 中,須要調用 stopPropagation();
優雅降級:Web站點在全部新式瀏覽器中都能正常工做,若是用戶使用的是老式瀏覽器,則代碼會針對舊版本的IE進行降級處理了,使之在舊式瀏覽器上以某種形式降級體驗卻不至於徹底不能用。
如:border-shadow
漸進加強:從被全部瀏覽器支持的基本功能開始,逐步地添加那些只有新版本瀏覽器才支持的功能,向頁面增長不影響基礎瀏覽器的額外樣式和功能的。當瀏覽器支持時,它們會自動地呈現出來併發揮做用。
如:默認使用flash上傳,但若是瀏覽器支持 HTML5 的文件上傳功能,則使用HTML5實現更好的體驗;
嚴格模式主要有如下限制:
變量必須聲明後再使用
函數的參數不能有同名屬性,不然報錯
不能使用with語句
不能對只讀屬性賦值,不然報錯
不能使用前綴0表示八進制數,不然報錯
不能刪除不可刪除的屬性,不然報錯
不能刪除變量delete prop,會報錯,只能刪除屬性delete global[prop]
eval不會在它的外層做用域引入變量
eval和arguments不能被從新賦值
arguments不會自動反映函數參數的變化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局對象
不能使用fn.caller和fn.arguments獲取函數調用的堆棧
增長了保留字(好比protected、static和interface)
設立"嚴格模式"的目的,主要有如下幾個:
消除Javascript語法的一些不合理、不嚴謹之處,減小一些怪異行爲;
消除代碼運行的一些不安全之處,保證代碼運行的安全;
提升編譯器效率,增長運行速度;
爲將來新版本的Javascript作好鋪墊。
注:通過測試IE6,7,8,9均不支持嚴格模式。
根據 navigator.userAgent // UA.toLowerCase().indexOf('chrome')
根據 window 對象的成員 // 'ActiveXObject' in window
優化原則和方向
性能優化的原則是以更好的用戶體驗爲標準,具體就是實現下面的目標:
多使用內存、緩存或者其餘方法
減小 CPU 和GPU 計算,更快展示
優化的方向有兩個:
減小頁面體積,提高網絡加載
優化頁面渲染
減小頁面體積,提高網絡加載
靜態資源的壓縮合並(JS 代碼壓縮合並、CSS 代碼壓縮合並、雪碧圖)
靜態資源緩存(資源名稱加 MD5 戳)
使用 CDN 讓資源加載更快
優化頁面渲染
CSS 放前面,JS 放後面
懶加載(圖片懶加載、下拉加載更多)
減小DOM 查詢,對 DOM 查詢作緩存
減小DOM 操做,多個操做盡可能合併在一塊兒執行(DocumentFragment)
事件節流
儘早執行操做(DOMContentLoaded)
使用 SSR 後端渲染,數據直接輸出到 HTML 中,減小瀏覽器使用 JS 模板渲染頁面 HTML 的時間
圖片懶加載的原理就是暫時不設置圖片的src屬性,而是將圖片的url隱藏起來,好比先寫在data-src裏面,等某些事件觸發的時候(好比滾動到底部,點擊加載圖片)再將圖片真實的url放進src屬性裏面,從而實現圖片的延遲加載
圖片預加載是指在一些須要展現大量圖片的網站,實現圖片的提早加載。從而提高用戶體驗。經常使用的方式有兩種,一種是隱藏在css的background的url屬性裏面,一種是經過javascript的Image對象設置實例對象的src屬性實現圖片的預加載。相關代碼以下:
#preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px; } #preload-02 { background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px; } #preload-03 { background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px; }
function preloadImg(url) { var img = new Image(); img.src = url; if(img.complete) { //接下來可使用圖片了 //do something here } else { img.onload = function() { //接下來可使用圖片了 //do something here }; } }
瀏覽器的渲染過程:
解析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等)也會引發迴流。由於瀏覽器須要經過迴流計算最新值
迴流必將引發重繪,而重繪不必定會引發迴流
須要要對元素進行復雜的操做時,能夠先隱藏(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
在解析 HTML 生成 DOM 過程當中,js 文件的下載是並行的,不須要 DOM 處理到 script 節點。所以,script的位置不影響首屏顯示的開始時間。
瀏覽器解析 HTML 是自上而下的線性過程,script做爲 HTML 的一部分一樣遵循這個原則
所以,script 會延遲 DomContentLoad,只顯示其上部分首屏內容,從而影響首屏顯示的完成時間
cookie 自己不是用來作服務器端存儲的(計算機領域有不少這種「狗拿耗子」的例子,例如 CSS 中的 float),它是設計用來在服務器和客戶端進行信息傳遞的,所以咱們的每一個 HTTP 請求都帶着 cookie。可是 cookie 也具有瀏覽器端存儲的能力(例如記住用戶名和密碼),所以就被開發者用上了。
使用起來也很是簡單,document.cookie = ....便可。
存儲量過小,只有 4KB
全部 HTTP 請求都帶着,會影響獲取資源的效率
API 簡單,須要封裝才能用
後來,HTML5 標準就帶來了sessionStorage和localStorage,先拿localStorage來講,它是專門爲了瀏覽器端緩存而設計的。
存儲量增大到 5MB
不會帶到 HTTP 請求中
API 適用於數據存儲 localStorage.setItem(key, value) localStorage.getItem(key)
sessionStorage的區別就在於它是根據 session 過去時間而實現,而localStorage會永久有效,應用場景不一樣。例如,一些須要及時失效的重要信息放在sessionStorage中,一些不重要可是不常常設置的信息,放在localStorage中。
語法糖(箭頭函數,類的定義,繼承),以及一些新的擴展(數組,字符串,對象,方法等),對做用域的從新定義,以及異步編程的解決方案(promise,async,await)、解構賦值的出現
變量定義(let和const,可變與不可變,const定義對象的特殊狀況)
解構賦值
模板字符串
數組新API(例:Array.from(),entries(),values(),keys())
箭頭函數(rest參數,擴展運算符,::綁定this)
Set和Map數據結構(set實例成員值惟一存儲key值,map實例存儲鍵值對(key-value))
Promise對象(前端異步解決方案進化史,generator函數,async函數)
Class語法糖(super關鍵字)
Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件監聽——更合理和更強大。Promise 有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。可是沒法獲取到pending狀態,在promise中接受兩個內置參數分別是resolve(成功)和reject(失敗),Promise實例生成之後,能夠用then方法分別指定resolved狀態和rejected狀態的回調函數。then方法能夠傳遞兩個回調函數第一個是成功,第二個是失敗,失敗回調也可使用promise的catch方法回調,promise還有一個強大的功能那就是all方法能夠組合多個promise實例,包裝成一個新的 Promise 實例。
async 會將其後的函數(函數表達式或 Lambda)的返回值封裝成一個 Promise 對象,而 await 會等待這個 Promise 完成,並將其 resolve 的結果返回出來。
async / await是ES7的重要特性之一,也是目前社區裏公認的優秀異步解決方案。目前async / await 在 IE edge中已經能夠直接使用了,可是chrome和Node.js尚未支持。幸運的是,babel已經支持async的transform了,因此咱們使用的時候引入babel就行。在開始以前咱們須要引入如下的package,preset-stage-3裏就有咱們須要的async/await的編譯文件。
ES6 中模塊化語法更加簡潔,使用export拋出,使用import from 接收,
若是隻是輸出一個惟一的對象,使用export default便可
// 建立 util1.js 文件,內容如
export default { a: 100 }
// 建立 index.js 文件,內容如
import obj from './util1.js'
若是想要輸出許多個對象,就不能用default了,且import時候要加{...},代碼以下
// 建立 util2.js 文件,內容如
export function fn1() { alert('fn1') } export function fn2() { alert('fn2') }
// 建立 index.js 文件,內容如
import { fn1, fn2 } from './util2.js’
class 其實一直是 JS 的關鍵字(保留字),可是一直沒有正式使用,直到 ES6 。 ES6 的 class 就是取代以前構造函數初始化對象的形式,從語法上更加符合面向對象的寫法
1)class 是一種新的語法形式,是class Name {...}這種形式,和函數的寫法徹底不同
2)二者對比,構造函數函數體的內容要放在 class 中的constructor函數中,constructor即構造器,初始化實例時默認執行
3)class 中函數的寫法是add() {...}這種形式,並無function關鍵字
並且使用 class 來實現繼承就更加簡單了
在class中直接extends關鍵字就能夠實現繼承,而不像以前的繼承實現有多種不一樣的實現方式,在es6中就只有一種
注意如下兩點:
使用extends便可實現繼承,更加符合經典面嚮對象語言的寫法,如 Java
子類的constructor必定要執行super(),以調用父類的constructor
Set 和 Map 都是 ES6 中新增的數據結構,是對當前 JS 數組和對象這兩種重要數據結構的擴展。因爲是新增的數據結構
1)Set 相似於數組,但數組能夠容許元素重複,Set 不容許元素重複
2)Map 相似於對象,但普通對象的 key 必須是字符串或者數字,而 Map 的 key 能夠是任何數據類型
箭頭函數其實只是一個密名函數的語法糖,區別在於普通函數做用域中的this有特定的指向,通常指向window,而箭頭函數中的this只有一個指向那就是指當前函數所在的對象,其實現原理其實就是相似於以前編程的時候在函數外圍定義that同樣,用了箭頭函數就不用定義that了直接使用this
使用Babel 轉碼器,Babel 的配置文件是.babelrc,存放在項目的根目錄下。使用 Babel 的第一步,就是配置這個文件。
拷貝其實就是對象複製,爲了解決對象複製是產生的引用類型問題
淺拷貝:利用迭代器,循環對象將對象中的全部可枚舉屬性複製到另外一個對象上,可是淺拷貝的有一個問題就是隻是拷貝了對象的一級,其餘級還若是是引用類型的值的話依舊解決不了
深拷貝:深拷貝解決了淺拷貝的問題,利用遞歸的形勢便利對象的每一級,實現起來較爲複雜,得判斷值是數組仍是對象,簡單的說就是,在內存中存在兩個數據結構徹底相同又相互獨立的數據,將引用型類型進行復制,而不是隻複製其引用關係。
從給定的數據中,隨機抽出一項,這項的左邊放全部比它小的,右邊放比它大的,而後再分別這兩邊執行上述操做,採用的是遞歸的思想,總結出來就是 實現一層,分別給兩邊遞歸,設置好出口
function fastSort(array,head,tail){ //考慮到給每一個分區操做的時候都是在原有的數組中進行操做的,因此這裏head,tail來肯定分片的位置 /*生成隨機項*/ var randomnum = Math.floor(ranDom(head,tail)); var random = array[randomnum]; /*將小於random的項放置在其左邊 策略就是經過一個臨時的數組來儲存分好區的結果,再到原數組中替換*/ var arrayTemp = []; var unshiftHead = 0; for(var i = head;i <= tail;i++){ if(array[i]<random){ arrayTemp.unshift(array[i]); unshiftHead++; }else if(array[i]>random){ arrayTemp.push(array[i]); } /*當它等於的時候放哪,這裏我想選擇放到隊列的前面,也就是從unshift後的第一個位置放置*/ if(array[i]===random){ arrayTemp.splice(unshiftHead,0,array[i]); } } /*將對應項覆蓋原來的記錄*/ for(var j = head , u=0;j <= tail;j++,u++){ array.splice(j,1,arrayTemp[u]); } /*尋找中間項所在的index*/ var nowIndex = array.indexOf(random); /*設置出口,當要放進去的片斷只有2項的時候就能夠收工了*/ if(arrayTemp.length <= 2){ return; } /*遞歸,同時應用其左右兩個區域*/ fastSort(array,head,nowIndex); fastSort(array,nowIndex+1,tail); }
思想就是在已經排好序的數組中插入到相應的位置,以從小到大排序爲例,掃描已經排好序的片斷的每一項,如大於,則繼續日後,直到他小於一項時,將其插入到這項的前面
function insertSort(array){ /*start根據已排列好的項數決定*/ var start=1; /*按順序,每一項檢查已排列好的序列*/ for(var i=start; i<array.length; start++,i++){ /*跟已排好序的序列作對比,並插入到合適的位置*/ for(var j=0; j<start; j++){ /*小於或者等於時(咱們是升序)插入到該項前面*/ if(array[i]<=array[j]){ console.log(array[i]+' '+array[j]); array.splice(j,0,array[i]); /*刪除原有項*/ array.splice(i+1,1); break; } } } }
故名思意 ,就是一個個冒泡到最前端或者最後端,主要是經過兩兩依次比較,以升序爲例,若是前一項比後一項大則交換順序,一直比到最後一對
function bubbleSort(array){ /*給每一個未肯定的位置作循環*/ for(var unfix=array.length-1; unfix>0; unfix--){ /*給進度作個記錄,比到未肯定位置*/ for(var i=0; i<unfix;i++){ if(array[i]>array[i+1]){ var temp = array[i]; array.splice(i,1,array[i+1]); array.splice(i+1,1,temp); } } } }
將當前未肯定塊的min或者max取出來插到最前面或者後面
function selectSort(array){ /*給每一個插入後的未肯定的範圍循環,初始是從0開始*/ for(var unfixed=0; unfixed<array.length; unfixed++){ /*設置當前範圍的最小值和其索引*/ var min = array[unfixed]; var minIndex = unfixed; /*在該範圍內選出最小值*/ for(var j=unfixed+1; j<array.length; j++){ if(min>array[j]){ min = array[j]; minIndex = j; } } /*將最小值插入到unfixed,而且把它所在的原有項替換成*/ array.splice(unfixed,0,min); array.splice(minIndex+1,1); } }
/** 方法一: * 1.構建一個新的數組存放結果 * 2.for循環中每次從原數組中取出一個元素,用這個元素循環與結果數組對比 * 3.若結果數組中沒有該元素,則存到結果數組中 * 缺陷:不能去重數組中得引用類型的值和NaN */ function unique(array){ var result = []; for(var i = 0;i < array.length; i++){ if(result.indexOf(array[i]) == -1) { result.push(array[i]); } } return result; } // [1,2,1,2,'1','2',0,'1','你好','1','你好',NaN,NaN] => [1, 2, "1", "2", 0, "你好",NaN,NaN] // [{id: '1'}, {id: '1'}] => [{id: '1'}, {id: '1’}] //方法二:ES6 Array.from(new Set(array)) // [1,2,1,2,'1','2',0,'1','你好','1','你好',NaN,NaN] => [1, 2, "1", "2", 0, "你好", NaN]
模板引擎原理總結起來就是:先獲取html中對應的id下得innerHTML,利用開始標籤和關閉標籤進行字符串切分,實際上是將模板劃分紅兩部分內容,一部分是html部分,一部分是邏輯部分,經過區別一些特殊符號好比each、if等來將字符串拼接成函數式的字符串,將兩部分各自通過處理後,再次拼接到一塊兒,最後將拼接好的字符串採用new Function()的方式轉化成所須要的函數。
經常使用的模版引擎主要有,Template.js,handlebars.js
通常狀況下是指私鑰用於對數據進行簽名,公鑰用於對簽名進行驗證;
HTTP網站在瀏覽器端用公鑰加密敏感數據,而後在服務器端再用私鑰解密。
1)使用jq的$.extend(true, target, obj)
2)newobj = Object.create(sourceObj),// 可是這個是有個問題就是 newobj的更改不會影響到 sourceobj可是 sourceobj的更改會影響到newObj
3)newobj = JSON.parse(JSON.stringify(sourceObj))
整體來講設計模式分爲三大類:
建立型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。
結構型模式,共七種:適配器模式、裝飾器模式、代理模式、外觀模式、橋接模式、組合模式、享元模式。
行爲型模式,共十一種:策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模
詳細:詳情
http://www.alloyteam.com/2012...
1)圖片懶加載的原理就是暫時不設置圖片的src屬性,而是將圖片的url隱藏起來,好比先寫在data-src裏面,等某些事件觸發的時候(好比滾動到底部,點擊加載圖片)再將圖片真實的url放進src屬性裏面,從而實現圖片的延遲加載
Javascript預加載圖片的方式:
function preloadImg(url) { var img = new Image(); img.src = url; if(img.complete) { //接下來可使用圖片了 //do something here } else { img.onload = function() { //接下來可使用圖片了 //do something here }; } }
2)圖片預加載,是指在一些須要展現大量圖片的網站,實現圖片的提早加載。從而提高用戶體驗。經常使用的方式有兩種,一種是隱藏在css的background的url屬性裏面,一種是經過javascript的Image對象設置實例對象的src屬性實現圖片的預加載。
CSS預加載圖片方式:
#preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px; } #preload-02 { background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px; } #preload-03 { background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px; }
function findMaxDuplicateChar(str) { if(str.length == 1) { return str; } var charObj = {}; for(var i = 0; i < str.length; i++) { if(!charObj[str.charAt(i)]) { charObj[str.charAt(i)] = 1; } else { charObj[str.charAt(i)] += 1; } } var maxChar = '', maxValue = 1; for(var k in charObj) { if(charObj[k] >= maxValue) { maxChar = k; maxValue = charObj[k]; } } return maxChar + ':' + maxValue; }
https://juejin.im/entry/58ada...
1)CommonJS就是爲JS的表現來制定規範,NodeJS是這種規範的實現,webpack 也是以CommonJS的形式來書寫。由於js沒有模塊的功能,因此CommonJS應運而生。但它不能在瀏覽器中運行。 CommonJS定義的模塊分爲:{模塊引用(require)} {模塊定義(exports)} {模塊標識(module)}
2)RequireJS 是一個JavaScript模塊加載器。 RequireJS有兩個主要方法(method): define()和require()。這兩個方法基本上擁有相同的定義(declaration) 而且它們都知道如何加載的依賴關係,而後執行一個回調函數(callback function)。與require()不一樣的是, define()用來存儲代碼做爲一個已命名的模塊。 所以define()的回調函數須要有一個返回值做爲這個模塊定義。這些相似被定義的模塊叫做AMD (Asynchronous Module Definition,異步模塊定義)。
3)AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出 AMD異步加載模塊。它的模塊支持對象 函數 構造器 字符串 JSON等各類類型的模塊。 適用AMD規範適用define方法定義模塊。
4)CMD是SeaJS 在推廣過程當中對模塊定義的規範化產出
AMD與CDM的區別:
(1)對於於依賴的模塊,AMD 是提早執行(好像如今也能夠延遲執行了),CMD 是延遲執行。
(2)AMD 推崇依賴前置,CMD 推崇依賴就近。
(3)AMD 推崇複用接口,CMD 推崇單用接口。
(4)書寫規範的差別。
5)umd是AMD和CommonJS的糅合。
AMD 瀏覽器第一的原則發展 異步加載模塊。
CommonJS模塊以服務器第一原則發展,選擇同步加載,它的模塊無需包裝(unwrapped modules)。這迫令人們又想出另外一個更通用的模式UMD ( Universal Module Definition ), 但願解決跨平臺的解決方案。UMD先判斷是否支持Node.js的模塊( exports )是否存在,存在則使用Node.js模塊模式。
模塊化的話其實主要就是對於js功能邏輯的劃分,在js中咱們通常都吧一個js文件定義成一個模塊,模塊主要的職責就是(封裝實現,暴露接口,聲明依賴)
AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化產出。
CMD 是 SeaJS 在推廣過程當中對模塊定義的規範化產出。
對於依賴的模塊,AMD 是提早執行,CMD 是延遲執行。不過 RequireJS 從 2.0 開始,也改爲能夠延遲執行(根據寫法不一樣,處理方式不一樣)。CMD 推崇 as lazy as possible.
CMD 推崇依賴就近,AMD 推崇依賴前置。
AMD 的 API 默認是一個當多個用,CMD 的 API 嚴格區分,推崇職責單一。好比 AMD 裏,require 分全局 require 和局部 require,都叫 require。CMD 裏,沒有全局 require,而是根據模塊系統的完備性,提供 seajs.use 來實現模塊系統的加載啓動。CMD 裏,每一個 API 都簡單純粹。
這是前端最多見的攻擊方式,不少大型網站(如 Facebook)都被 XSS 攻擊過。
舉一個例子,我在一個博客網站正常發表一篇文章,輸入漢字、英文和圖片,徹底沒有問題。可是若是我寫的是惡意的 JS 腳本,例如獲取到document.cookie而後傳輸到本身的服務器上,那我這篇博客的每一次瀏覽都會執行這個腳本,都會把訪客 cookie 中的信息偷偷傳遞到個人服務器上來。
其實原理上就是黑客經過某種方式(發佈文章、發佈評論等)將一段特定的 JS 代碼隱蔽地輸入進去。而後別人再看這篇文章或者評論時,以前注入的這段 JS 代碼就執行了。JS 代碼一旦執行,那可就不受控制了,由於它跟網頁原有的 JS 有一樣的權限,例如能夠獲取 server 端數據、能夠獲取 cookie 等。因而,攻擊就這樣發生了。
XSS 的危害至關大,若是頁面能夠隨意執行別人不安全的 JS 代碼,輕則會讓頁面錯亂、功能缺失,重則會形成用戶的信息泄露。
好比早些年社交網站常常爆出 XSS 蠕蟲,經過發佈的文章內插入 JS,用戶訪問了感染不安全 JS 注入的文章,會自動從新發布新的文章,這樣的文章會經過推薦系統進入到每一個用戶的文章列表面前,很快就會形成大規模的感染。
還有利用獲取 cookie 的方式,將 cookie 傳入入侵者的服務器上,入侵者就能夠模擬 cookie 登陸網站,對用戶的信息進行篡改。
那麼如何預防 XSS 攻擊呢?—— 最根本的方式,就是對用戶輸入的內容進行驗證和替換,須要替換的字符有:
& 替換爲:&
< 替換爲:<
替換爲:>
」 替換爲:"
‘ 替換爲:'
/ 替換爲:/
替換了這些字符以後,黑客輸入的攻擊代碼就會失效,XSS 攻擊將不會輕易發生。
除此以外,還能夠經過對 cookie 進行較強的控制,好比對敏感的 cookie 增長http-only限制,讓 JS 獲取不到 cookie 的內容。
CSRF 是借用了當前操做者的權限來偷偷地完成某個操做,而不是拿到用戶的信息。
例如,一個支付類網站,給他人轉帳的接口是http://buy.com/pay?touid=999&...,而這個接口在使用時沒有任何密碼或者 token 的驗證,只要打開訪問就直接給他人轉帳。一個用戶已經登陸了http://buy.com,在選擇商品時,忽然收到一封郵件,而這封郵件正文有這麼一行代碼<img src="[http://buy.com/pay?touid=999&](http://buy.com/pay?touid=999&);money=100"/>,他訪問了郵件以後,其實就已經完成了購買。
CSRF 的發生實際上是藉助了一個 cookie 的特性。咱們知道,登陸了http://buy.com以後,cookie 就會有登陸過的標記了,此時請求http://buy.com/pay?touid=999&... cookie 的,所以 server 端就知道已經登陸了。而若是在http://buy.com去請求其餘域名的 API 例如http://abc.com/api時,是不會帶 cookie 的,這是瀏覽器的同源策略的限制。可是 —— 此時在其餘域名的頁面中,請求http://buy.com/pay?touid=999&...,會帶着buy.com的 cookie ,這是發生 CSRF 攻擊的理論基礎。
預防 CSRF 就是加入各個層級的權限驗證,例如如今的購物網站,只要涉及現金交易,確定要輸入密碼或者指紋才行。除此以外,敏感的接口使用POST請求而不是GET也是很重要的。