本文是 重溫基礎 系列文章的第四篇。
今日感覺:常懷感恩之心,對人對己。前端
系列目錄:git
本章節複習的是JS中的基礎組件之一,函數,用來複用特定執行邏輯。github
定義函數有兩種方法:函數聲明 和 函數表達式 :segmentfault
也成爲函數聲明,一般格式爲:數組
function f (a){ return a + 1; }
解釋:這裏聲明一個函數 f
,並傳入一個參數 a
,當函數執行之後,經過 return
關鍵字返回了 a+1
的值。 安全
參數:
當傳入的參數是一個數字/字符串等具體的值的時候,若參數的值被改變,不會影響到全局或調用函數。
但若是參數是個對象,若函數內改變的這個參數的屬性,則函數外部的這個參數原始的值會被修改。微信
var leo = { age:20 } function f(obj){ obj.age = 15; obj.name = 'leo'; } f(leo); console.log(leo); //{age: 15, name: "leo"}
經過定義一個匿名的函數,來賦值給一個變量,經過這個變量來調用這個函數。閉包
var f = function (a){ return a + 1; }
可是函數表達式也能夠提供函數名,用於函數內部調用,並指代自己,也能夠做爲調試器堆棧跟蹤中識別該函數。ide
var f = function g(a){ return n < 2 ? 1 : a*g(a-1); }
另外,函數表達式聲明能夠用來根據不一樣條件,來定義一個函數:函數
var f; if(a == 1){ f = function (){ return 'when a == 1'; } }else { f = function (){ return 'when a != 1'; } }
函數定義完成後不會自動執行,須要咱們經過函數名稱來調用,才能真正執行:
var f = function (){ console.log('ok'); } f(); // 'ok'
另外,函數也能夠調用自身,這就是遞歸過程:
function f (n){ if( n==0 || n==1) { return 1; }else { return n * f(n-1); } } // 三目運算 function f (n){ return (n==0 || n==1)?1: n*f(n-1); }
因爲函數只在函數的內部有定義,因此函數內部定義的變量在函數外部不能訪問,函數內部就是這個函數的做用域。
當一個父級函數內,還定義了一個子級函數,則這個子級函數能夠訪問父級函數定義的變量。
// 全局做用域 global scope var a = 1, b = 2; function f (){ return a + b; } f(); // 3 function g(){ var a1 = 'leo', b1 = 'pingan'; function hi (){ return a1 + '和' + b1 } return hi(); } g(); // 'leo和pingan'
閉包是 JavaScript 中最強大的特性之一,而且JS容許函數嵌套。
在一個函數內部在嵌套一個函數,而嵌套的這個函數對外面的函數是私有的,則造成一個閉包,閉包是一個能夠本身擁有獨立的環境和變量的表達式,一般是函數。
理解一下,前面說的內部函數能夠調用外部函數的變量和方法,那麼能夠這麼理解:閉包的函數繼承了父級容器函數的參數和變量,即內部函數包含外部函數的做用域。
總結一下:
function f(a) { function g(b){ return a + b; } return g; } var a1 = f(5); // ƒ g(b){ return a + b; } var a2 = a1(6); // 11 var a3 = f(5)(6); // 11
閉包能夠給內部函數的變量提供必定的安全保障。
另外,閉包還有複雜的用法:
var f = function (name){ var age ; return { setName : function (newName){ name = newName; }, getName : function (){ return name; }, getAge : function (){ return age; }, setAge : function (newAge){ age = newAge; } } } var leo = f('leo'); leo.setName('pingan'); leo.setAge(20); leo.getName(); // 'pingan' leo.getAge(); // 20
在同一個閉包做用域下若參數或變量名相同,產生衝突,則優先使用做用域最近:
function f(){ var a = 1; function g(a){ return a + 1; } return g; } f()(3); // 4
函數的實際參數會被保存在一個類數組對象 arguments
對象中,經過索引訪問具體的參數:
var a = arguments[i]
arguments
的索引從0開始,也有arguments.length
屬性獲取長度。
當咱們不知道參數的數量的時候,能夠使用arguments.length
來獲取實際傳入參數的數量,再用arguments
對象來獲取每一個參數。
例如:
// 拼接全部參數爲一個字符串 // 參數 s 爲分隔符 function f( s ){ var text = ''; for(var i = 0;i<= arguments.length; i++){ text += arguments[i] + s ; } return text; } f('--','leo','pingan','robin'); // "----leo--pingan--robin--undefined--" f('**','leo','pingan','robin'); // "****leo**pingan**robin**undefined**"
ES6開始,新增兩個類型的參數:默認參數和剩餘參數:
若函數沒有傳入參數,則參數默認值爲undefined
,一般設置參數默認值是這樣作的:
// 沒有設置默認值 function f(a, b){ b = b ? b : 1; return a * b; } f(2,3); // 6 f(2); // 2 // 設置默認值 function f(a, b = 1){ return a * b; } f(2,3); // 6 f(2); // 2
能夠將參數中不肯定數量的參數表示成數組,以下:
function f (a, ...b){ console.log(a, b); } f(1,2,3,4); // a => 1 b => [2, 3, 4]
函數箭頭表達式是ES6新增的函數表達式的語法,也叫胖箭頭函數,變化:更簡潔的函數和this
。
// 有1個參數 let f = v => v; // 等同於 let f = function (v){return v}; // 有多個參數 let f = (v, i) => {return v + i}; // 等同於 let f = function (v, i){return v + i}; // 沒參數 let f = () => 1; // 等同於 let f = function (){return 1}; let arr = [1,2,3,4]; arr.map(ele => ele + 1); // [2, 3, 4, 5]
注意這幾點:
1. 箭頭函數內的`this`老是指向**定義時所在的對象**,而不是調用時。 2. 箭頭函數不能當作**構造函數**,即不能用`new`命令,不然報錯。 3. 箭頭函數不存在`arguments`對象,即不能使用,能夠使用`rest`參數代替。 4. 箭頭函數不能使用`yield`命令,即不能用做Generator函數。
一個簡單的例子:
function Person(){ this.age = 0; setInterval(() => { this.age++; }, 1000); } var p = new Person(); // 定時器一直在執行 p的值一直變化
本部份內容到這結束
Author | 王平安 |
---|---|
pingan8787@qq.com | |
博 客 | www.pingan8787.com |
微 信 | pingan8787 |
每日文章推薦 | https://github.com/pingan8787... |
JS小冊 | js.pingan8787.com |
歡迎關注微信公衆號【前端自習課】天天早晨,與您一塊兒學習一篇優秀的前端技術博文 .