函數的本質是對象數組
三種定義方式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的值累加;