1 . 請解釋事件代理 (event delegation)
javascript
當須要對不少元素添加事件的時,能夠經過將事件添加到它們的父節點經過委託來觸發處理函數。其中利用到了瀏覽器的事件冒泡機制。html
var delegate = function(client, clientMethod) { return function() { return clientMethod.apply(client, arguments); } } var agentMethod = delegate (client, clientMethod); agentMethod(); // 獲取父節點,併爲它添加一個click事件 document.getElementById("parent-list").addEventListener("click",function(e) { // 檢查事件源e.targe是否爲Li if(e.target && e.target.nodeName.toUpperCase == "LI") { // 真正的處理過程在這裏 console.log("List item ",e.target.id.replace("post-")," was clicked!"); } });
2 . 談談瀏覽器的事件冒泡機制
java
對於事件的捕獲和處理,不一樣的瀏覽器廠商有不一樣的處理機制,咱們以W3C對DOM2.0定義的標準事件爲例
DOM2.0模型將事件處理流程分爲三個階段:1、事件捕獲階段,2、事件目標階段,3、事件起泡階段。node
事件捕獲:當某個元素觸發某個事件(如onclick),頂層對象document就會發出一個事件流,隨着DOM樹的節點向目標元素節點流去,直到到達事件真正發生的目標元素。在這個過程當中,事件相應的監聽函數是不會被觸發的。git
事件目標:當到達目標元素以後,執行目標元素該事件相應的處理函數。若是沒有綁定監聽函數,那就不執行。github
事件起泡:從目標元素開始,往頂層元素傳播。途中若是有節點綁定了相應的事件處理函數,這些函數都會被一次觸發。若是想阻止事件起泡,可使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)來組織事件的冒泡傳播。ajax
3 . JavaScript 中 this 是如何工做的。
編程
4 . 談談CommonJs 、AMD 和CMD
數組
CommonJS規範,一個單獨的文件就是一個模塊。每個模塊都是一個單獨的做用域 CommonJS的使用表明:NodeJS瀏覽器
AMD 即Asynchronous Module Definition 異步模塊定義 它是一個在瀏覽器端模塊化開發的規範 AMD 是 RequireJS 在推廣過程當中對模塊定義的規範化的產出
CMD 即Common Module Definition 通用模塊定義 其表明爲SeaJS
requireJS主要解決兩個問題
CMD和AMD的區別
5 . 談談對IIFE的理解
IIFE即Immediately-Invoked Function Expression 當即執行函數表達式
不推薦
(function(){})();
推薦
(function(){}());
在javascript裏,括號內部不能包含語句,當解析器對代碼進行解釋的時候,先碰到了(),而後碰到function關鍵字就會自動將()裏面的代碼識別爲函數表達式而不是函數聲明。
知識拓展:
function(){ /* code */ }(); 解釋下該代碼能正確執行嗎?
不行,在javascript代碼解釋時,當遇到function關鍵字時,會默認把它當作是一個函數聲明,而不是函數表達式,若是沒有把它顯視地表達成函數表達式,就報錯了,由於函數聲明須要一個函數名,而上面的代碼中函數沒有函數名。(以上代碼,也正是在執行到第一個左括號(時報錯,由於(前理論上是應該有個函數名的。)
function foo(){ /* code */ }(); 解釋下該代碼能正確執行嗎?
在一個表達式後面加上括號,表示該表達式當即執行;而若是是在一個語句後面加上括號,該括號徹底和以前的語句沒法匹配,而只是一個分組操做符,用來控制運算中的優先級(小括號裏的先運算)至關於先聲明瞭一個叫foo的函數,以後進行()內的表達式運算,可是()(分組操做符)內的表達式不能爲空,因此報錯。(以上代碼,也就是執行到右括號時,發現表達式爲空,因此報錯)。
6 . .call 和 .apply 的區別是什麼?
foo.call(this, arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)
call, apply方法區別是,從第二個參數起, call方法參數將依次傳遞給借用的方法做參數, 而apply直接將這些參數放到一個數組中再傳遞, 最後借用方法的參數列表是同樣的.
7 . 請解釋 Function.prototype.bind?
bind() 方法的主要做用就是將函數綁定至某個對象,bind() 方法會建立一個函數,函數體內this對象的值會被綁定到傳入bind() 函數的值。
原理
Function.prototype.bind = function(context) { var self = this; // 保存原函數 return function() { // 返回一個新函數 return self.apply(context, arguments); // 執行新函數時,將傳入的上下文context做爲新函數的this } }
用法:
var paint = { color: "red", count: 0, updateCount: function() { this.count++; console.log(this.count); } }; // 事件處理函數綁定的錯誤方法: document.querySelector('button') .addEventListener('click', paint.updateCount); // paint.updateCount函數的this指向變成了該DOM對象 // 事件處理函數綁定的正確方法: document.querySelector('button') .addEventListener('click', paint.updateCount.bind(paint)); // paint.updateCount函數的this指向變成了paint
8 . 請解釋原型繼承 (prototypal inheritance) 的原理。
當查找一個對象的屬性時,JavaScript 會向上遍歷原型鏈,直到找到給定名稱的屬性爲止。——出自JavaScript祕密花園
JavaScript中的每一個對象,都有一個內置的 proto 屬性。這個屬性是編程不可見的(雖然ES6標準中開放了這個屬性,然而瀏覽器對這個屬性的可見性的支持不一樣),它其實是對另外一個對象或者 null 的引用。
當一個對象須要引用一個屬性時,JavaScript引擎首先會從這個對象自身的屬性表中尋找這個屬性標識,若是找到則進行相應讀寫操做,若沒有在自身的屬性表中找到,則在 proto 屬性引用的對象的屬性表中查找,如此往復,直到找到這個屬性或者 proto 屬性指向 null 爲止。
如下代碼展現了JS引擎如何查找屬性:
//__proto__ 是一個不該在你代碼中出現的非正規的用法,這裏僅僅用它來解釋JavaScript原型繼承的工做原理。 function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)) return obj[prop] else if (obj.__proto__ !== null) return getProperty(obj.__proto__, prop) else return undefined }
JS的ECMA規範只容許咱們採用 new 運算符來進行原型繼承
原型繼承
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p = new Point(10, 20); p.print(); // 10 20
順便闡述下new 運算符是如何工做的?
function New (f) { var n = { '__proto__': f.prototype }; /*第一步*/ return function () { f.apply(n, arguments); /*第二步*/ return n; /*第三步*/ }; }
JavaScript中真正的原型繼承
Object.create = function (parent) { function F() {} F.prototype = parent; return new F(); };
使用真正的原型繼承(如 Object.create 以及 proto)仍是存在如下缺點:
ES6 內部實現類和類的繼承
class Parent { constructor(name) { //構造函數 this.name = name; } say() { console.log("Hello, " + this.name + "!"); } } class Children extends Parent { constructor(name) { //構造函數 super(name); //調用父類構造函數 // ... } say() { console.log("Hello, " + this.name + "! hoo~~"); } }
參考:
9 . 請儘量詳盡的解釋 AJAX 的工做原理
Ajax 的原理簡單來講經過 XmlHttpRequest 對象來向服務器發異步請求,從服務器得到數據,而後用 JavaScript來操做 DOM 而更新頁面。 這其中最關鍵的一步就是從服務器得到請求數據。
不使用ajax工做原理
使用ajax工做原理
10 . javascript中"attribute" 和 "property" 的區別是什麼?
property 和 attribute很是容易混淆,兩個單詞的中文翻譯也都很是相近(property:屬性,attribute:特性),但實際上,兩者是不一樣的東西,屬於不一樣的範疇。每個DOM對象都會有它默認的基本屬性,而在建立的時候,它只會建立這些基本屬性,咱們在TAG標籤中自定義的屬性是不會直接放到DOM中的。