函數也是對象,使對象不一樣於其它對象的決定性特色是函數存在一個被稱爲 [[Call]]
的內部屬性。正則表達式
相似於[[Call]]
這種內部屬性沒法經過代碼訪問,他只是定義了代碼執行時的行爲。數組
ECMAScript爲JavaScript的對象定義了多種內部屬性,這些內部屬性都用雙重中括號來標註。瀏覽器
[[Call]] 屬性是函數獨有的,代表該對象能夠被執行。因爲僅函數擁有該屬性,ECMAScript 定義 typeof 操做符對任何具備 [[Call]] 屬性的對象返回 "function"。app
過去因某些瀏覽器曾在正則表達式中包含 [[Call]]
屬性,致使正則表達式被錯誤鑑別爲函數。函數
函數有兩種字面形式:函數聲明跟函數表達式。ui
二者的一個重要區別是:函數聲明會被提高至上下文(要麼是該函數被聲明時所在的函數範圍,要麼是全局範圍)的頂部。this
函數是JavaScript的一大重點。spa
基本上只要是可使用其餘引用值的地方,你就可使用函數。也就是說,你能夠像使用對象同樣使用函數(由於函數原本就是對象)。指針
JavaScript函數另外一個獨特之處在於你能夠給函數傳遞任意數量的參數卻不形成錯誤。調試
這是由於函數參數保存在類數組對象 arguments
中。
如同一個普通JavaScript數組,arguments能夠自由增加來包含任意個數的值,這些值可經過數字索引來引用。
雖然arguments相似數組,可是Array.isArray(arguments)
返回 false
最後須要注意兩點:
length
屬性代表其指望的參數個數。大多數面嚮對象語言支持函數重載,它能讓一個函數具備多個簽名。函數簽名由函數的名字、參數的個數及其類型組成。
而 JavaScript 能夠接收任意數量的參數且參數類型徹底沒有限制。這說明 JavaScript 函數根本就沒有簽名,所以也不存在重載。
function sayMessage(message){
console.log(message);
}
function sayMessage(){
console.log("Default Message");
}
sayMessage("Hello!"); // 輸出"Default Message";
複製代碼
在 JavaScript 裏,當你試圖定義多個同名的函數時,只有最後的定義有效,以前的函數聲明被徹底刪除(函數也是對象,變量只是存指針)。
var sayMessage = new Function("message", "console.log(message)");
var sayMessage = new Function("console.log(\"Default Message\");");
sayMessage("Hello!");
複製代碼
固然,你能夠根據傳入參數的數量來模仿重載。
對象的值是函數,則該屬性被稱爲方法。
JavaScript 全部的函數做用域內都有一個 this
對象表明調用該函數的對象。
在全局做用域中,this
表明全局對象(瀏覽器裏的 window)。
當一個函數做爲對象的方法調用時,默認 this
的值等於該對象。
this在函數調用時才被設置。
function sayNameForAll(){
console.log(this.name);
}
var person1 = {
name: "Nicholas",
sayName: sayNameForAll
}
var name = "Jack";
person1.sayName(); // 輸出 "Nicholas"
sayNameforAll(); // 輸出 "Jack"
複製代碼
有3種函數方法運行你改變 this
值。
使用 call
或 apply
方法,就不須要將函數加入每一個對象——你顯示地指定了 this
的值而不是讓 JavaScript 引擎自動指定。
call
與 apply
的不一樣地方是,call
須要把全部參數一個個列出來,而 apply
的參數須要一個數組或者相似數組的對象(如 arguments
對象)。
bind
是 ECMAScript 5 新增的,它會建立一個新函數返回。其參數與 call
相似,並且其全部參數表明須要被永久設置在新函數中的命名參數(綁定了的參數(沒綁定的參數依然能夠傳入),就算調用時再傳入其它參數,也不會影響這些綁定的參數)。
function sayNameForAll(label){
console.log(label + ":" + this.name);
}
var person = {
name: "Nicholas"
}
var sayNameForPerson = sayNameForAll.bind(person);
sayNameForPerson("Person"); // 輸出"Person:Nicholas"
var sayName = sayNameForAll.bind(person, "Jc");
sayName("change"); // 輸出"Jc:Nicholas" 由於綁定的形參,會忽略調用時再傳入參數
複製代碼
[[Call]]
,包含了該函數的執行指令。Function
構造函數。但這會使你的代碼難以理解和調試,除非函數的真實形式要直到運行時才能肯定的時候纔會利用它。