斷言
單元測試框架的核心是斷言方法,通常叫assert()。
該方法通常接收一個值--需要斷言的值,以及一個表示該斷言目的的描述。
如果該值執行的結果為true,斷言就會通過;
否則,斷言就會被認為是失敗的。
通常用一個相應的通過(pass)/ 失敗(fail)標記記錄相關的信息;
function assert(value, desc) { let li = document.createElement('li'); li.className = value ? 'pass' : 'fail'; li.appendChild(document.createTextNode(desc)); document.getElementById('results').appendChild(li);}// 斷言函數function assert(value, desc) { if (value) { console.log(`/033[32m ${desc} /033[0m`); // 斷言通過 綠色字體 } else { console.log(`/033[31m ${desc} /033[0m`); // 斷言失敗 紅色字體 }}函數
if (window) { var x = 123;}alert(x);執行代碼后,會彈出123,是因為JavaScript在大括號關閉處并沒有終止其作用域。
作為函數進行調用
如果一個數不是作為方法、構造器、或者通過apply()或call()進行調用的,則認為它是“作為函數”進行調用的。
function ninja() {};ninja()var samurai = function() {};samurai()作為方法進行調用
當一個函數被賦值給對象的一個屬性,并使用引用該函數的這個屬性進行調用時,那么函數就是作為該對象的一個方法進行調用的。
var 0 = {};o.whatever = function() {};o.whatever();作為構造器進行調用
創建一個新的空對象;
傳遞給構造器都對象是this參數,從而成為構造器的函數上下文;
如果沒有顯式都返回值,新創建的對象則作為構造器的返回值進行返回。
function Ninja() { this.skulk = function() { return this; }}var ninja1 = new Ninja();var ninja2 = new Ninja();構造器的目的是通過函數調用初始化創建新的對象。
函數調用方式差異
作為方法調用,該上下文是方法的擁有者;
作為全局函數進行調用,其上下文永遠是window(也就說,該函數是window的一個方法)。
作為構造器進行調用,其上下文對象則是新創建的對象實例。
使用apply()和call()方法
function juggle() { var result = 0; for (var n = 0; n < arguments.length; n++) { result += arguments[n] } this.result = result;}var ninja1 = {};var ninja2 = {};juggle.apply(ninja1, [1,2,3,4]);juggle.call(ninja2, 5,6,7,8)assert(ninja1.result === 10, 'juggled via apply');assert(ninja2.result === 26, 'juggled via call');使用apply()和call()可以選擇任意對象作為函數上下文;
函數總結
函數是第一型對象;
函數是通過字面量進行創建的,其名稱是可選的。
在頁面生命周期內,瀏覽器可以將函數作為各種類型的事件處理程序進行調用。
變量的作用域開始于聲明處,結束于函數尾部,其會跨域邊界(如:大括號)
內部函數在當前函數的任何地方都可用(提升),即便是提前引用。
函數的形參列表和實際參數列表的長度可以是不同的。
每個函數調用都會傳入兩個隱式參數。
可以用不同的方法進行函數調用,不同的調用機制決定了函數上下文的不同。
匿名函數
為了不讓不必要的函數名稱污染全局命名空間,可以創建大量的小型函數進行傳遞,而不是創建包含大量命令語句的大型函數。
遞歸
閉包
var outerValue = 'ninja';var later;function outerFunction() { // 該變量的作用域限制在該函數內部,并且在函數外部訪問不到; var innerValue = 'samurai'; // 在外部函數內,聲明一個內部函數。 // 注意:聲明該函數時,innerValue是在作用域內的 function innerFunction() { assert(outerValue, 'I can see the ninja'); assert(innerValue, 'I can see the samurai'); // 將內部函數引用到later變量上,由于later在全局作用域內,所以可以對它進行調用。 later = innerFunction; }}// 調用外部函數,將會聲明內部函數,并將內部函數賦值給later變量。outerFunction();// 通過later調用內部函數。// 我們不能直接調用內部函數,因為它的作用域(和innerValue一起)被限制在outerFunction內。later();閉包使用場景:私有變量
在構造器內隱藏變量,使其在外部作用域不可訪問,但是可以存在于閉包內。
function Ninja() { var feints = 0; this.getFenits = function() { return feints; } this.feint = function() { feints++; }}var ninja = new Ninja();ninja.feint();assert(ninja.getFenits() === 1, '調用一次,內部變量++');assert(ninja.feints === undefined, '函數外部不可訪問')變量的作用域依賴于變量所在的閉包
閉包記住的是變量的引用,而不是閉包創建時刻該變量的值
原型與面向對象
新聞熱點
疑難解答