1. 程式人生 > 實用技巧 >JS函式深入

JS函式深入

函式的本質是物件

三種定義方式

1、 字面量=function宣告

            function add() {
                // body...
            }
            add();

2、 var賦值表示式

            var add = function (argument) {
                // body...
            };
            add();
            var add = function fn(argument) {
                
// body... fn(); add(); }; add(); fn();//會報錯,只能在函式體內呼叫

3、 建構函式

    var add = new Function('num1', 'num2', 'return num1 + num2;');
            add();

三種定義方式區別:

字面量=function宣告:預載入時add=function

    console.log(add());
    function add() {
        
return 1; }

var賦值表示式:預載入時add=undefined

    console.log(add());
    var add = function () {
        return 1;
};

建構函式:少用


雜七雜八的知識點:

JS中沒有塊級作用域,所以不會在if中發生預解析,在外部預解析的時候,if中宣告的所有函式都會被提前,所以無法達到按需定義的目的。

內部函式可以訪問外部函式的變數(作用域鏈的機制)


案例:寫出一個加法(add)函式,並在其內部定義一個函式(isNumber),用來判斷add的引數是否可以轉化為數字型別進行相加,

如果可以,就在頁面中輸出結果;

如果不能就退出add,給出提示“請傳入數字型別的引數”

function add(num1,num2){
    if(isNaN(num1) || isNaN(num2)){
        alert('請傳入數字型別的引數');
        return;
    }else{
        return parseInt(num1)+parseInt(num2);
    }
}

var num1=prompt('請輸入數字1');

var num2=prompt('請輸入數字2');

alert(add(num1,num2));

案例:匿名函式也是函式,當它自執行的時候會建立函式作用域,它裡面的變數和函式都是區域性的,當匿名函式執行完畢後會被銷燬。所以我們在外面訪問不到add

    function () {
        function add(num1,num2){
            return num1+num2;
        }
    }();
    document.write(add(1,2));//報錯

匿名函式自執行方式:

    var add = function () {
        console.log(1);
    }();

    (function () {
        console.log(1);
    })();

    !+-~function () {
        console.log(1);
    }();

遞迴呼叫:遞迴呼叫就是自己呼叫自己,但切記一定要有終止條件,否則函式將無限遞迴下去

    function factorial(num) {
        if (num <= 1) return 1;
        return num * factorial(num - 1);
        // return 5 * 4! = 5 * 4 * 3! =... 5 * 4 * 1!
    }
    console.log(factorial(5));

方法的呼叫:

    document.onclick = function () {
        console.log('你點選了文件!');
    };
    document.onclick();
    var operation = {
        add: function (num1, num2) {
            return num1 + num2;
        },
        subtract: function (num1, num2) {
            return num1 - num2;
        },
        '@': function () {
            console.log('@');
        },
        key: function () {
            // body...
        }
    };
    console.log(operation.add(1, 2));
    console.log(operation['@'](1, 2)); //@符比較特別
    var key = 'add';
    console.log(operation[key](1, 2));

鏈式呼叫

    var operation = {
        add: function (num1, num2) {
            console.log(num1 + num2);
            return this;
        },
        subtract: function (num1, num2) {
            console.log(num1 - num2);
            return this;
        },
        '@': function () {
            console.log('@');
        },
        key: function () {
            // body...
        }
    };
    operation.add(1, 2).subtract(2, 1);

間接呼叫:

物件沒有call和apply方法,只有函式有

call和apply的唯一區別就在它們傳參的方式上

apply可以將陣列和類陣列一次性的傳遞進函式中,call只能一個一個的傳;

    var name = 'xm';
    var person = {};
    person.name = 'xh';
    person.getName = function () {
        return this.name;
    };
    console.log(person.getName()); //this指向person
    console.log(person.getName.call(window)); //this指向window
    console.log(person.getName.apply(window)); //this指向window

    function add(num1, num2) {
        return num1 + num2;
    }
    console.log(add(1, 2));
    var datas = [1, 2];
    console.log(add.call(window, 1, 2));
    console.log(add.apply(window, datas)); //apply(ele,[])

輸出:'xm', [object Object]

person()就是普通函式的呼叫,返回值是return後面的內容:'xm' ; new person()是將person作為建構函式呼叫,返回的永遠是物件 ; document.write沒法輸出物件,它會嘗試著將其轉換成字串輸出

輸出:undefined

call可以改變函式中this的指向,這裡在呼叫方法的時候將其this改為了window,所以this.value就變成了window.value,而window.value沒有定義過,所以為undefined


函式的引數:

function add() {
    if (arguments.length == 0) return;
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
}
console.log(add());
console.log(add(1, 2, 3, 4, 5));

arguments

類陣列,實質是類

function fn(name) {
    arguments[0] = '';
    console.log(name);
}
fn('xm');//沒有輸出

arguments.callee 指代函式本身,多用於遞迴

計算階乘方法一:

function factorial(num) {
    if (num <= 1) return 1;
    return num * factorial(num - 1);
}
console.log(factorial(5));

計算階乘方法二:

function factorial(num) {
    if (num <= 1) return 1;
    return num * arguments.callee(num - 1);
}
console.log(jiecheng(5));

計算階乘方法三:

var jicheng = function fn(num) {
    if (num <= 1) return 1;
    return num * fn(num - 1);
};
console.log(jicheng(5));

判斷傳入實參的個數是否與形參相等

arguments.length實參個數

add.length形參個數

function add(num1, num2) {
    if (arguments.length != add.length) throw new Error('請傳入' + add.length + '個引數!');
    return num1 + num2;
}
console.log(add(1, 1));
console.log(add(1));
console.log(add(1, 2, 3));

案例:

輸出:1,1,1,1,2,3

1、 count()()這樣呼叫,每次都會建立一個新的區域性作用域,num的值會不斷地被初始化為1

2、 return num++表示先返回num的值,再將num加1

3、 先將count()賦給fn,此時count()只調用了一次,接下來多次呼叫fn()的時候,count函式並沒有多次呼叫,num只會在count函式呼叫的時候被初始化,所以多次呼叫fn()的時候num不會被多次初始化;由於fn相當於count函式的內層函式(var fn=count();這行程式碼執行後,就呼叫了count(),呼叫count後就將裡面的函式賦值給了fn,所以說fn就相當於函式的內層函數了。),可以訪問count中的變數num,所以多次呼叫fn函式,會將num的值累加;