(event delegation)
事件代理也稱爲事件委託,利用了事件冒泡。例如:javascript
<ul class="item-list"> <li class="item">item1</li> <li class="item">item2</li> <li class="item">item3</li> </ul>
當頁面li
增多時單獨給每一個li
元素添加事件處理程序既繁瑣又容易出錯,利用事件冒泡,在ul
去監聽事件,li
產生事件往上冒泡時去捕獲,利用e.target
來判斷是否爲咱們的目標元素,是的話就能夠作相應操做了。html
JavaScript
中this
是如何工做的。做爲獨立函數的調用java
function func(){ console.log(this); } func(); //Window
全局做用域中聲明一個函數,並調用它,此時函數中的this指向全局對象。json
做爲對象方法調用跨域
function say(){ console.log(this); } var obj = { name: "f2er", say: say }; obj.say(); //Object {name: "f2er"}
當函數做爲一個對象的方法調用時,函數中的this
綁定到了這個對象。數組
使用call或apply來調用函數瀏覽器
function func(){ console.log(this); } var obj = { name:"f2er" }; func.call(obj); //Object {name: "f2er"} func.apply(obj); //Object {name: "f2er"}
當使用call()
或apply()
函數進行函數調用時,傳入參數對象的將被設置爲函數體內this
的值,這兩個函數都是設置調用函數體內的this
值的,且第一個參數都爲this
,區別是第二個參數apply()
是一個參數arguments
(類數組對象),而call()
,傳遞給他的是一系列參數。安全
new
來調用函數服務器
function F2er(name){ this.name = name; console.log(this); } var f2er = new F2er('f2er'); // F2er {name: "f2er"}
當使用new
來調用一個函數時,會建立一個新的對象,而後綁定到Dog()
調用中的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
每一個函數Sub
都有一個屬性prototype
,prototype
指向一個原型對象,原型對象中也有一個指向函數的屬性constructor
,經過new
一個函數Sub
能夠產生實例instance
,調用這個instance
的某個屬性或方法時,instance
會先查找自身是否有這個方法或者屬性,沒有的話就會去實例的構造函數Sub
的原型prototype
中查找,即Sub.prototype
,若是給原型對象Sub.prototype
賦予另外一個類型的實例superInstance
,則是在superInstance
中查找的,這個superInstance
中也有屬性prototype
指向某個原型對象,以此一級級往上最終到Object.prototype
,這樣就造成了原型繼承。
利用此原理能夠本身實現一個inherits函數:
function inherits(subType, superType){ var _prototype = Object.create(superType.prototype); _prototype.constructor = subType; subType.prototype = _prototype; }
(function fn(){..})(),函數被包含在一個括號內,變成爲一個表達式,隨後跟着一個(),就當即執行這個函數,
這種模式就是當即執行函數表達式(Immediately Invoked Function Expression),簡稱IIFE。
也有用(function fn(){..}())後面的括號在前面的括號內這種形式表示的,這兩種形式在功能上都是一致的。
IIFE的一些做用:
建立做用域,內部保存一些大量臨時變量的代碼防止命名衝突。
一些庫的外層用這種形式包起來防止做用域污染。
運行一些只執行一次的代碼。
(function(){ var module = require('module'); module.setup(); module.run(); })();
用閉包保存狀態
如下點擊頁面標籤的時候,實際並非彈出每一個具體的i
的,而是elems.length
,由於每一個a
監聽器中引用的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'); }
如下點擊頁面標籤的時候,每個i
傳入一個IIFE
,IIFE
造成單獨一個做用域保存了當時的i
值,因此點擊a
標籤,能夠彈出不一樣的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); }
當某個函數調用時會建立一個執行環境以及做用域鏈,而後根據arguments
和其它命名參數初始化造成活動對象。在外部函數調用結束後,其執行環境與做用域鏈被銷燬,可是其活動對象保存在了閉包之中,最後在閉包函數調用結束後才銷燬。簡單的說,閉包就是可以讀取其餘函數內部變量的函數。在js
中,閉包是指有權訪問另外一個函數做用域中的變量的函數。
匿名自執行函數
有的場景下函數只須要執行一次,例如init()
之類的函數,其內部變量無需維護,咱們可使用閉包。 咱們建立了一個匿名的函數,並當即執行它,因爲外部沒法引用它內部的變量,所以在函數執行完後會馬上釋放資源,並且不污染全局對象。
封裝
模擬面向對象的代碼風格進行封裝,使私有屬性存在成爲可能。
常駐內存,會增大內存使用量,易形成內存泄露
JavaScript
宿主對象和原生對象的區別?宿主對象是指DOM
和BOM
。
原生對象是Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、Math
等對象。
function Person(){}、var person = Person()、var person = new Person()
?function Person(){}
聲明一個函數Person()
。
var person = Person()
將函數Person()
的結果返回給變量person
,若是沒有返回值則person
爲undefined
。
var person = new Person()
new
一個Person
的實例對象。
.call
和.apply
的區別是什麼?.call
和.apply
的共同點是都是用來改變函數體內this
對象的值。
區別是第二個參數不同。apply()
的第二個參數是一個類數組對象arguments
,參數都是以數組的形式傳入,而call()
,傳遞給他的是一系列參數。例如
Math.max.call(null, 1, 2, 3, 4); //4 Math.max.apply(null, [1, 2, 3, 4]); //4
Function.prototype.bind
Function.prototype.bind
方法會建立一個新函數,當這個新函數被調用時,它的this
值是傳遞給bind()
的第一個參數, 它的參數是bind()
的其餘參數和其本來的參數.
Function.prototype.bind
的實現相似於:
Function.prototype.bind = function (scope) { var fn = this; return function () { return fn.apply(scope, arguments); }; }
Function.prototype.bind
的做用
建立綁定函數
一些函數的參數經常也是函數,給當作參數的函數綁定this
值確保參數函數執行時有正確的this
指向。
Ajax
的工做原理
Ajax
是無需刷新頁面就能從服務器取得數據的一種方法。
Ajax
經過XmlHttpRequest
對象來向服務器發異步請求,從服務器得到數據,而後用javascript
來操做DOM
更新頁面。
建立XMLHttpRequest
對象。
設置響應HTTP
請求的回調函數。
建立一個HTTP
請求,指定相應的請求方法、url
等。
發送HTTP
請求。
獲取服務器端返回的數據。
使用JavaScript
操做DOM
更新頁面。
對搜索引擎不友好
要實現Ajax
下的先後退功能成本較大
跨域問題限制
JSONP
的工做原理
JSONP(JSON with Padding)
是一種非官方跨域數據交互協議,它容許在服務器端集成<script>
標籤返回至客戶端,經過javascript
回調的形式實現跨域訪問。
由於同源策略的緣由,咱們不能使用XMLHttpRequest
與外部服務器進行通訊,可是<script>
能夠訪問外部資源,因此經過JSON
與<script>
相結合的辦法,能夠繞過同源策略從外部服務器直接取得可執行的JavaScript
函數。
客戶端定義一個函數,好比jsonpCallback
,而後建立<script>
,src
爲url + ?jsonp=jsonpCallback
這樣的形式,以後服務器會生成一個和傳遞過來jsonpCallback
同樣名字的參數,並把須要傳遞的數據當作參數傳入,好比jsonpCallback(json)
,而後返回給客戶端,此時客戶端就執行了這個服務器端返回的jsonpCallback(json)
回調。
通俗的說,就是客戶端定義一個函數而後請求,服務器端返回的javascript
內容就是調用這個函數,須要的數據都當作參數傳入這個函數了。
優勢 - 兼容性好,簡單易用,支持瀏覽器與服務器雙向通訊
缺點 - 只支持GET請求;存在腳本注入以及跨站請求僞造等安全問題
補充一點,JSONP
不使用XMLHttpRequest
對象加載資源,不屬於真正意義上的AJAX
。
變量的聲明前置就是把變量的聲明提高到當前做用域的最前面。
函數的聲明前置就是把整個函數提高到當前做用域的最前面(位於前置的變量聲明後面)。
//變量的聲明前置 console.log(num);//undefined var num = 1; 等價於 //變量的聲明前置 var num; console.log(num);//undefined num = 1;
//函數的聲明前置 var num = 1; console.log(doubleNum(num));//2 function doubleNum(num){ return num*2; } 等價於 //函數的聲明前置 var num; function doubleNum(num){ return num*2; } num = 1; console.log(doubleNum(num));//2
事件冒泡(event bubbling),事件最開始時由觸發的那個元素身上發生,而後沿着DOM
樹向上傳播,直到document
對象。若是想阻止事件起泡,可使用e.stopPropagation()
。
JavaScript
的同源策略同源策略限制了一個源(origin)中加載文本或腳本與來自其它源(origin)中資源的交互方式。同源指的是協議、域名、端口相同,同源策略是一種安全協議。
同源策略保證了用戶的信息安全,瀏覽器打開多個站點時,互相之間不能利用JavaScript
獲取對方站點的敏感信息。
JSONP
CORS
修改document.domain來進行跨域
使用window.name來進行跨域
使用window.postMessage來進行跨域
"use strict"
?使用它的好處和壞處分別是什麼?在全部語句以前放一個特定語句
"use strict"
,就會爲整個script標籤開啓嚴格模式。
消除Javascript
語法的一些不嚴謹之處,減小一些怪異行爲;
消除代碼運行的一些不安全之處,保證代碼運行的安全;
提升編譯器效率,增長運行速度;
爲將來新版本的Javascript
作好鋪墊。
嚴格模式改變了語義。依賴這些改變可能會致使沒有實現嚴格模式的瀏覽器中出現問題或者錯誤。