摘要:用函數(shù)構(gòu)造器進(jìn)行求值中的所有函數(shù)都是的實(shí)例,可以直接使用構(gòu)造器來實(shí)例化函數(shù)。構(gòu)造器可變參數(shù)列表的最后一個(gè)參數(shù),始終是要?jiǎng)?chuàng)建函數(shù)的函數(shù)體內(nèi)容。
1. JavaScript常用測試框架:
2. 斷言:QUnit
YUI Test
JsUnit
Jasmine
單元測試框架的核心是斷言方法,通常叫做assert()。該方法通常接受一個(gè)值——需要斷言的值,以及一個(gè)表示該斷言目的的描述。如果該值執(zhí)行結(jié)果為true,斷言就會(huì)通過;否則斷言就會(huì)被認(rèn)為是失敗的。3. 函數(shù)是第一型對象:
對象在JavaScript中有如下功能:
它們可以通過字面量進(jìn)行創(chuàng)建;
它們可以賦值給變量、數(shù)組或其他對象的屬性;
它們可以作為參數(shù)傳遞給函數(shù);
它們可以作為函數(shù)的返回值進(jìn)行返回;
它們可以擁有動(dòng)態(tài)創(chuàng)建并賦值的屬性;
在JavaScript中,函數(shù)擁有全部這些功能,也就是說可以像這門語言中的其他對象一樣使用。因此,我們說函數(shù)是第一型對象。函數(shù)還有一個(gè)特殊的功能,它們可以被調(diào)用。
4. 瀏覽器的事件輪詢:瀏覽器的事件輪詢是單線程的,每個(gè)事件都是按照在隊(duì)列中所放置的順序來處理的。5. 回調(diào)概念:
當(dāng)我們定義一個(gè)函數(shù)稍后執(zhí)行時(shí),無論何時(shí)定義,在瀏覽器執(zhí)行還是在其他地方執(zhí)行,我們定義的就是所謂的回調(diào)。6. 函數(shù)聲明:
7. 作用域和函數(shù):JavaScript函數(shù)是使用函數(shù)字面量進(jìn)行聲明從而創(chuàng)建函數(shù)值的,就像使用數(shù)字字面量創(chuàng)建數(shù)字值一樣。
函數(shù)字面量由四個(gè)部分組成:function關(guān)鍵字;
可選名稱;
括號內(nèi)部的參數(shù);
函數(shù)體,包含在大括號內(nèi)的一系列JavaScript語句;
8. 使用apply()和call()方法:在Javascript中,作用域是由function進(jìn)行聲明的,而不是代碼塊。聲明的作用域創(chuàng)建于代碼塊,但不是終結(jié)于代碼塊。
例如:if(window){ var x= 213; } alert(x);//213
9. arguments.callee屬性:在函數(shù)調(diào)用的時(shí)候,JavaScript為我們提供了一種方式,可以顯示指定任何一個(gè)對象作為其函數(shù)的上下文。JavaScript的每個(gè)函數(shù)都有apply()和call()方法。
通過函數(shù)的apply()方法來調(diào)用函數(shù),我們要給apply()傳入兩個(gè)參數(shù):一個(gè)是作為函數(shù)上下文的對象,另外一個(gè)是作為函數(shù)參數(shù)所組成的數(shù)組。call()方法的使用方式類似,唯一不同的是,給函數(shù)傳入的參數(shù)是一個(gè)參數(shù)列表,而不是單個(gè)數(shù)組。
代碼示例:
10. 自記憶函數(shù):代碼示例:
var ninja = { chirp: function(n) { return n > 1 ? arguments.callee(n - 1) + "-chirp" : "chirp"; } }callee屬性引用的是當(dāng)前所執(zhí)行的函數(shù)。該屬性可以作為一個(gè)可靠的方法引用函數(shù)自身。
記憶之前計(jì)算出的值: function isPrime(value) { if (!isPrime.answers) { isPrime.answers = {}; } if (isPrime.answers[value] != null) { return isPrime.answers[value]; } var prime = value != 1; for (var i = 2; i < value; i++) { if (value % i == 0) { prime = false; break; } } return isPrime.answers[value] = prime; }
緩存記憶DOM元素 function getElements(name) { if (!getElements.cache) { getElements.cache = {}; } return getElements.cache[name] = getElements.cache[name] || document.getElementsByTagName(name); }11. 模擬類似數(shù)組的方法
var elems = { length: 0, add: function (elem) { Array.prototype.push.call(this, elem); }, gather: function (id) { this.add(document.getElementById(id)); } };12. 使用apply()支持可變參數(shù)
在這里指定Math為上下文是沒有必要的 function smallest(array) { return Math.min.apply(Math, array); } function largest(array) { return Math.max.apply(Math, array); }
重載函數(shù)的方法:
function addMethod(object, name, fn) { var old = object[name];//保存原有的函數(shù),因?yàn)檎{(diào)用的時(shí)候可能不匹配傳入的參數(shù)個(gè)數(shù) object[name] = function () { if (fn.length == arguments.length) { //如果該匿名函數(shù)的形參個(gè)數(shù)和實(shí)數(shù)個(gè)數(shù)匹配,就調(diào)用該函數(shù) return fn.apply(this, arguments); } else if (typeof old == "function") { //如果傳入的參數(shù)個(gè)數(shù)不匹配,則調(diào)用原有的參數(shù) return old.apply(this, arguments); } } }
addMethod方法共接受三個(gè)參數(shù):
要綁定方法的對象
綁定方法所用的屬性名稱
要綁定的方法
13. 什么是閉包:閉包是一個(gè)函數(shù)在創(chuàng)建時(shí)允許該自身函數(shù)訪問并操作該自身函數(shù)之外的變量時(shí)所創(chuàng)建的作用域。換句話說,閉包可以讓函數(shù)訪問所有的變量和函數(shù),只要這些變量和函數(shù)聲明時(shí)的作用域內(nèi)就行。14. 在封閉的作用域內(nèi),強(qiáng)制使用一個(gè)名稱:
(function ($) { $("img").on("click", function (e) { $(e.target).addClass("clickOn"); }) })(jQuery);//jQuery作為參數(shù)綁定到$上15. 利用即時(shí)函數(shù)妥善處理迭代問題:
for (var i = 0; i < length; i++) { (function (n) { alert(n); })(i); }16. 使用hasOwnProperty()方法辨別Object原型擴(kuò)展:
Object.prototype.keys = function () { var keys = []; for (var i in this) { //使用hasOwnProperty()忽略原型對象上的屬性 if (this.hasOwnProperty(i)) { keys.push(i); } } return keys; }; var obj = {a: 1}; console.log(obj.keys());17. 在Number原型上添加一個(gè)方法
Number.prototype.add = function (num) { return this + num; }; var n = 5; console.log(n.add(3));18. 子類化Array對象:
function MyArray() {} MyArray.prototype = new Array(); var mine = new MyArray(); mine.push(1, 2, 3); console.log(mine.length == 3);//true19. 模擬Array功能,而不是擴(kuò)展出子類:
function MyArray() {} MyArray.prototype.length = 0; (function () { var methods = ["push", "pop", "shift", "unshift", "slice", "splice", "join"]; for (var i = 0; i < methods.length; i++) { (function (name) { MyArray.prototype[name] = function () { return Array.prototype[name].apply(this, arguments); } })(methods[i]) } })(); var mine = new MyArray(); mine.push(1, 2, 3); console.log(mine);//[1, 2, 3]20. 判斷函數(shù)是否是作為構(gòu)造器進(jìn)行調(diào)用的
function Test(){ return this instanceof arguments.callee; }
通過arguments.callee可以得到當(dāng)前執(zhí)行函數(shù)的引用;
“普通”函數(shù)的上下文是全局作用域(除非有人做了強(qiáng)制修改);
利用instanceof操作符測試已構(gòu)建對象是否構(gòu)建于指定的構(gòu)造器;
基于這些事實(shí),函數(shù)在作為構(gòu)造器進(jìn)行執(zhí)行的時(shí)候,表達(dá)式:this instanceof arguments.callee;的結(jié)果是true,如果作為普通函數(shù)執(zhí)行,則返回false。
21. 用eval()方法進(jìn)行求值:基本功能:
該方法將執(zhí)行傳入代碼的字符串;
在調(diào)用eval()方法的作用域內(nèi)進(jìn)行代碼求值;
console.log(eval("5+5") == 10);//true
求值結(jié)果:
eval()方法將返回傳入字符串中最后一個(gè)表達(dá)式的執(zhí)行結(jié)果。
console.log(eval("3+4;5+6"));//11
在使用eval()方法求值的時(shí)候,求值執(zhí)行的作用域就是調(diào)用eval()時(shí)的作用域,而不是全局作用域。
22. 用函數(shù)構(gòu)造器進(jìn)行求值:JavaScript中的所有函數(shù)都是Function的實(shí)例,可以直接使用Function構(gòu)造器來實(shí)例化函數(shù)。
var add = new Function("a", "b", "return a + b;"); console.log(add(3, 4));//7
Function構(gòu)造器可變參數(shù)列表的最后一個(gè)參數(shù),始終是要?jiǎng)?chuàng)建函數(shù)的函數(shù)體內(nèi)容。前面的參數(shù)則表示函數(shù)的形參名稱。
所以,上面的示例代碼等價(jià)于如下代碼:
var add = function(a, b) { return a + b;}
雖然這些代碼在功能上是等同的,但采用Function構(gòu)造器方式有一個(gè)明顯的區(qū)別,函數(shù)體由運(yùn)行時(shí)的字符串所提供。
另外一個(gè)極其重要的實(shí)現(xiàn)區(qū)別是,使用Function構(gòu)造器創(chuàng)建函數(shù)的時(shí)候,不會(huì)創(chuàng)建閉包。在不想承擔(dān)任何不相關(guān)閉包的開銷時(shí),這可能是一件好事。
23. 將JSON字符串轉(zhuǎn)化成JavaScript對象var json = "{"name":"Ninja"}"; var object = eval("(" + json + ")"); console.log(object);//Object {name: "Ninja"}
使用eval()做JSON解析時(shí)需要注意的是:通常,JSON數(shù)據(jù)來自于遠(yuǎn)程服務(wù)器,而且,盲目執(zhí)行遠(yuǎn)程服務(wù)器上的不可信代碼,基本是不可取的。
最受歡迎的JSON轉(zhuǎn)換器腳本是由JSON標(biāo)記的創(chuàng)造者Douglas Crockford所編寫。在該轉(zhuǎn)換器中,他做了一些初步的JSON字符串解析,以防止任何惡意信息通過。Github:JSON-js
24. with語句with語句是一個(gè)強(qiáng)大的、但經(jīng)常被誤解的、有爭議的Javascript特性。with語句允許我們將一個(gè)對象的所有屬性引用到當(dāng)前作用域,允許我們無需使用擁有者對象的前綴,就可以對這些屬性進(jìn)行引用和賦值操作。
var use = "other";//定義一個(gè)全局變量 var katana = {//創(chuàng)建一個(gè)對象 isSharp: true, use: function () { this.isSharp != this.isSharp; } }; with (katana) {//建立一個(gè)with作用域,在該作用域內(nèi),可以直接引用屬性名稱,而不必使用katana前綴,好像它們就是全局變量和全局方法一樣 console.log(use !== "other" && typeof use == "function");//作用域內(nèi)進(jìn)行測試,true console.log(this !== katana);//true } console.log(use === "other");//作用域外進(jìn)行測試,true console.log(typeof isSharp === "undefined");//true
注意:在with語句的作用域內(nèi),對象屬性的優(yōu)先級絕對高于在更高層作用域內(nèi)定義的同名變量。函數(shù)上下文(this)是不受with語句影響的。25. 判斷一個(gè)瀏覽器是否支持opacity:
var div = document.createElement("div"); div.setAttribute("style", "opacity:0.5"); var OPACITY_SUPPORTED = div.style.opacity === "0.5"; console.log(OPACITY_SUPPORTED);26. 獲取計(jì)算樣式的值:
function fetchComputedStyle(element, property) {//定義新函數(shù) if (window.getComputedStyle) { var computedStyles = window.getComputedStyle(element);//獲取接口 if (computedStyles) { property = property.replace(/[A-z]/g, "-$1").toLowerCase();//獲取樣式值 return computedStyles.getPropertyValue(property); } } else if (element.currentStyle) {//使用專有方式,IE瀏覽器 property = property.replace(/-([a-z])/ig, function (all, letter) { return letter.toUpperCase(); }); return element.currentStyle[property]; } } window.onload = function () { var div = document.getElementsByTagName("div")[0]; console.log(fetchComputedStyle(div, "display")); };27. 綁定和解綁事件處理程序:
在DOM2下,對于兼容于DOM的現(xiàn)代瀏覽器,我們綁定和解綁事件處理程序使用的是addEventListener()和removeEventListener()方法;而對IE老版本使用的則是attachEvent()和detachEvent()方法。注意:IE沒有提供事件捕獲階段的監(jiān)聽方式,只支持時(shí)間處理過程中的冒泡階段。此外,IE的實(shí)現(xiàn)給綁定處理程序設(shè)置了錯(cuò)誤的上下文,使得處理程序內(nèi)的this引用的是全局上下文,而不是事件目標(biāo)元素。另外,IE沒有將事件信息傳遞給處理程序,而是將事件信息定死在全局上下文了——window對象。
這意味著,在處理如下類型的事件時(shí),我們需要根據(jù)不同的瀏覽器來指定不同的方式。
綁定一個(gè)處理程序時(shí);
解綁一個(gè)處理程序時(shí);
獲取事件信息時(shí);
獲取事件目標(biāo)時(shí);
如何解決多API的問題,以及IE不能正確設(shè)置上下文問題:
代碼:綁定事件處理程序時(shí),設(shè)置正確的上下文
if (document.addEventListener) { this.addEvent = function (elem, type, fn) { elem.addEventListener(type, fn, false);//false表示使用冒泡處理 return fn; }; this.removeEvent = function (elem, type, fn) {//DOM解綁函數(shù) elem.removeEventListener(type, fn, false); } } else if (document.attachEvent) {//檢測是否支持IE this.addEvent = function (elem, type, fn) { var bound = function () { return fn.apply(elem, arguments);//改變上下文 }; elem.attachEvent("on" + type, bound); return bound; }; this.removeEvent = function (elem, type, fn) { elem.detachEvent("on" + type, fn); } }28. 將事件委托給祖先元素:
假設(shè)一個(gè)表格在初始化加載的時(shí)候,所有的單元格都是白色背景,我們很想直觀地表明,表格中的哪個(gè)單元格在與用戶交互的時(shí)候被單機(jī)了。
丑陋的代碼: var cells = document.getElementsByTagName("td"); for (var n = 0; n < cells.length; n++) { addEvent(cells[n], "click", function () { this.style.backgroundColor = "yellow"; }); } 優(yōu)雅的寫法: var table = document.getElementById("#someTable"); addEvent(table, "click", function (event) { if (event.target.tagName.toLowerCase() == "td") { event.target.style.backgroundColor = "yellow";//一個(gè)元素被單擊的時(shí)候可以通過event.target獲取該元素的引用 } });
存在一個(gè)問題:在老版本IE瀏覽器中,submit和change事件根本沒有冒泡,那么如何進(jìn)行事件委托?
29. 事件冒泡檢測代碼:console.log(isEventSupported("click"));//true function isEventSupported(eventName) { //創(chuàng)建一個(gè)div用于測試,通常各個(gè)事件都可以冒泡到div上來,包括change和submit var element = document.createElement("div"), isSupported; eventName = "on" + eventName; isSupported = (eventName in element);//檢測元素是否有一個(gè)屬性表示該事件 //如果檢測到?jīng)]有這個(gè)屬性,那就創(chuàng)建一個(gè)ontype并插入一點(diǎn)代碼,然后判斷該元素是否可以將其轉(zhuǎn)換為一個(gè)函數(shù) //如果轉(zhuǎn)換為一個(gè)函數(shù),說明該元素知道如何解釋冒泡事件 if (!isSupported) { element.setAttribute(eventName, "return;"); isSupported = typeof element[eventName] == "function"; } element = null;//刪除臨時(shí)元素 return isSupported; }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/79985.html
摘要:無處不在的理解語言與其他主流語言相比,函數(shù)式語言的血統(tǒng)更多一些。函數(shù)式語言一類程序設(shè)計(jì)語言,是一種非馮諾伊曼式的程序設(shè)計(jì)語言。函數(shù)式語言主要成分是原始函數(shù),定義函數(shù)和函數(shù)型。性能分析內(nèi)置對象上的和方法。 無處不在的JavaScript 理解JavaScript語言 與其他主流語言相比,JavaScript函數(shù)式語言的血統(tǒng)更多一些。 函數(shù)式語言一類程序設(shè)計(jì)語言,是一種非馮.諾伊曼式的程序...
摘要:閉包閉包的特點(diǎn)就是內(nèi)部匿名函數(shù)可以訪問外部函數(shù)作用域的變量和方法變量對象。閉包的主要表現(xiàn)形式就是匿名函數(shù),但是兩者并不是等價(jià)的。中是沒有塊級作用域的,為了在中引入塊級作用域,可以使用匿名函數(shù)模擬塊級作用域。 在介紹閉包之前,首先解釋在隨后的測試實(shí)例中會(huì)使用的assert測試函數(shù),這個(gè)方法有別于alert()測試,有很大的改進(jìn)。 assert()測試方法 #...
摘要:閉包閉包的特點(diǎn)就是內(nèi)部匿名函數(shù)可以訪問外部函數(shù)作用域的變量和方法變量對象。閉包的主要表現(xiàn)形式就是匿名函數(shù),但是兩者并不是等價(jià)的。中是沒有塊級作用域的,為了在中引入塊級作用域,可以使用匿名函數(shù)模擬塊級作用域。 在介紹閉包之前,首先解釋在隨后的測試實(shí)例中會(huì)使用的assert測試函數(shù),這個(gè)方法有別于alert()測試,有很大的改進(jìn)。 assert()測試方法 #...
摘要:第二例這段代碼是用來做將斷言測試分組的,代碼多了些,問題自然也更多了些。首先作者使用了自執(zhí)行方法封閉了作用域,使用來指向全局對象,進(jìn)而產(chǎn)生全局可訪問的屬性。沒想到,久負(fù)盛名,豆瓣評分的大作,作者的光環(huán),代碼風(fēng)格居然是如此的不謹(jǐn)慎。 第二章中 作者給了幾個(gè)簡單的斷言例子,思路與方向是極不錯(cuò)的,創(chuàng)造JQ的大神,思想高度絕對無法讓我質(zhì)疑的,但是代碼的功底細(xì)節(jié),實(shí)在是讓人不敢恭維。 第一例: ...
摘要:設(shè)置和清除定時(shí)器直接引用忍者秘籍中的圖片注意定時(shí)器的時(shí)間間隔設(shè)為,也會(huì)有幾毫秒的延遲。以上參考資料忍者秘籍第章馴服線程和定時(shí)器 showImg(https://segmentfault.com/img/remote/1460000015353524?w=1024&h=681); 前言 前段時(shí)間剛看完《JS忍者秘籍》,雖說是15年出版的,有些東西是過時(shí)了,但像對原型鏈、閉包、正則、定時(shí)器...
摘要:我們需要知道的是,對于而言,匿名函數(shù)是一個(gè)很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個(gè)供以后使用的函數(shù)。截圖自忍者秘籍通過完善之前對匿名函數(shù)的粗略定義,我們可以修復(fù)解決這個(gè)問題。 從名字即可看書,此篇博客總結(jié)與《JavaScript忍者秘籍》。對于JavaScript來說,函數(shù)為第一類型對象。所以這里,我們主要是介紹JavaScript中函數(shù)的運(yùn)用。 系列博客地址:h...
閱讀 2657·2023-04-26 00:42
閱讀 2809·2021-09-24 10:34
閱讀 3821·2021-09-24 09:48
閱讀 4157·2021-09-03 10:28
閱讀 2580·2019-08-30 15:56
閱讀 2775·2019-08-30 15:55
閱讀 3267·2019-08-29 12:46
閱讀 2249·2019-08-28 17:52