函數是這樣一段JavaScript代碼 它只定義一次 但可能被執行或調用屢次
Function類型是JavaScript提供的引用類型之一 經過Function類型建立Function對象
在JavaScript中 函數也是以對象的形式存在的 每一個函數都是一個Function對象
函數名 本質就是一個變量名 是指向某個Function對象的引用數組
// 1.函數聲明方式 function fun(){ console.log('this is function'); } // 2.字面量方式 var fn = function(){ console.log('this is function too'); } // 判斷函數是否爲Function類型的 console.log(fun instanceof Function);// true console.log(fn instanceof Function);// true // JavaScript中全部的函數都是Function類型的對象 /* 3.建立Function類型的對象 - 是一個函數 var 函數名 = new Function(參數,函數體); * 因爲函數的參數和函數體都是以字符串形式傳遞給Function的 */ var f = new Function('a','console.log(a)'); f(100);// 以函數方式進行調用
// 1.Object與Function都是自身的類型 console.log(Object instanceof Object);// true console.log(Function instanceof Function);// true // 2.Object自身是構造函數,而構造函數也是函數,是函數都是Function類型 console.log(Object instanceof Function);// true // 3.Function是引用類型,用於建立對象,是對象都是Object類型 console.log(Function instanceof Object);// true
..變量的聲明提早 console.log(v);//undefined var v = 100; //若是使用函數聲明方式定義函數時 - 函數的聲明提早 fun() function fun(){ console.log('this is function'); }
Function的apply()方法用於調用一個函數 而且接受指定的this值 以及一個數組做爲參數緩存
// 定義函數 function fun(value){ console.log('this is ' + value); } // 函數的調用方式 fun('function');// 語法結構:函數名稱() /* apply(thisArg,argArray)方法 -> 用於調用一個指定函數 * 參數 * thisArg - this * argArray - 數組,做爲參數(實參)的列表 */ fun.apply(null, ['function']);
Function的call()方法用於調用一個函數 而且接受指定的this值做爲參數 以及參數列表閉包
//定義函數 function fun(value value2){ console.log('this is' + value); } //函數的調用方式 fun('function','張三');//語法結構:函數名稱() fun.apply(null,['function','張三']); //call()方法 - 用於調用一個函數 fun.call(null,'function','張三');
Function的bind()方法用於建立一個新的函數(稱爲綁定函數) 而且接受指定的this值做爲參數 以及參數列表app
// 定義函數 function fun(value){ console.log('this is ' + value); } /* bind(thisArg, arg1, arg2, ...)方法 * 做用 - 用於建立一個新函數(稱爲綁定函數) * 參數 * thisArg - this * arg1, arg2, ... - 表示參數列表 * 返回值 - 返回新的函數 */ // var f = fun.bind();// 相對於從指定函數複製一份出來 fun('李四');// this is 李四 var f = fun.bind(null, '張三'); f();// this is 張三
在其餘開發語言中 函數具備一種特性 叫作重載 重載就是定義多個同名的函數 但每個函數接受的參數的個數不一樣 程序會根據用時傳遞的實參個數進行判斷 具體調用的是哪一個函數
可是在JaveScript中 函數是沒有重載現象的 也就是說 若是同時定義多個同名的函數 只有最後一個定義的函數是有效的函數
/* 重載的含義 1.定義多個同名的函數,但具備數量不一樣的參數 2.調用函數,根據傳遞參數的個數調用指定的函數 */ function add(a,b){ return a + b; } function add(a,b,c){ return a + b + c; } function add(a,b,c,d){ return a + b + c + d; } add(1,2);// 3 add(1,2,3);// 6 add(1,2,3,4);// 10 // JavaScript的函數不存在重載 -> 當函數同名時,最後一次定義的函數有效 console.log(add(1,2));// NaN console.log(add(1,2,3));// NaN console.log(add(1,2,3,4));// 10
JavaScript提供了arguments對象 該對象能夠模擬函數重載的現象 arguments對象是函數內部的本地變量 arguments已經再也不是函數的屬性了
arguments對象能夠獲取函數的全部參數 但arguments對象並非一個數組 而是一個類數組對象(沒有數組特有的方法)佈局
/* JavaScript提供arguments對象 * 該對象存儲當前函數中全部的參數(實參) - 類數組對象 * 場景 - 該對象通常用於函數中 * 做用 - 用於獲取當前函數的全部參數 * 屬性 * length - 函數全部參數(實參)的個數 * 用法 - 模擬實現函數的重載 */ function add(){ var num = arguments.length; switch (num) { case 2: return arguments[0] + arguments[1]; break; case 3: return arguments[0] + arguments[1] + arguments[2]; break; case 4: return arguments[0] + arguments[1] + arguments[2] + arguments[3]; break; } } console.log(add(1,2));// 3 console.log(add(1,2,3));// 6 console.log(add(1,2,3,4));// 10
調用自身的函數被稱之爲遞歸函數 在某種意義上說 遞歸近似於循環 二者都有重複執行相同的代碼 而且二者都須要一個終止條件以免無限循環或者無限遞歸性能
/* 函數的遞歸 -> 就是在指定函數的函數體中調用自身函數 function fun(){ // 當前函數的邏輯內容 console.log('this is function'); // 調用自身函數 -> 實現遞歸 fun(); } fun(); */ function fn(v){ console.log(v); if (v >= 10) { return; } // fn(v + 1); arguments.callee(v + 1); } // fn(0); var f = fn; fn = null; f(0); // console.log(f);
JavaScript能夠將函數做爲數據使用 做爲函數本體 它像普通的數據同樣 不必定要有名字 默認名字的函數被稱之爲匿名函數this
function(a){return a;} /* 匿名函數的做用: 1.將匿名函數做爲參數傳遞給其餘函數 - 回調函數 2.將匿名函數用於執行一次性任務 - 自調函數 */
當一個函數做爲參數傳遞給另外一個函數時 做爲參數的函數被稱之爲回調函數code
// 做爲另外一個函數(fn)的參數的函數(one) - 回調函數 var one = function(){ return 1; } function fn(v){ return v(); } // one函數僅是做爲fn函數的參數出現 - 並非調用 // var result = fn(one); /* 以上代碼等價於如下代碼 如下代碼中做爲參數的函數 - 匿名回調函數 */ var result = fn(function(){return 1;}); console.log(result);// 1
回調函數的優勢:
1.它能夠在不作命名的的狀況下傳遞函數(這意味着能夠節省全局變量)
2.能夠將一個函數調用操做委託給另外一個函數(這意味着能夠節省一些代碼編寫工做)
3.回調函數也有助於提高性能對象
// 做爲另外一個函數(fn)的參數的函數(one) -> 回調函數 var one = function(w){ return w; } function fn(v){// 形參是一個函數 return v(100);// 函數的調用體 } // var result = fn(one);// 實參必須是一個函數 var result = fn(function(w){return w;}); console.log(result);
自調函數就是定義函數後自行調用
/* 自調函數 - 定義即調用的函數 * 第一個小括號 - 用於定義函數 * 第二個小括號 - 用於調用函數 */ // 全局做用域 - 生命週期:JavaScript文件從執行到執行完畢 (function(value){ // 函數做用域 - 生命週期:從函數調用到調用完畢 console.log('this is ' + value); })('function'); // 表達式語法 (function(value){ // 函數做用域 - 生命週期:從函數調用到調用完畢 console.log('this is ' + value); }('function')); !function(value){ // 函數做用域 - 生命週期:從函數調用到調用完畢 console.log('this is ' + value); }('function'); +function(value){ // 函數做用域 - 生命週期:從函數調用到調用完畢 console.log('this is ' + value); }('function');
將一個函數做爲另外一個函數的結果進行返回 做爲結果返回的函數稱之爲值的函數
var one = function(){ return 100; } // 做爲值的函數 -> 內部函數的一種特殊用法 function fun(){ var v = 100; // 內部函數 return function(){ return v; }; } var result = fun(); //console.log(result);// one函數 //console.log(result());// 100 console.log(fun()());
不少開發語言中都具備塊級做用域 但ECMAScript5版本中並無跨級做用域 這常常會致使理解上的困惑
雖然ECMAScript5版本沒有塊級做用域 但具備函數做用域 在某個函數內部定義的便利的做用域就是該函數做用域
每一段JavaScript代碼(全局代碼或函數)都有一個與之關聯的做用域鏈
var a = 10;// 全局變量 function fun(){ var b = 100;// fun函數做用域的局部變量 // 內部函數 function fn(){ var c = 200;// fn函數做用域的局部變量 // 內部函數 function f(){ var d = 300;// f函數做用域的佈局變量 // 調用變量 console.log(a);// 10 console.log(b);// 100 console.log(c);// 200 console.log(d);// 300 } f(); // 調用變量 // console.log(a);// 10 // console.log(b);// 100 // console.log(c);// 200 // console.log(d);// d is not defined } fn(); // 調用變量 // console.log(a);// 10 // console.log(b);// 100 // console.log(c);// c is not defined // console.log(d);// d is not defined } fun();
JavaScript容許函數嵌套 而且內部函數能夠訪問定義在外部函數中的全部變量和函數 以及外部函數能訪問的全部變量和函數 可是 外部函數卻不可以訪問定義在內部函數中的變量和函數
當內部函數以某一種方式被任何一個外部函數做用域訪問時 一個閉包距產生了
閉包就是詞法表示包括沒必要計算的變量的函數 也就是說 該函數能使用函數外定義的變量
var n;// 定義變量,但不初始化值 function fun(){// 函數做用域 var v = 100; // 進行初始化值 -> 一個函數 n = function(){ console.log(v); } // n(); } fun(); n();// 100
閉包的特色:1.局部變量:在函數中定義有共享意義(如 緩存 計數器等)的局部變量(注:定義全局變量會對外形成污染)2.內部函數:在函數(f)中聲明有內嵌函數 內嵌函數(g)對函數(f)長得局部變量進行訪問3.外部使用:函數(f)向外返回此內嵌函數(g) 外部能夠經過此內嵌函數持有並訪問聲明在函數(f)中的變量 而此變量在外部是經過其餘途徑沒法訪問的閉包的做用:1.提供可共享的局部變量2.保護共享的局部變量 提供專門的讀寫變量的函數3.避免全局污染