譯文:Javascript-Functions

我的理解+google翻譯+有道翻譯。若有錯誤,請指正。原文來自MDN:Functionsjavascript

Functions是javascript基本構建模塊之一。每個function是一個javascript程序--一組執行任務或計算值的語句。要使用一個function,必須在調用該function範圍某處先做定義。java

functions 定義(函數定義)

一個函數的定義(也成爲函數聲明)由關鍵字function設定,而後是:數組

  • 函數的名字
  • 傳遞給函數的的參數列表,這些參數用括號括起來,使用逗號分隔。
  • 定義函數的javascript語句,使用花括弧({})括起來。

例以下面的代碼中,定義了一個名爲square的簡單函數:安全

function square(number) {
    return number * number;
}

square函數接收一個參數,名爲number。該函數由一條語句組成,即返回參數number的乘積。服務器

return number * number;

初始參數(如一個數字)經過值傳遞給函數,傳遞給函數的值若是被被函數修改了,這種狀況下值的修改不反映到全局環境或函數調用中(this change is not reflected globally or in the calling function.)。閉包

若是傳遞一個對象(即非原始值,如Array或用戶自定義對象)參數,函數修改對象的屬性,這種修改對於函數外部是可見的,看下面的用例演示:app

function myFunc(theObject) {
    theObject.make = "Toyota";
}

var mycar = {make: "Honda", model: "Accord", year: 1998},
    x,
    y;
    x = mycar.make;     // x 取值 "Honda"
    myFunc(mycar);
    y = mycar.make;     // y 取值 "Toyota"
                        // (make 屬性已經被函數修改)

注意:賦值一個新的對象給參數對函數外部沒有任何影響,由於這種狀況改變了參數的值,而不是改變了對象的屬性值:ide

function myFunc(theObject) {
    theObject = {make: "Ford", model: "Focus", year: 2006};
}

var mycar = {make: "Honda", model: "Accord", year: 1998},
    x,
    y;
x = mycar.make;     // x 取值 "Honda"
myFunc(mycar);
y = mycar.make;     // y 一直取值 "Honda"

在第一個例子中,對象mycar傳給函數myFunc,並改變了對象mycar。函數

對於原文有不一樣見解:ui

原文:In the second case, the function did not alter the object that was passed; instead, it created a new local variable that happens to have the same name as the global object passed in,

翻譯:在第二個例子中,函數沒有改變傳過來的對象;函數建立了一個新的局部變量,只不過這個新的局部變量與傳入的全局對象名稱相同。

此處函數並非建立了一個新的局部變量,而是,theObject做爲函數的參數,自己就是個局部變量,在函數體內的theObject = {make: "Ford", model: "Focus", year: 2006};
實際上是該參數指向了一個新的對象而非建立了一個新的局部變量。傳入的對象在函數內被「改變」。

因此對傳入的全局對象沒有任何影響。

以上的函數聲明是語法上地函數聲明,函數也能夠經過函數表達式建立。函數能夠是匿名的,沒必要有一個名稱。例如,函數square能被定義爲:

var square = function(number) {return number * number};
var x = square(4) //x 取值 16

此外,函數名能夠提供一個函數表達式,而且能夠用於在函數內部指向自己,或在調試器中堆棧跟蹤過程肯定函數:

var factorial = function fac(n) {return n<2 ? 1 : n*fac(n-1)};
console.log(factorial(3));//6 函數的遞歸

當函數做作爲參數傳遞給另外一個函數時,函數表達式很是方便。下面的例子中展現了一個名爲map的函數,調用它使用一個匿名函數做爲其第一個參數:

function map(f,a) {
    var result = [],
    i;
    for (i = 0; i != a.length; i++){
        result[i] = f(a[i]);
    }
    return result;
}

下面的代碼:

map(function(x) {return x * x * x}, [0, 1, 2, 5, 10]);

返回 0,8,125,1000

在JavaScript中,函數能夠根據條件來定義。例如,下面的函數定義中只有當num等於0時定義myFunc:

var myFunc;
if (num == 0){
    myFunc = function(theObject) {
        theObject.make = "Toyota"
    }
}

除了描述性的定義函數,也能夠在程序運行時使用 Function constructor(函數構造)和一個字符串建立函數,與eval()很類似;例如

var setBGColor = new Function("document.bgColor = 'antiquewhite'");//將一個函數分配給變量setBGColor。該函數設置當前文檔的背景顏色

一個方法是一個函數,這個函數方法也能夠做爲對象的屬性。關於objects和methods更多信息參考Working with Objects

調用函數

定義一個函數而不運行它。則定義的函數只是爲該函數命名和指定該函數被調用的時候去作什麼事情。調用函數時實際是經過指定的參數執行指定的動做。例如,定義了一個函數square,你會按下面的方式調用:

square(5);

前面的語句是以5爲參數調用square函數。該函數執行內部語句返回值25。

函數被調用時肯在一個做用域內,但函數的聲明能夠在函數調用下面,例如:

print(square(5));
/* ... */
function square(n){return n*n} 

函數的做用域由其在聲明時所在的範圍,或是整個程序若是在頂級範圍聲明。注意這種運行方式只在上例的語法下定義函數(即fucnction funName(){})。下面的代碼不會運行。

print(square(5));
square = function (n) {
  return n * n;
}

 函數的參數不僅侷限於字符串和數字類型。也能夠傳一個對象到函數。例子show_prop函數(定義在Working with Objects)接收一個對象做爲參數。

函數能夠是遞歸的,也就是說,它能夠調用自己。例如,這裏是一個函數,遞歸計算階乘:

function factorial(n){
    if ((n == 0) || (n == 1))
        return 1;
    else
        return (n * factorial(n - 1));
}

而後能夠經過下面的代碼計算1到5的階乘:

var a, b, c, d, e;
a = factorial(1); // a gets the value 1
b = factorial(2); // b gets the value 2
c = factorial(3); // c gets the value 6
d = factorial(4); // d gets the value 24
e = factorial(5); // e gets the value 120

還有其餘的方法來調用函數.常常有函數須要動態調用或變化函數的參數數量,或在運行時的函數上下文中設置一個指定的肯定對象。證實functions是它們本身,也是對象,對象反過來含有方法(參見Function object)。【It turns out that functions are, themselves, objects, and these objects in turn have methods (see the <i>Function object</i>). 】 apply()可以實現這一目標。

函數做用域

定義在函數內的變量不能被函數外部任何地方訪問,由於只是定義在函數範圍內。然而在已定義的函數內,一個函數可使用全部的定義的變量和函數。也就是說,全局做用域內定義的函數可使用全局做用域內全部定義的變量。在另外一個函數內定義的函數也可使用其在父函數內定義的和其它父函數可訪問的全部變量。

// 下面的變量定義在全局做用域內
var num1 = 20,
    num2 = 3,
    name = "Chamahk";
// 這個函數定義在全局做用域內
function multiply() {
    return num1 * num2;
}
multiply(); // Returns 60
// 一個內嵌函數示例
function getScore () {
    var num1 = 2,
          num2 = 3;              
    function add() {
        return name + " scored " + (num1 + num2);
      }              
      return add();
}
getScore(); // Returns "Chamahk scored 5"

閉包

閉包是Javascript很是強大的功能之一。JavaScript容許函數嵌套,此外,授予內部函數訪問全部其外包函數內定義的變量和函數(其它變量和函數須要能被父函數訪問。)但外包函數不能訪問其內部函數定義的變量和函數。這樣使內部函數的變量獲得了安全。此外,由於內部函數能夠在外包函數的做用域內訪問,因此當內部函數管理週期超過外包函數生存期時,在外包函數內定義的變量和函數將會比外包函數存在時間更長。當內部函數在外包函數外部任意範圍以某種方式變爲有效代碼時就建立了一個閉包。

var pet = function(name) {         // 外包函數定義name變量
    var getName = function() {
        return name;               // 內部函數訪問外包函數的name變量
    }
return getName;                    // 返回內部函數,從而暴露到外部做用域
},
myPet = pet("Vivie");            
myPet();                           // Returns "Vivie"

也能夠比上面的代碼複雜得多。能夠返回一個包含處理外包對象內部變量的方法的對象。

var createPet = function(name) {
      var sex;  
      return {
        setName: function(newName) {
              name = newName;
        },                
        getName: function() {
              return name;
        },                
        getSex: function() {
              return sex;
        },                
        setSex: function(newSex) {
              if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
                sex = newSex;
              }
        }
      }
}
var pet = createPet("Vivie");
pet.getName();                  // Vivie
pet.setName("Oliver");
pet.setSex("male");
pet.getSex();                   // male
pet.getName();                  // Oliver

在上面的代碼中,外包函數的變量名能夠被內部函數訪問,並且沒有其餘方式訪問內部變量除非經過內部函數訪問。內部函數的變量做爲內部函數的安全存儲。它們保持特殊的「持久狀態」,但爲內部函數的運行提供安全的數據(They hold "persistent", yet secure, data for the inner functions to work with)。這些內部函數甚至能夠不分配一個變量或擁有一個名稱。

var getCode = (function(){
var secureCode = "0]Eal(eh&2";    // 一處代碼不但願被外部修改...          
    return function () {
        return secureCode;
    };
})();

getCode();    // 返回保密的代碼

可是要提防使用閉包時的一些陷阱。若是一個閉包函數定義了一個與外部做用域變量同名的變量,將沒有任何辦法再次指向外部做用域的同名變量。

var createPet = function(name) {    // 外包函數定義了一個名爲name的變量
    return {
        setName: function(name) {    // 閉包函數也定義了一個名爲name的變量
            name = name;             // ??? 咱們如何訪問外包函數定義的name變量 ???
        }
    }
}

閉包內的this變量很是神奇及不可捉摸。他們必須當心使用,由於this的指向徹底取決於函數的調用,而非取決在哪定義。關於閉包的精品文章在這能夠找到:closures(閉包)

使用 arguments 參數對象

函數的參數保存在一個相似數組的對象內。能夠像下面的代碼在函數中尋址傳遞給函數的參數。

arguments[i];

其中i是參數的起始值爲0索引序號。因此傳遞給函數的第一個參數會是argument[0]。參數的總數用的arguments.length表示。

使用arguments參數對象時,可使用比函數聲明接收的參數數量更多的參數來調用函數。一般在你事先不知道有多少參數將被傳遞給函數時是頗有用處的。可使用arguments.length來肯定實際傳遞給函數的參數的個數,而後使用arguments 參數對象來訪問每一個參數。

function myConcat(separator) {
    var result = "", // 初始化列表
        i;
       // 遍歷參數
    for (i = 1; i < arguments.length; i++) {
        result += arguments[i] + separator;
    }
    return result;
}

能夠傳遞任意數量的參數給這個函數,它串連每一個參數轉換成字符串「列表」。

// returns "red, orange, blue, "
myConcat(", ", "red", "orange", "blue");

// returns "elephant; giraffe; lion; cheetah; "
myConcat("; ", "elephant", "giraffe", "lion", "cheetah");

// returns "sage. basil. oregano. pepper. parsley. "
myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");

須要注意的是:arguments變量相似於數組,不是真正的數組。arguments變量相似數組是由於它編號索引和length屬性,此外,也不具有數組處理方法。更多信息參看Javascript參考Function object 

預約義函數

javascript有幾個一級預約義函數:

 如下各節將介紹這些函數,更多詳細信息參考 JavaScript Reference

eval 函數

eval函數不引用特定對象來運行計算一行javascript字符串類型的代碼,其語法以下:

eval(expr);

expr爲運行的字符串。

若是該字符串表明一個表達式,eval運行計算該表達式。若是該參數表明一行或多行JavaScript語句中,eval執行語句。eval代碼做用域與調用eval代碼做用域相同。不要用eval運行一個計算表達式;javascript自動運行計算表達式。

isFinite 函數

isFinite函數肯定參數是否爲一個有限數字。語法以下:

isFinite(number);

number爲數字類型。

若是參數爲NaN,正無窮大或負無窮大,此方法返回false,不然返回true。

下面的代碼檢查客戶端的輸入,肯定它是不是一個有限數字。

if(isFinite(ClientInput)){
        /* 執行指定步驟 */
}

isNaN 函數

isNaN函數判斷參數是不是「NaN」(非數字值),語法以下:

isNaN(testValue);

testValue爲須要判斷的值。

parseFloat函數和parseInt函數運行一個非數字值時,返回NaN。若是傳入一個「NaN」(非數字),isNaN返回true,不然false。

下面的代碼肯定floatValue是不是一個數字,而後相應地調用對應程序。

var floatValue = parseFloat(toFloat);
if (isNaN(floatValue)) {
    notFloat();
} else {
    isFloat();
}

parseInt函數 和 parseFloat函數

 兩個解析(轉換)函數,parseInt和parseFloat,當參數爲字符串時返回一個數字值。

parseFloat語法:

parseFloat(str);

其中parseFloat解析它的參數字符串str,並試圖返回一個浮點數.若是遇到一個字符不是一個符號(+或 - ),數字(0-9),小數點或指數,則在此處返回值,並忽略該字符及其後的全部字符。若是第一個字符不能被轉換爲數字,則返回「NaN」(非數字)。

parseInt語法

parseInt(str [, radix]);

parseInt函數解析轉換第一個字符串參數str,並嘗試返回一個以指定的radix參數爲基數的整數。radix爲可選參數。理由radix爲10則轉換爲十進制數,爲8時轉換八進制數,16時轉換爲十六進制等等。對高於十的進制數,使用字母表中的字母來表示大於9的數。例如十六進制數使用A-F。

若是parseInt函數遇到一個不是指定基數的數字字符,則忽略該字符和後續字符,返回解析到該點的整數值。若是第一個字符不能轉換爲指定基數的數字,返回NaN。parseInt函數截取字符串轉爲整數。

Number 和 String 函數

Number 和 String 函數能夠把一個對象轉爲數字類型或字符串類型。語法以下:

var objRef;
objRef = Number(objRef);
objRef = String(objRef);

objRef做爲對象引用。Number做爲對象的valeOf()方法;String做爲對象的toString()方法。

下面的例子轉換Date對象爲可讀的字符串。

var D = new Date(430054663215),
    x;
x = String(D); // x equals "Thu Aug 18 04:37:43 GMT-0700 (太平洋夏令時) 1983"

下面的例子把String(字符串)對象轉換爲Number(數字)對象。

var str = "12",
   num;
num = Number(str);

咱們能夠經過DOM的write()和javascript的typeOf運算符來作一個檢測。

var str = "12",
    num;
document.write(typeof str);
document.write("<br/>");
num = Number(str);
document.write(typeof num);

escape 和 unescape 函數(JavaScript 1.5以上已廢棄)

escape和unescape 函數對非ASCII字符不能正常運行,已被棄用。在JavaScript1.5和更高版本,使用encodeURI,decodeURI,encodeURIComponent和decodeURIComponent。

escape和unescape函數能夠對字符串進行編碼和解碼。escape函數返回參數在ISO拉丁字符集十六進制編碼。unescape函數返回指定的十六進制編碼值的ASCII字符串。

語法以下:

escape(string);
unescape(string);

它們主要用於服務器端JavaScript對URL鍵值對進行編碼和解碼。

相關文章
相關標籤/搜索