JS函數深刻

函數的本質是對象數組

三種定義方式app

一、  字面量=function聲明函數

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

二、  var賦值表達式this

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

三、  構造函數spa

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

三種定義方式區別:code

字面量=function聲明:預加載時add=function對象

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

var賦值表達式:預加載時add=undefinedblog

    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

一、 count()()這樣調用,每次都會建立一個新的局部做用域,num的值會不斷地被初始化爲1

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

三、 先將count()賦給fn,此時count()只調用了一次,接下來屢次調用fn()的時候,count函數並無屢次調用,num只會在count函數調用的時候被初始化,因此屢次調用fn()的時候num不會被屢次初始化;因爲fn至關於count函數的內層函數(var fn=count();這行代碼執行後,就調用了count(),調用count後就將裏面的函數賦值給了fn,因此說fn就至關於函數的內層函數了。),能夠訪問count中的變量num,因此屢次調用fn函數,會將num的值累加;

相關文章
相關標籤/搜索