javascript忍者祕籍-第三章 函式定義與引數

smiler2018發表於2018-12-03

函式的定義與引數

JavaScript 作為函式式語言來理解。

關鍵概念

函式是第一類物件(一等公民)

函式可以看作是 其他任意型別的 Javascript 物件

函式和其他的資料型別一樣,能被變數引用,以字面量形式宣告,作為函式引數傳遞

發現

:musical_note: 在需要呼叫某函式的位置 定義該函式,能讓程式碼更緊湊、更易懂

術語

一等公民

一般來說,如果某程式設計語言中的一個值可以作為 引數傳遞,可以從 子程式中返回,可以 賦值給變數,就稱為一等公民

二等公民

可以作為 引數傳遞,但是不能從子程式中返回,也不能賦值給變數

三等公民

值連作為引數傳遞都不行(label)

3.1 函式式的不同點

與物件的不同

物件的常見功能

  1. 物件可通過字面量來建立 {}

    var lsObj = {};
    複製程式碼
  2. 物件可以賦值給變數、陣列項,或其他物件的屬性

    var lsObj = {};
    lsArray.push({});
    lsObj.data = {}
    複製程式碼
  3. 物件可以作為引數傳遞給函式

    function hide(obj){
        obj.visibility = false;
    }
    hide({});
    複製程式碼
  4. 物件可以作為函式的返回值

    function returnNewLs(){
        return {};
    }
    複製程式碼
  5. 物件能夠具有動態建立和分配的屬性

    var lsObj = {};
    lsObj.name = "lisi";
    複製程式碼

函式是第一類物件

函式擁有物件的所有能力,所以函式可被看作 任意其他型別 的物件

函式也具有物件的功能

  1. 通過字面量建立

    function ninjaFunction(){}
    複製程式碼
  2. 賦值給變數、陣列項或其他物件的屬性

    var ninjaFunction = function(){};   //為變數賦值一個新函式
    ninjaArray.push(function(){});      //向陣列中增加一個新函式
    ninja.data = function(){};          //給某個物件的屬性賦值一個新函式
    複製程式碼
  3. 作為函式的引數傳遞

    function call(ninjaFunction){
        ninjaFunction();
    }
    //新函式作為引數傳遞給函式
    call(function(){});
    複製程式碼
  4. 作為函式的返回值

    //返回一個新函式
    function returnNewNinjaFunction(){
        return function(){};
    }
    複製程式碼
  5. 動態建立的屬性

    //為函式增加一個新屬性
    var ninjaFunction = function(){};
    ninjaFunction.ninja = "Hanzo";
    複製程式碼

:eight_pointed_black_star: 函式也是物件,函式與物件的不同在於:==函式是可呼叫的==

:v: 第一類物件的特點之一:能夠作為引數傳入函式

對於函式來說這個特性表明:將某個函式作為引數傳入另一個函式,傳入的函式會在將來的某個時刻執行。由此推出 【回撥函式】

回撥函式

瀏覽器的回撥函式(計時器函式)和我們自定義的回撥函式

回撥不一定是非同步的

瀏覽器回撥

document.body.addEventListener("mousemove",function(){...})
複製程式碼

自定義的回撥

排序方法sort,可以傳入一個函式進行排序

var values = [0,3,2,7,1,8];
values.sort(function(value1,value2){
    return value1 - value2;
});
複製程式碼

? 函式式方式 把 函式當作一個 單獨實體 來建立,與其他型別一樣,建立、作為引數傳遞和返回。函式顯示了一等公民的地位。

function(value1,value2){} 是一個整體,類似 abc

3.2 函式作為物件

類似物件,函式也可以新增屬性

//物件
var ninja = {};
ninja.name = 'hitsuke';

//函式
var wieldSword = function(){};
wieldSword.swordType = "katana";
複製程式碼

儲存函式

函式的屬性作為值

:question: 管理一個元素的所有回撥函式集合,相同的回撥只儲存一次

//儲存唯一函式集合
var store = {
    nextId : 1,
    cache : {},
    add : function(fn){
        if(!fn.id){
            fn.id = this.nextId++;
            this.cache[fn.id] = fn;
            return true;
        }
    }
}

function ninja(){}

store.add(ninja);  //true  ninja.id 存在了  
//Object.getOwnPropertyNames(ninja) (6) ["length", "name", "arguments", "caller", "prototype", "id"]
store.add(ninja);  //undefined
複製程式碼

快取結果

函式的屬性作為物件

//計算先前得到的值
function isPrime(value){
    if(!isPrime.answers){
        isPrime.answers = {};  //建立快取
    }
    if(isPrime.answers[value] !== undefined){
        return isPrime.answers[value];  //檢查快取的值 並 返回
    }
    var prime = value !== 0 && value !== 1;
    for(var i = 2;i < value; i++){
        if(value % i === 0){
            prime = false;
            break;
        }
    }
    return isPrime.answers[value] = prime;  //儲存計算的值
}

isPrime(5);
isPrime.answers[5];
複製程式碼

3.3 函式定義

JavaScript 定義函式的幾種方式

  1. 函式宣告和函式表示式

    function abc(){}
    
    var abc = function(){}
    複製程式碼
  2. 箭頭函式 lambda函式

    myArg => myArg * 2
    複製程式碼
  3. 函式建構函式

    new Function('a','b','return a + b')
    複製程式碼
  4. 生成器函式

    //函式退出再進入時,之前的變數值被儲存
    function* myGen(){ yield 1; }
    複製程式碼

函式宣告和函式表示式

//函式宣告強制以 function 開頭;作為一個單獨的JavaScript語句,函式宣告必須獨立
function samurai(){
    return "samurai here";
}

function ninja(){
    function hiddenNinja(){
        return "ninja here";
    }
    return hiddenNinja();
}
複製程式碼
//函式表示式 作為 賦值表示式的右值 、作為其他函式的引數
var myFunc = function(){};

myFunc(function(){
    return function(){};
});
複製程式碼

對於函式宣告來說,函式名是強制性的,對於函式表示式來說,函式名是可選的。

立即執行函式

一般包裹在一對括號內:JavaScript解析器必須輕易區分 函式宣告和函式表示式的區別。

函式表示式放在括號內,為JavaScript解析器指明:它正在處理一個函式表示式而不是語句。

myFunctionName(3);

//IIFE 立即函式
(function(){})(3)

(function namedFunctionExpression(){})();  //立即呼叫

//函式表示式作為一元操作符的引數立即呼叫
//為JS引擎指明 處理的是表示式,而不是語句
+function(){}();
-function(){}();
!function(){}();
~function(){}();
複製程式碼

箭頭函式

箭頭函式是函式表示式的簡化版

//箭頭函式的語法
//箭頭函式接收一個引數並返回表示式的值
param => expression

//如果沒有引數或多於一個引數,引數列表必須包裹在括號內
//如果只有一個引數,括號不是必須的
var greet = name => "Greeting " + name;

var greet = () => "Greeting";
var greet = (name,age) => "hello " + name + age;

//胖箭頭 操作符後面可以是 表示式 也可以是程式碼塊
var greet = name => "Greeting" + name;

var greet = (name,age) => {
    return name + age;
}
複製程式碼
var values = [1,2,3,5,8];
values.sort(function(value1,value2){
    return value1 - value2;
});

//箭頭函式
values.sort((value1,value2) => value1 - value2);
複製程式碼

3.4 函式的實參和形參

如果函式的 實引數量 > 形引數量 , 多餘的不會分配給形參

如果函式的 實引數量 < 形引數量 , 對應的形參賦值為 undefined

剩餘引數

只有函式的最後一個引數才能是剩餘引數。

給函式的最後一個形參加上省略號(…)字首,這個引數就變成了一個 剩餘引數的陣列 。陣列內包含著傳入的剩餘的引數。

function multiMax(first, ...remainingNumbers){
    ...
}
複製程式碼

預設引數

為函式的引數提供一個預設引數

預設引數可以是任意值:數字、字串、物件、陣列、甚至是函式

後面的預設引數 可以引用 前面的預設引數

function performAction(ninja, action){
    action = typeof action === "undefined" ? "skulking" : action;
    return ninja + " " + action;
}

function performAction(ninja, action = "skulking"){
    return ninja + " " + action;
}

function performAction(ninja, action = "skulking", message = ninja + " " + action){
    return message;
}
複製程式碼

typeof 操作符返回一個字串 用於表明運算元的型別。如果運算元未定義,則返回字串 "undefined"

相關文章