摘要:請解釋事件代理事件代理也稱為事件委托,利用了事件冒泡。同源指的是協(xié)議域名端口相同,同源策略是一種安全協(xié)議。目的同源策略保證了用戶的信息安全,瀏覽器打開多個站點時,互相之間不能利用獲取對方站點的敏感信息。
請解釋事件代理(event delegation)
事件代理也稱為事件委托,利用了事件冒泡。例如:
當(dāng)頁面li增多時多帶帶給每個li元素添加事件處理程序既繁瑣又容易出錯,利用事件冒泡,在ul去監(jiān)聽事件,li產(chǎn)生事件往上冒泡時去捕獲,利用e.target來判斷是否為我們的目標(biāo)元素,是的話就可以做相應(yīng)操作了。
請解釋JavaScript中this是如何工作的。作為獨立函數(shù)的調(diào)用
function func(){ console.log(this); } func(); //Window
全局作用域中聲明一個函數(shù),并調(diào)用它,此時函數(shù)中的this指向全局對象。
作為對象方法調(diào)用
function say(){ console.log(this); } var obj = { name: "f2er", say: say }; obj.say(); //Object {name: "f2er"}
當(dāng)函數(shù)作為一個對象的方法調(diào)用時,函數(shù)中的this綁定到了這個對象。
使用call或apply來調(diào)用函數(shù)
function func(){ console.log(this); } var obj = { name:"f2er" }; func.call(obj); //Object {name: "f2er"} func.apply(obj); //Object {name: "f2er"}
當(dāng)使用call()或apply()函數(shù)進行函數(shù)調(diào)用時,傳入?yún)?shù)對象的將被設(shè)置為函數(shù)體內(nèi)this的值,這兩個函數(shù)都是設(shè)置調(diào)用函數(shù)體內(nèi)的this值的,且第一個參數(shù)都為this,區(qū)別是第二個參數(shù)apply()是一個參數(shù)arguments(類數(shù)組對象),而call(),傳遞給他的是一系列參數(shù)。
new來調(diào)用函數(shù)
function F2er(name){ this.name = name; console.log(this); } var f2er = new F2er("f2er"); // F2er {name: "f2er"}
當(dāng)使用new來調(diào)用一個函數(shù)時,會創(chuàng)建一個新的對象,然后綁定到Dog()調(diào)用中的this。
請解釋原型繼承(prototypal inheritance)的原理。先上一個例子:
function Super(){ this.superValue = "super"; } Super.prototype.getSuperValue = function (){ return this.superValue; } function Sub(){ this.subValue = "sub"; } var superInstance = new Super(); Sub.prototype = superInstance; Sub.prototype.getSubValue = function (){ return this.subValue; } var instance = new Sub(); console.log(instance.getSuperValue()); // super
每個函數(shù)Sub都有一個屬性prototype,prototype指向一個原型對象,原型對象中也有一個指向函數(shù)的屬性constructor,通過new一個函數(shù)Sub可以產(chǎn)生實例instance,調(diào)用這個instance的某個屬性或方法時,instance會先查找自身是否有這個方法或者屬性,沒有的話就會去實例的構(gòu)造函數(shù)Sub的原型prototype中查找,即Sub.prototype,如果給原型對象Sub.prototype賦予另一個類型的實例superInstance,則是在superInstance中查找的,這個superInstance中也有屬性prototype指向某個原型對象,以此一級級往上最終到Object.prototype,這樣就形成了原型繼承。
利用此原理可以自己實現(xiàn)一個inherits函數(shù):
function inherits(subType, superType){ var _prototype = Object.create(superType.prototype); _prototype.constructor = subType; subType.prototype = _prototype; }IIFE(立即調(diào)用的函數(shù)表達式)是什么?有什么作用?
(function fn(){..})(),函數(shù)被包含在一個括號內(nèi),變成為一個表達式,隨后跟著一個(),就立即執(zhí)行這個函數(shù),
這種模式就是立即執(zhí)行函數(shù)表達式(Immediately Invoked Function Expression),簡稱IIFE。
?也有用(function fn(){..}())后面的括號在前面的括號內(nèi)這種形式表示的,這兩種形式在功能上都是一致的。
IIFE的一些作用:
創(chuàng)建作用域,內(nèi)部保存一些大量臨時變量的代碼防止命名沖突。
一些庫的外層用這種形式包起來防止作用域污染。
運行一些只執(zhí)行一次的代碼。
(function(){ var module = require("module"); module.setup(); module.run(); })();
用閉包保存狀態(tài)
以下點擊頁面標(biāo)簽的時候,實際并不是彈出每個具體的i的,而是elems.length,因為每個a監(jiān)聽器中引用的i都是同一個作用域的。
var elems = document.getElementsByTagName("a"); for (var i = 0; i < elems.length; i++) { elems[i].addEventListener("click", function (e) { e.preventDefault(); alert("I am link #" + i); }, "false"); }
以下點擊頁面標(biāo)簽的時候,每一個i傳入一個IIFE,IIFE形成多帶帶一個作用域保存了當(dāng)時的i值,所以點擊a標(biāo)簽,可以彈出不同的i值。
var elems = document.getElementsByTagName("a"); for (var i = 0; i < elems.length; i++) { (function (lockedInIndex) { elems[i].addEventListener("click", function (e) { e.preventDefault(); alert("I am link #" + lockedInIndex); }, "false"); })(i); }什么是閉包(closure),有什么作用?
當(dāng)某個函數(shù)調(diào)用時會創(chuàng)建一個執(zhí)行環(huán)境以及作用域鏈,然后根據(jù)arguments和其它命名參數(shù)初始化形成活動對象。在外部函數(shù)調(diào)用結(jié)束后,其執(zhí)行環(huán)境與作用域鏈被銷毀,但是其活動對象保存在了閉包之中,最后在閉包函數(shù)調(diào)用結(jié)束后才銷毀。簡單的說,閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。在js中,閉包是指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)。
閉包的作用匿名自執(zhí)行函數(shù)
有的場景下函數(shù)只需要執(zhí)行一次,例如init()之類的函數(shù),其內(nèi)部變量無需維護,我們可以使用閉包。 我們創(chuàng)建了一個匿名的函數(shù),并立即執(zhí)行它,由于外部無法引用它內(nèi)部的變量,因此在函數(shù)執(zhí)行完后會立刻釋放資源,而且不污染全局對象。
封裝
模擬面向?qū)ο蟮拇a風(fēng)格進行封裝,使私有屬性存在成為可能。
缺點常駐內(nèi)存,會增大內(nèi)存使用量,易造成內(nèi)存泄露
請指出JavaScript宿主對象和原生對象的區(qū)別?宿主對象是指DOM和BOM。
原生對象是Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、Math等對象。
請指出以下代碼的區(qū)別:function Person(){}、var person = Person()、var person = new Person()?function Person(){}
聲明一個函數(shù)Person()。
var person = Person()
將函數(shù)Person()的結(jié)果返回給變量person,如果沒有返回值則person為undefined。
var person = new Person()
new一個Person的實例對象。
.call和.apply的區(qū)別是什么?.call和.apply的共同點是都是用來改變函數(shù)體內(nèi)this對象的值。
區(qū)別是第二個參數(shù)不一樣。apply()的第二個參數(shù)是一個類數(shù)組對象arguments,參數(shù)都是以數(shù)組的形式傳入,而call(),傳遞給他的是一系列參數(shù)。例如
Math.max.call(null, 1, 2, 3, 4); //4 Math.max.apply(null, [1, 2, 3, 4]); //4請解釋Function.prototype.bind
Function.prototype.bind方法會創(chuàng)建一個新函數(shù),當(dāng)這個新函數(shù)被調(diào)用時,它的this值是傳遞給bind()的第一個參數(shù), 它的參數(shù)是bind()的其他參數(shù)和其原本的參數(shù).
Function.prototype.bind的實現(xiàn)類似于:
Function.prototype.bind = function (scope) { var fn = this; return function () { return fn.apply(scope, arguments); }; }
Function.prototype.bind的作用
創(chuàng)建綁定函數(shù)
一些函數(shù)的參數(shù)常常也是函數(shù),給當(dāng)做參數(shù)的函數(shù)綁定this值確保參數(shù)函數(shù)執(zhí)行時有正確的this指向。
Ajax的工作原理原理Ajax是無需刷新頁面就能從服務(wù)器取得數(shù)據(jù)的一種方法。
Ajax通過XmlHttpRequest對象來向服務(wù)器發(fā)異步請求,從服務(wù)器獲得數(shù)據(jù),然后用javascript來操作DOM更新頁面。
過程創(chuàng)建XMLHttpRequest對象。
設(shè)置響應(yīng)HTTP請求的回調(diào)函數(shù)。
創(chuàng)建一個HTTP請求,指定相應(yīng)的請求方法、url等。
發(fā)送HTTP請求。
獲取服務(wù)器端返回的數(shù)據(jù)。
使用JavaScript操作DOM更新頁面。
缺點對搜索引擎不友好
要實現(xiàn)Ajax下的前后退功能成本較大
跨域問題限制
JSONP的工作原理JSONP(JSON with Padding)是一種非官方跨域數(shù)據(jù)交互協(xié)議,它允許在服務(wù)器端集成