函數表達式
- 定義函數的方式有兩種:
- 函數聲明
sayHi(); function sayHi() { alert('hi'); }
- 函數表達式
var functionName = function(a,b,c){}
- 注意
- 匿名函數
- 使用前必須先指派
//錯誤代碼
sayHi();
var sayHi = function() {
alert('hi');
}
//另一個例子
var sayHi; //如果不指派在js中屬于無效文法
if(condition) {
sayHi = function() { alert('hi');}
}else {
sayHi = function() { alert('aha');}
}
遞歸
- 問題1
var diguiA = digui; digui = null; alert(diguiA(4));
-
arguments.callee
是一個指向正在執行的函數的指針,以此來替代函數名,調用函數。
-
問題2
嚴格模式下,通路這個屬性會産生錯誤
- 解決(命名函數表達式)
var digui = (function d(num) { if (num <= 1) { return 1; } else { return num * f(num-1); } })
閉包
有權通路另一個函數作用域中的變量的函數。
建立閉包的常用方式,就是在一個函數内部建立另一個函數。
function out(outX) {
return function (object1,object2) {
var a = object[outX]
var b = object[outX]
//函數代碼
}
}
- 作用域鍊
- 本質上是一個指向變量對象的指針清單,它隻引用但不實際包含變量對象。
- 在建立A()函數的時候,會建立一個預先包含全局變量的作用域鍊,這個作用域鍊被包含在内部的[[Scope]]屬性中。當調用A()函數時,會為函數建立一個執行環境,然後通過啊複制函數的[[Scope]]屬性中的對象建構起執行環境中的作用域鍊。
- 函數執行完後,局部活動對象就會被銷毀,記憶體中僅儲存全局作用域(全局執行環境的變量對象)。
- !!!閉包與此不同!!!另一個函數内部定義的函數回京包含函數(即外部函數)的活動對象添加到他的作用域鍊中。換而言之,匿名函數可以通路在out()中定義的所有變量。
-
副作用
閉包隻能取得包含函數中任何變量的最後一個值
//解決function A() { var result = new Array(); for(var i = 0;i < 10;i++) { result[i] = function(){ return i; }; } }
function A() { var result = new Array(); for(var i = 0;i < 10;i++) { result[i] = function(num){ return function() { return num; } }; } }
-
this對象
匿名函數的執行環境具有全局性,是以其this對象通常指向window。
-
記憶體洩漏
閉包的作用鍊中包含html元素
模仿塊級作用域
- JS沒有塊級作用域的概念。JS不會告訴你是否多次聲明了同一個變量,他會對後續的聲明視而不見但會執行初始化。
- 這種技術經常在全局作用域中被用在函數外部,進而限制向全局作用域中的所有變量。
function A(count) { for(var i = 0;i < count;i++) { alert(i); } alert(i); }
- 實作
(function() { //這裡是塊級作用域 })(); var A = function () { //這裡是塊級作用域 } A();
私有變量
- JS中沒有私有成員的概念,所有對象屬性都是共有的。
- 私有變量:定義在函數中的變量。
- 特權方法:有權通路私有變量和私有函數的公有方法。
-
靜态私有變量
在一個私有作用域下,定義私有變量或函數。
- 子產品模式
- 為隻有一個執行個體的對象建立私有變量和特權方法
- 如果必須建立一個對象并以某些資料對其進行分初始化,同時還要公開一些能夠通路這些私有資料的方法,那就可以使用子產品模式。
var A = { name : value, method : function () { //這裡是方法的代碼 } }
-
增強的子產品模式
在傳回對象之前加入對其增強的代碼。比如,能夠通路私有變量的公有方法。