第一百零二節,JavaScript函數

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;也就是不須要將方法追加到對象裏

相關文章
相關標籤/搜索