【重溫基礎】4.函數

本文是 重溫基礎 系列文章的第四篇。
今日感覺:常懷感恩之心,對人對己。前端

系列目錄:git

本章節複習的是JS中的基礎組件之一,函數,用來複用特定執行邏輯。github

1.定義函數

定義函數有兩種方法:函數聲明函數表達式segmentfault

1.1 函數聲明

也成爲函數聲明,一般格式爲:數組

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"}

1.2函數表達式

經過定義一個匿名的函數,來賦值給一個變量,經過這個變量來調用這個函數。閉包

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';
    }
}

2.函數調用

函數定義完成後不會自動執行,須要咱們經過函數名稱來調用,才能真正執行:

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);
}

3.函數做用域

因爲函數只在函數的內部有定義,因此函數內部定義的變量在函數外部不能訪問,函數內部就是這個函數的做用域。
當一個父級函數內,還定義了一個子級函數,則這個子級函數能夠訪問父級函數定義的變量。

// 全局做用域 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'

3.1 閉包

閉包是 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

3.2命名衝突

在同一個閉包做用域下若參數或變量名相同,產生衝突,則優先使用做用域最近

function f(){
    var a = 1;
    function g(a){
        return a + 1;
    }
    return g;
}
f()(3); // 4

4.arguments對象

函數的實際參數會被保存在一個類數組對象 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**"

5.函數參數

ES6開始,新增兩個類型的參數:默認參數剩餘參數

5.1默認參數

若函數沒有傳入參數,則參數默認值爲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

5.2剩餘參數

能夠將參數中不肯定數量的參數表示成數組,以下:

function f (a, ...b){
    console.log(a, b);
}
f(1,2,3,4); // a => 1 b => [2, 3, 4]

6.箭頭函數

函數箭頭表達式是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]
  • this

注意這幾點:

1. 箭頭函數內的`this`老是指向**定義時所在的對象**,而不是調用時。  
2. 箭頭函數不能當作**構造函數**,即不能用`new`命令,不然報錯。  
3. 箭頭函數不存在`arguments`對象,即不能使用,能夠使用`rest`參數代替。  
4. 箭頭函數不能使用`yield`命令,即不能用做Generator函數。

一個簡單的例子:

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++;
  }, 1000);
}
var p = new Person(); // 定時器一直在執行 p的值一直變化

參考資料

1.MDN 函數


本部份內容到這結束

Author 王平安
E-mail pingan8787@qq.com
博 客 www.pingan8787.com
微 信 pingan8787
每日文章推薦 https://github.com/pingan8787...
JS小冊 js.pingan8787.com

歡迎關注微信公衆號【前端自習課】天天早晨,與您一塊兒學習一篇優秀的前端技術博文 .

相關文章
相關標籤/搜索