JavaScript函數算法
學習要點:數組
1.函數聲明app
2.return返回值函數
3.arguments對象性能
函數是定義一次但卻能夠調用或執行任意屢次的一段JS代碼。函數有時會有參數,即函數被調用時指定了值的局部變量。函數經常使用這些參數來計算一個返回值,這個值也成爲函數調用表達式的值。學習
一.函數聲明this
函數對任何語言來講都是一個核心的概念。經過函數能夠封裝任意多條語句,並且能夠在任何地方、任什麼時候候調用執行。ECMAScript中的函數使用function關鍵字來聲明,後跟一組參數以及函數體。spa
function關鍵字聲明函數prototype
無參函數:指針
function box() { //沒有參數的函數 alert('只有函數被調用,我纔會被之執行'); } box(); //直接調用執行函數
有參函數:
若是有參函數在調用時沒有傳參數,會自動賦值參數爲undefined
function box(name, age) { //帶參數的函數 alert('你的姓名:'+name+',年齡:'+age); } box('李炎恢',28); //調用函數,並傳參
二.return返回值,關鍵字,給函數定義返回值
帶參和不帶參的函數,都沒有定義返回值,而是調用後直接執行的。實際上,任何函數均可以經過return語句跟後面的要返回的值來實現返回值。
無參定義返回值:
function box() { //沒有參數的函數 return '我被返回了!'; //經過return把函數的最終值返回 } alert(box()); //調用函數會獲得返回值,而後外面輸出
有參定義返回值:
function box(name, age) { //有參數的函數 return '你的姓名:'+name+',年齡:'+age;//經過return 把函數的最終值返回 } alert(box('李炎恢', 28)); //調用函數獲得返回值,而後外面輸出
咱們還能夠把函數的返回值賦給一個變量,而後經過變量進行操做。
function box(num1, num2) { return num1 * num2; } var num = box(10, 5); //函數獲得的返回值賦給變量 alert(num);
return語句還有一個功能就是退出當前函數,注意和break的區別。
PS:break用在循環和switch分支語句裏。
注意:函數裏一旦遇到return返回關鍵字後,下面還有代碼就不會執行了
function box(num) { if (num < 5) return num; //知足條件,就返回num return 100; //返回以後,就不執行下面的語句了 } alert(box(2)); //打印函數變量
三.arguments對象
ECMAScript函數不介意傳遞進來多少參數,也不會由於參數不統一而錯誤。實際上,函數體內能夠經過arguments對象來接收傳遞進來的參數。
也就是函數能夠不設置形式參數,在函數裏能夠用arguments來接收實際參數的傳參,
arguments以數組下標方式類獲取實際參數
function box() { return arguments[0]+' | '+arguments[1]; //arguments[0],將調用函數時傳的參數,當作數組索引下標的方式獲取到 //arguments[0],就是獲取傳參的第一個參數1 //arguments[1],就是獲取傳參的第二個參數2 } alert(box(1,2,3,4,5,6)); //傳遞參數
arguments對象的length屬性能夠獲得參數的數量。
也就是arguments對象的length屬性能夠檢查到,調用函數時傳了多少個實際參數
function box() { return arguments.length; //獲得6 } alert(box(1,2,3,4,5,6));
咱們能夠利用length這個屬性,來智能的判斷有多少參數,而後把參數進行合理的應用。好比,要實現一個加法運算,將全部傳進來的數字累加,而數字的個數又不肯定。
function box() { var sum = 0; if (arguments.length == 0) return sum; //若是沒有參數,返回sum變量 for(var i = 0;i < arguments.length; i++) { //若是有,就統計有多少位參數,循環對應次數,而後就累加 sum = sum + arguments[i]; } return sum; //返回累加結果26 } alert(box(5,9,12));
ECMAScript中的函數,沒有像其餘高級語言那種函數重載功能。
function box(num) { return num + 100; } function box (num) { //會執行這個函數 return num + 200; } alert(box(50)); //返回結果
函數補充,Function類型
學習要點:
1.函數的聲明方式
2.做爲值的函數
3.函數的內部屬性
4.函數屬性和方法
在ECMAScript中,Function(函數)類型其實是對象。每一個函數都是Function類型的實例,並且都與其餘引用類型同樣具備屬性和方法。因爲函數是對象,所以函數名實際上也是一個指向函數對象的指針。
一.函數的聲明方式
1.普通的函數聲明
function box(num1, num2) { return num1+ num2; } alert(box(1,2));
2.使用變量初始化函數
var box= function(num1, num2) { return num1 + num2; }; alert(box(1,2));
3.使用Function構造函數【不推薦】
var box= new Function('num1', 'num2' ,'return num1 + num2'); alert(box(1,2));
PS:第三種方式咱們不推薦,由於這種語法會致使解析兩次代碼(第一次解析常規ECMAScript代碼,第二次是解析傳入構造函數中的字符串),從而影響性能。但咱們能夠經過這種語法來理解"函數是對象,函數名是指針"的概念。
二.做爲值的函數
ECMAScript中的函數名自己就是變量,因此函數也能夠做爲值來使用。也就是說,不只能夠像傳遞參數同樣把一個函數傳遞給另外一個函數,並且能夠將一個函數做爲另外一個函數的結果返回。
將一個函數當作參數傳給另一個函數
function box(sumFunction, num) { //定義函數box return sumFunction(num); //返回執行box函數,並傳出參數10 } function sum(num) { //定義函數sum return num + 10; //返回傳入參數加10 } var result = box(sum, 10); //執行函數box,將sum函數當作參數傳入box函數 alert(result);
三.函數內部屬性
在函數內部,有兩個特殊的對象:arguments和this。arguments是一個類數組對象,包含着傳入函數中的全部參數,主要用途是保存函數參數。但這個對象還有一個名叫callee的屬性,該屬性是一個指針,指向擁有這個arguments對象的函數。
階乘遞歸
function box(num) { if (num <= 1) { return 1; } else { return num * box(num-1); //4 * 3 * 2 * 1=24階乘,遞歸 } } alert(box(4));
對於階乘函數通常要用到遞歸算法,因此函數內部必定會調用自身;若是函數名不改變是沒有問題的,但一旦改變函數名,內部的自身調用須要逐一修改。爲了解決這個問題,咱們可使用arguments.callee來代替。
callee屬性,該屬性是一個指針,指向擁有這個arguments對象的函數
function box(num) { if (num <= 1) { return 1; } else { return num * arguments.callee(num-1); //使用callee來執行box函數自身 } } alert(box(4));
this屬性
函數內部另外一個特殊對象是this,其行爲與Java和C#中的this大體類似。換句話說,this引用的是函數,數據以執行操做的對象,或者說函數調用語句所處的那個做用域。PS:當在全局做用域中調用函數時,this對象引用的就是window。
window是一個對象,並且是js裏面最大的對象,是最外圍的對象
alert(window); //打印對象,返回[object Window] alert(typeof window); //查看對象類型
this在全局做用域中時this就是window對象
alert(this); //返回[object Window]
全局變量都是Window的屬性
//全局變量都是Window的屬性 var color = "紅色的"; //聲明一個變量 alert(window.color); //經過Window屬性打印變量
經過this打印全局變量
var color = "紅色的"; //聲明一個變量 alert(this.color); //經過this屬性打印變量,全局變量也能夠經過this來打印,也等同於經過Window打印
window.color = "紅色"; 至關於var color = "紅色";
window.color = "紅色"; //至關於var color = "紅色"; alert(color); var color = "紅色"; alert(color);
this在對象裏面的指向的對象自己
注意:this在對象裏面的指向的對象自己
var box = { //建立一個對象 color:"藍色", //對象裏的一個字段,等同於一個變量 saycolor:function(){ //對象裏的一個方法,也就是匿名函數 alert(this.color); //此時的this指向的是box對象自己, } }; box.saycolor(); //執行對象裏面的saycolor()方法
this在函數與對象裏面的區別
window.color = '紅色的'; //或者var color = '紅色的';也行 var box = { //建立一個對象 color : '藍色的' //定義一個字段 }; function sayColor() { //建立一個普通函數 alert(this.color); //打印this下面的color } sayColor(); //此時執行函數,函數裏的this指向的window,因此打印的window.color //返回紅色的 box.sayColor = sayColor; //將sayColor()函數,追加到box對象裏,此時sayColor()函數裏的this就在對象裏了,this在對象裏指向的就是對象自己 box.sayColor(); //此時執行box對象裏的sayColor()函數,打印的就是對象裏面的color //返回藍色的
四.函數屬性和方法
ECMAScript中的函數是對象,所以函數也有屬性和方法。每一個函數都包含兩個屬性:length和prototype。其中,length屬性表示函數但願接收的命名參數的個數。
length屬性表示函數但願接收的命名參數的個數。
function box(name,age){ alert(name + age); } box(5,6); //執行函數 alert(box.length); //查看函數但願接收的命名參數的個數 //返回2
prototype屬性
PS:對於prototype屬性,它是保存全部實例方法的真正所在,也就是原型。這個屬性,咱們將在面向對象一章詳細介紹。而prototype下有兩個方法:apply()和call(),每一個函數都包含這兩個非繼承而來的方法。這兩個方法的用途都在特定的做用域中調用函數,實際上等於設置函數體內this對象的值。簡單一句話理解就是apply()和call()方法能夠冒充一個函數執行
apply()方法冒充另一個函數,第一個參數是要冒充的函數的做用域,第二個參數是數組類型的形式參數,用於接收函數的形式參數
冒充一個函數,實際上就是將要冒充的函數指向指定的做用域去執行
function box(num1,num2){ //原函數 return num1 + num2; } alert(box(1,2)); //執行打印返回數據 function saybox(num1,num2){ //冒充box函數執行,實際就是調用了box函數 return box.apply(this,[num1,num2]); //用apply方法冒充另一個函數,第一個參數是要冒充的函數的做用域,此時this就是box函數的做用域,this就是window //第二個參數是數組類型的形式參數,用於接收函數的形式參數 } alert(saybox(3,4)); //執行冒充函數
第二個參也能夠用arguments屬性類接收實際參數
function box(num1,num2){ //原函數 return num1 + num2; } alert(box(1,2)); //執行打印返回數據 function saybox(num1,num2){ //冒充box函數執行,實際就是調用了box函數 return box.apply(this,arguments); //用apply方法冒充另一個函數,第一個參數是要冒充的函數的做用域,此時this就是box函數的做用域,this就是window //第二個參也能夠用arguments屬性類接收實際參數 } alert(saybox(3,4)); //執行冒充函數
call()方法於apply()方法相同,他們的區別僅僅在於接收參數的方式不一樣。對於call()方法而言,第一個參數是做用域,沒有變化,變化只是其他的參數都是直接傳遞給函數的。
冒充一個函數,實際上就是將要冒充的函數指向指定的做用域去執行
和apply區別在於後面的傳參
function box(num1,num2){ //原函數 return num1 + num2; } alert(box(1,2)); //執行打印返回數據 function saybox(num1,num2){ //冒充box函數執行,實際就是調用了box函數 return box.call(this,num1,num2); //用call方法冒充另一個函數,第一個參數是要冒充的函數的做用域,此時this就是box函數的做用域,this就是window //做用域後面的參數是形式參數,原函數有多少個形式參數,就須要寫多少個形式參數 } alert(saybox(3,4)); //執行冒充函數
事實上,傳遞參數並非apply()和call()方法真正的用武之地;它們常用的地方是可以擴展函數賴以運行的做用域。
var color = '紅色的'; //或者window.color = '紅色的';也行 var box = { color : '藍色的' }; function sayColor() { alert(this.color); } sayColor(); //執行sayColor()函數,此時函數裏的this做用域是window,因此打印的是紅色 sayColor.call(this); //這句話的意思是冒充this下的sayColor函數執行,做用域在window sayColor.call(window); //這句話的意思是冒充window下的sayColor函數執行,做用域在window sayColor.call(box); //這句話的意思是冒充box對象下的sayColor函數執行,做用域在box,
冒充一個函數,實際上就是將要冒充的函數指向指定的做用域去執行
這個例子是以前做用域理解的例子修改而成,咱們能夠發現當咱們使用call(box)方法的時候,sayColor()方法的運行環境已經變成了box對象裏了。
使用call()或者apply()來擴充做用域的最大好處,就是對象不須要與方法發生任何耦合關係(耦合,就是互相關聯的意思,擴展和維護會發生連鎖反應)。也就是說,box對象和sayColor()方法之間不會有多餘的關聯操做,好比 box.sayColor = sayColor;也就是不須要將方法追加到對象裏