javascript
JS高级程序设计精简版(第十章:函数)附思维导图
????????時隔兩年后二刷JavaScript高級程序語言,純手打讀書筆記+思維導圖,讓自己有一個比較全面的知識體系,后面有遇到例子的時候會慢慢補充更多的用法。有不足之處歡迎大家評論區指出,共勉!!
第十章 函數
函數也是對象,函數是Function類型的實例,函數名就是指向函數對象的指針。
定義函數的四種方式:函數聲明、函數表達式、new Function();、箭頭函數
一、參數
1、實參
函數定義的形參個數可以和實參個數不同,因為函數被調用時接收一個數組保存實參。
因為js函數使用參數數組,所以函數無法重載(無簽名:參數類型或數量不同)。
2、默認參數
function makeKing(name = 'Henry') { }//ES6新增
arguments對象的值不會是命名參數的默認值。
默認參數也可以是調用一個函數求的值,只是在函數調用時才會求這個值。
箭頭函數也支持默認值,此時不能省略括號()。
3、默認參數的作用域和暫時性死區
給多個參數定義默認值跟使用 let 關鍵字順序聲明變量一樣,所以前面的參數無法引用后面定義的參數(暫時性死區),也不能引用函數體內定義的let/const變量。
4、參數擴展與收集
參數擴展:countArguments(-1, ...values);
參數收集:function ignoreFirst(firstValue, ...values) { }//...values后面不能再聲明參數。
二、定義函數
1、箭頭函數
let triple = x?=> 3 * x; //省略函數體的{}就會返回這一行代碼的值
箭頭函數局限:不能使用arguments、super、new.target,不能用作構造函數,沒有prototype屬性。
2、函數聲明
function a(){},通過這種方法會讓函數聲明提升,且生成函數定義,所以可以在聲明前調用函數,比變量更先提升。
var a = function(){},函數表達式不會被提升,無法在函數定義前調用。
- 函數內部
1、arguments對象
arguments:在函數內部訪問arguments對象來取得傳入的每個參數。arguments是類數組對象,通過arguments[0]來獲取第一個參數,其值始終會與命名參數一致(內存分開)。
嚴格模式:①arguments賦值不會改變命名參數的值②無法重寫arguments對象。
箭頭函數無法使用arguments,但是可以在箭頭函數外面包裝一層function再使用參數。
arguments.callee指向函數本身,可以在函數內部調用此函數本身,與函數名解耦。
2、this
標準函數:this是調用此函數的上下文對象。
箭頭函數:this是定義箭頭函數的上下文。
回調函數中的標準函數,this默認指向window,因為在函數調用前沒有.調用,可以通過箭頭函數解決。
函數對象上有一個屬性caller,指向調用此函數的函數,全局作用域中調用則為null。
嚴格模式:訪問arguments.callee和arguments.caller都會報錯。不能給caller賦值。
new.target:函數是否使用 new 關鍵字調用的,是new a()則new.target指向a構造函數。
- 函數的屬性和方法
length:保存函數定義中,命名參數的個數。
prototpye:原型對象。
apply(指定函數作用域的對象,[參數數組])
call(指定函數作用域的對象,...[參數數組])
這兩種方法都可以定義函數的this指向,可以將任意對象設置為函數的作用域。
bind(obj)創建一個新的函數實例,this會綁定給obj。
toLocaleString()、toString()返回函數字符串代碼,valueOf()返回函數本身。
五、遞歸
1、遞歸
遞歸:在函數內部調用函數本身。
第一種:通過函數名調用,當函數名修改時則會出錯。
第二種:使用arguments.callee調用函數本身,但嚴格模式無法訪問arguments.callee
第三種:使用命名函數表達式?var fun = (function f(n) { f(n-1)})
2、尾調用優化
尾調用:外層函數的返回值是內層函數的返回值。
ES5:每多調用一次嵌套函數,就會多增加一個棧幀。
ES6:符合尾調用優化條件的,會在return時將第一個棧幀彈出棧外,所以無論調用多少次嵌套函數,都只有一個棧幀,這種優化在遞歸中尤其明顯。
優化條件:
①必須在嚴格模式下(因為嚴禁使用arguments.callee造成對外函數的引用)
②外函數的返回值是調用尾調用函數,返回后不用再執行額外的邏輯,且不是閉包。
六、閉包
1、閉包
活動對象:函數執行時,每個執行上下文都有一個包含其中變量的對象,叫變量對象(全局上下文)或者活動對象(函數上下文)。
定義函數時,會為他創建作用域鏈,預裝載全局變量對象,保存在內部[[Scope]]中。
調用函數時,創建其執行上下文,復制[[scope]]來創建作用域鏈,然后創建活動對象并將其推入作用域鏈前端。
閉包:引用了另一個函數作用域中變量的函數。外層函數的活動對象在函數執行完不能被銷毀,因為內層函數的作用域鏈仍有對他的引用。
閉包中的this,指向的是調用此函數(返回的這個函數)的執行上下文,所以將this保存到閉包中則可以實現在內部函數直接訪問外部變量。也可以通過賦值this固定作用域。
let object = {
identity: 'My Object',
getIdentityFunc() {
let that = this; //賦值this固定作用域
return function() {
return that.identity; //不論函數在何處執行,that都始終指向object
};
}
2、內存泄露
因為IE9之前的垃圾回收機制是引用計數,所以閉包會導致內存泄露。后面的版本盡量回收閉包中不用的數據,但也應謹慎使用閉包。
3、立即執行函數
立即執行函數(function(){//作用域 })()可以模擬塊級作用域(ES5)。
4、私有變量
任何定義在函數或塊中的變量,都是私有的。
特權方法:能夠訪問私有變量的公共方法,可以通過兩種方式實現。
第一種:通過構造函數定義
私有變量不用this,而在this.方法中訪問這些變量(閉包)。構造函數定義特權方法的缺點是會為每個實例創建此方法。
第二種:通過使用私有作用域定義,具體有以下三種模式
1)靜態私有變量
通過使用私有作用域定義私有變量和函數。
(function() {
// 靜態私有變量,實例共享
let privateVariable = 10;
// 構造函數 MyObject是全局變量 可以在外部使用 注意嚴格模式報錯
MyObject = function() {};
// 公有和特權方法 定義在原型上
MyObject.prototype.publicMethod = function() {
return privateVariable;
};
})();
2)模塊模式
let singleton = function() {
let privateVariable = 10; // 私有變量
return { // 特權/公有方法和屬性
publicMethod() { }
};
}();
模塊模式 是在單例對象基礎上拓展的,在立即執行函數中定義私有變量和方法,然后return一個對象,此對象里的屬性和方法是公有的特權方法。
3)模塊增強模式
在模塊模式中,返回對象之前,先將對象增強,比如通過構造函數創建此對象。
?
?
總結
以上是生活随笔為你收集整理的JS高级程序设计精简版(第十章:函数)附思维导图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android桌面小工具,超好用的手机桌
- 下一篇: Python解运筹学问题