函數和函數的做用域問題,arguments

this的值:在函數執行時,this關鍵字並不會指向正在運行的函數自己,而是指向調用該函數的對象.因此,若是你想在函數內部獲取函數自身的引用,只能使用函數名或者使用argument.callee屬性(嚴格模式下不可用),若是該函數是一個匿名函數,則你只能使用後者. node

1.定義函數

三種方式: 算法

1)函數聲明 (function語句) 數組

function name([param[, param[, ... param]]]) { statements }
name函數名.

param函數的參數的名稱,一個函數最多能夠有255個參數. 閉包

statements這些語句組成了函數的函數體. ide

2)函數表達式 (function操做符) 函數

函數表達式和函數聲明很是相似,它們甚至有相同的語法 (查看function操做符瞭解詳情 ): 優化

function [name]([param] [, param] [..., param]) { statements }
name函數名,能夠省略,省略函數名的話,該函數就成爲了匿名函數.

param函數的參數的名稱,一個函數最多能夠有255個參數. this

statements這些語句組成了函數的函數體. spa

3)Function構造函數 prototype

和其餘類型的對象同樣,Function對象也可使用new操做符來建立:

new Function (arg1, arg2, ... argN, functionBody)
arg1, arg2, ... arg N一個或多個變量名稱,來做爲函數的形參名.類型爲字符串,值必須爲一個合法的JavaScript標識符,例如Function("x", "y","alert(x+y)"),或者逗號鏈接的多個標識符,例如Function("x,y","alert(x+y)")

functionBody一個字符串,包含了組成函數的函數體的一條或多條語句.

即便不使用new操做符,直接調用Function函數,效果也是同樣的,仍然能夠正常建立一個函數.

注意: 不推薦使用Function構造函數來建立函數.由於在這種狀況下,函數體必須由一個字符串來指定.這樣會阻止一些JS引擎作程序優化,還會引發一些其餘問題.

2.arguments對象

在函數內部,你可使用arguments對象獲取到該函數的全部傳入參數. 查看 arguments.


arguments 對象是函數內部的本地變量;arguments 已經再也不是函數的屬性了。

你能夠在函數內部經過使用 arguments 對象來獲取函數的全部參數。這個對象爲傳遞給函數的每一個參數創建一個條目,條目的索引號從 0 開始。例如,若是一個函數有三個參數,你能夠經過如下方式獲取參數:

arguments[0] arguments[1] arguments[2]

參數也能夠被從新賦值:

arguments[1] = 'new value';

arguments對象並非一個真正的數組。它相似於數組,但沒有數組所特有的屬性和方法,除了 length。例如,它沒有 pop 方法。不過能夠將其轉換成數組:

var args = Array.prototype.slice.call(arguments);
注:不該在 arguments 對象上使用 slice 方法,這會阻礙 JavaScript 引擎的優化 (好比 V8 引擎)。做爲替代,應經過遍歷 arguments 對象的方式來構建一個新的數組。


arguments 對象僅在函數內部有效,在函數外部調用 arguments 對象會出現一個錯誤。

若是你調用一個函數,當這個函數的參數數量比它顯式聲明的參數數量更多的時候,你就可使用 arguments對象。這個技術對於參數數量是一個可變量的函數來講比較有用。 你能夠用 arguments.length來獲得參數的數量,而後能夠用 argumentsobject 來對每一個參數進行處理。 (想要獲得當一個函數定義時的該函數的參數數量, 請使用 Function.length屬性。)

function myConcat(separator) {
  var args = Array.prototype.slice.call(arguments, 1);
  return args.join(separator);
}



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

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



3.遞歸

一個函數能夠指向並調用自身。 有三種方法可使一個函數指向自身:

  1. 函數名
  2. arguments.callee
  3. 一個指向函數的做用域內變量

例如, 考慮下面的函數定義:

var foo = function bar() {
   // statements go here
};

在函數體內, 下列語句是等價的:

  1. bar()
  2. arguments.callee()
  3. foo()
一個調用自身的函數稱爲遞歸函數. 在某些方面, 遞歸類同於一個循環. 都屢次執行同一段代碼, 而且都須要一個條件 (來避免無盡循環, 或者是無盡的遞歸). 例如,下面的循環:
function walkTree(node) {
   if (node == null) // 
      return;
   // do something with node
   for (var i = 0; i < node.childNodes.length; i++) {
      walkTree(node.childNodes[i]);
   }
}
將每一個遞歸算法轉化爲非遞歸的都是可能的,但一般邏輯會變得十分複雜,而且這樣作須要用到棧。事實上,遞歸自己用到了棧:函數棧。(每次感受都迷糊在這個棧裏面
function foo(i) {
   if (i < 0)
      return;
   document.writeln('begin:' + i);
   foo(i - 1);
   document.writeln('end:' + i);
}
foo(3);
begin:3
begin:2
begin:1
begin:0
end:0
end:1
end:2
end:3

4.嵌套函數和閉包

你能夠將一個函數嵌套在另外一個函數內部.被嵌套的函數 (內部函數)是隻屬於嵌套它的函數(外部函數)的私有函數.這樣就造成了一個閉包.

function addSquares(a,b) {
   function square(x) {
      return x * x;
   }
   return square(a) + square(b);
}
a = addSquares(2,3); // returns 13
b = addSquares(3,4); // returns 25
c = addSquares(4,5); // returns 41
因爲內部函數造成了一個閉包,你能夠把這個內部函數當作返回值返回,該函數引用到了外部函數和內部函數的兩個參數:
function outside(x) {
   function inside(y) {
      return x + y;
   }
   return inside;
}
fn_inside = outside(3); 
result = fn_inside(5); // returns 8

result1 = outside(3)(5); // returns 8

5.函數內的局部變量

arguments: 一個"類數組"的對象,包含了傳入當前函數的全部實參.

arguments.callee : 指向當前正在執行的函數.

arguments.caller  : 指向調用當前正在執行的函數的函數,請使用arguments.callee.caller代替

arguments.length: 傳入當前函數的實參個數.

arguments.callee.length:形參的個數

例子:檢測一個函數是否存在

你可使用typeof操做符來檢測一個函數是否存在.下例中,首先檢測window對象的noFunc屬性是不是一個函數,若是是,則調用它,不然,進行其餘的一些動做.

if ('function' == typeof window.noFunc) {
   // 調用 noFunc()
 } else {
   // 進行其餘動做
 }

注意在if語句中,使用的是對noFunc函數的引用,只有函數名,沒有後面的括號"()",這樣函數纔不會被調用.

相關文章
相關標籤/搜索