函數 html
實現特定功能的 n 條語句封裝體。c++
1. 建立一個函數對象面試
var myFunc = new Function(); // typeof myFunc 將會打印 function
var aFunc = new Function("console.log('Hello!');"); console.log(aFunc); // 打印: " function anonymous(){ console.log("Hello!"); } "
function myFunc(){ console.log("Hello myFunc !"); }
// 會 函數聲明 提高
var myFunc = function(){ console.log("Hello myFunc ! "); };
// 會 變量聲明 提高
var myAdd = function(a,b){ // 傳遞多個參數使用,隔開 console.log(a+b); };
注意:函數解析器不會檢查實參的類型; 多餘的參數將不會被使用; 缺乏的參數定義爲 undefined數組
2. 函數的返回值 外界須要函數處理的值安全
使用 return 關鍵字返回指定結果,並結束函數。閉包
不寫 return 默認爲 return ; 此時的函數返回值爲 undefinedapp
3. 函數的參數 當沒法肯定 n 個變量的值時, 使用 n 個參數 傳遞____形參異步
length
屬性返回函數預期傳入的參數個數,即函數定義之中的參數個數
length
屬性就是定義時的參數個數。無論調用時輸入了多少個參數,length
屬性始終等於 形參個數
function f(a, b){} f.length // 2
function f(a, a) { console.log(a); } f(1, 2) // 2 f(1) // undefined // 這時,若是要得到第一個a的值,可使用arguments對象。 function f(a, a) { console.log(arguments[0]); } f(1) // 1
只有函數調用時,才能動態肯定 this 的指向函數
.call(obj, 12, 13);工具
.apply(obj, [12, 13]);
.bind(obj, 12, 13); 重構建函數
不會當即執行函數,而是會建立一個新函數,新函數的 this 指向 obj,參數也被傳遞
也不會修改原函數的 this
arguments 實參列表
對象 只有數組的 length 屬性,可以經過 index 讀寫數據
arguments[0]
就是第一個參數,arguments[1]
就是第二個參數,以此類推。這個對象只有在函數體內部,纔可使用。
var f = function (one) { console.log(arguments[0]); console.log(arguments[1]); console.log(arguments[2]); } f(1, 2, 3) // 1 // 2 // 3
arguments
對象能夠在運行時修改。
var f = function(a, b) { arguments[0] = 3; arguments[1] = 2; return a + b; } f(1, 1) // 5
arguments
對象是一個只讀對象,修改它是無效的,但不會報錯。
var f = function(a, b) { 'use strict'; // 開啓嚴格模式 arguments[0] = 3; // 無效 arguments[1] = 2; // 無效 return a + b; } f(1, 1) // 2
arguments
對象的 length
屬性,能夠判斷函數調用時到底帶幾個參數。arguments
很像數組,但它是一個對象。數組專有的方法(好比 slice
和 forEach
),不能在 arguments
對象上直接使用。
arguments
對象使用數組方法,真正的解決方法是將arguments
轉爲真正的數組。下面是兩種經常使用的轉換方法:
//slice方法 var args = Array.prototype.slice.call(arguments);
//逐一填入新數組。 var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); }
arguments
.callee
屬性,返回它所對應的原函數
var f = function () { console.log(arguments.callee === f); } f() // true // 能夠經過arguments.callee,達到調用函數自身的目的。 // 這個屬性在嚴格模式裏面是禁用的,所以不建議使用。
undefined
undefined
function f(a, b) { return a; } f( , 1) // 報錯 SyntaxError: Unexpected token ,(…) f(undefined, 1) // undefined
var sun = { name:"孫悟空", gender:"男", age:600 }; function sayHello(obj){ document.write("你們好,我是"+obj.name+", "+obj.gender+", "+obj.age+"歲了"); } sayHello(sun);
function haha(someFunc){ someFunc(); } haha(sayHello);
4. 函數的屬性和方法
.name 屬性,返回函數的名字
function f1() {} f1.name // "f1" var f2 = function () {}; f2.name // "f2" var f3 = function myName() {}; f3.name // 'myName'
.toString()
方法返回一個字符串,內容是函數的源碼
function f() { a(); b(); c(); // 這是註釋 } f.toString() // function f() { // a(); // b(); // c(); // 這是註釋 // }
5. 做用域(scope)
變量存在的範圍。
不一樣做用域的同名變量不會衝突
function Foo() { getName = function () { alert (1); }; return this; } Foo.getName = function () { alert (2);}; Foo.prototype.getName = function () { alert (3);}; var getName = function () { alert (4);}; function getName() { alert (5);} //請寫出如下輸出結果: Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();
var getName; window.getName = function () { alert (4);}; function Foo() { // window.Foo getName = function () { alert (1); }; // 覆蓋 window.getName return this; }; window.Foo.prototype.getName = function () { alert (3);}; window.Foo.getName = function () { alert (2);}; //請寫出如下輸出結果: Foo.getName(); // window.Foo.getName() 2 getName(); // window.getName() 4 // this.getName() window.getName() 1 注意是在何時被覆蓋的 Foo().getName();
getName(); // window.getName() 1 new Foo.getName(); // window.Foo.getName() 2 // 注意 new 返回的是對象 直接調用返回看return // f.getName() window.f.getName() window.Foo.prototype.getName 3 new Foo().getName();
new new Foo().getName(); // new window.f.getName() 3
6. 閉包 closure
① 嵌套: 做爲函數裏面的 函數 fn2
② fn2 引用了外部函數的局部變量
③ 外部函數 被調用執行時產生閉包,在 new 的時候也至關於執行了____實質是在 第一個知足以上條件 的函數被解析到是,產生閉包
此時就產生了一個閉包____ fn2.Scopes[0] = fn2.closure————包含了被引用局部變量的一個"對象",存在於嵌套的內部函數中,可使用調試工具查看到。
其中 [[Scopes]] 是由底層 c/c++ 實現
缺點:
因爲閉包的存在,未釋放,致使佔用內存時間變長。易形成內存泄漏
怕的就是出現 很是多個閉包
解決:
能不用閉包就不用閉包
及時釋放____讓 指向含閉包函數的 變量,指向 null
function Person(name) { var _age; function setAge(n) { _age = n; } function getAge() { return _age; } return { name: name, getAge: getAge, setAge: setAge }; } var p1 = new Person('張三'); p1.setAge(25); // 操做的是 閉包中的 _age p1.getAge() // 訪問的是 閉包中的 _age
// 上面代碼中,函數的內部變量,經過閉包和,變成了返回對象的私有變量。Person_agegetAgesetAgep1
注意
外層函數每次運行,都會生成一個新的閉包,而這個閉包又會保留外層函數的內部變量,因此內存消耗很大。
所以不能濫用閉包,不然會形成網頁的性能問題。
fn2
記住了它誕生的環境 fn1
的內部變量。在本質上,閉包就是將函數內部和函數外部鏈接起來的一座橋樑。
function f1() { var n = 999; function f2() { console.log(n); } return f2; } var result = f1(); result(); // 999
// 函數的返回值就是函數,因爲能夠讀取的內部變量,因此就能夠在外部得到的內部變量了f1f2f2f1f1
f2
,即可以讀取其餘函數內部變量的函數。
function createIncrementor(start) { return function () { return start++; }; } var inc = createIncrementor(5); // 執行了 外層函數,而後銷燬了 函數上下文,即 全部外層函數的變量都銷燬了 inc(); // 5 inc(); // 6 inc(); // 7
7. 當即調用的函數表達式(IIFE)
自調用匿名函數
____封裝時, 隱藏函數內部具體實現, 防止外部修改函數內的代碼
____防止污染外部命名空間
這就叫作「當即調用的函數表達式」(Immediately-Invoked Function Expression),簡稱 IIFE。
// 寫法一 var tmp = newData; processData(tmp); storeData(tmp); // 寫法二 更好,由於徹底避免了污染全局變量。 (function(w){ // var tmp = newData; processData(tmp); storeData(tmp); }(window)); // 方便對代碼進行壓縮, 變量 window 改爲 w, 減少代碼體積
()
是一種運算符,跟在函數名以後,表示調用該函數。 好比,isNaN()
就表示調用 isNaN
函數。function
出如今行首,爲了避免讓引擎將其理解成一個表達式。最簡單的處理,就是將其放在一個圓括號裏面。
8. 回調函數
自定義的,不被本身調用的,達到某種條件後被某對象調用了。
異步加載通知機制:
全部異步代碼,不能當即執行
只有等主進程執行完全部代碼後,纔會執行 異步代碼
setTimeout(function(){ console.log("異步代碼"); }, 0); console.log("主進程代碼");
// 打印:
// 主進程代碼
// 異步代碼
9. eval
命令
接受一個字符串做爲參數,並將這個字符串看成語句執行。
eval('var a = 1;'); a // 1
// Uncaught SyntaxError: Invalid or unexpected token
eval
的參數不是字符串,那麼會原樣返回。eval
沒有本身的做用域,都在當前做用域內執行,所以可能會修改當前做用域的變量的值,形成安全問題。eval
內部聲明的變量,不會影響到外部做用域。
eval
依然能夠讀寫當前做用域的變量。
(function f() { 'use strict'; var foo = 1; eval('foo = 2'); console.log(foo); // 2 })()
因此通常不推薦使用。一般狀況下,eval
最多見的場合是解析 JSON 數據的字符串,不過正確的作法應該是使用原生的JSON.parse
方法。
eval
的別名調用的形式五花八門,只要不是直接調用,都屬於別名調用,由於引擎只能分辨eval()
這一種形式是直接調用。
eval.call(null, '...'); window.eval('...'); (1, eval)('...'); (eval, eval)('...'); // 上面這些形式都是eval的別名調用,做用域都是全局做用域。
內存溢出
須要的內存,大於現有內存
內存泄漏
資源佔有一片空間,而不曾釋放,致使這片內存沒法被使用
及時 obj = null; 來釋放內存
在函數中, 未使用 var 關鍵字定義變量, 致使直接聲明瞭一個全局變量
10. 屬性描述符