函數的本質是對象 三種定義方式 1、 字面量=function聲明 function add() { // body... } add(); 2、 var賦值表達式 var add = function (argument) { // body... }; add(); var add = func ...
函數的本質是對象
三種定義方式
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的值累加;