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的值累加;