面向對象編程中,函數、方法、類的構造函數是三種不同的概念。 JS中,它們只是單個構造對象的三種不同的使用模式。 三種不同的使用模式 函數調用 函數的表現與行為一致,調用hello函數並將給定的實參綁定到username形參。 方法調用 js中的方法,是指對象的屬性恰好是函數而已。 這裡方法hello ...
面向對象編程中,函數、方法、類的構造函數是三種不同的概念。
JS中,它們只是單個構造對象的三種不同的使用模式。
三種不同的使用模式
函數調用
function hello(username){ return 'hello,'+username; } hello('world');//"hello,world"
函數的表現與行為一致,調用hello函數並將給定的實參綁定到username形參。
方法調用
js中的方法,是指對象的屬性恰好是函數而已。
var obj={ hello:function(){ return 'hello,'+this.username; }, username:'world' }; obj.hello();//"hello,world"
這裡方法hello是通過this變數來訪問obj對象的屬性的。
this的指向是如何完成的呢?從上面的這個例子中,可能傾向於this變數被綁定到obj對象了,由於hello方法定義在obj對象中。
下麵看一個例子
var obj2={ hello:obj.hello, username:'han mei mei.' } obj2.hello();//"hello,han mei mei."
事實是,在方法調用的時候才由表達式來確定this變數的綁定情況。
綁定到this變數的對象被稱為調用接收者(receiver)。
表達式obj.hello()在obj對象中查找名為hello的屬性,並將obj對象作為接收者,然後調用該屬性。
表達式obj2.hello()在obj2對象中查找名為hello的屬性,恰巧是obj.hello函數,但是接收者是obj2對象。
通常,通過某個對象調用方法將查找該方法並將對象作為該方法的接收者,也即this變數的對象。
按照上面的文字,畫了一張圖:
由於方法其實就是通過特定對象調用的函數,不知為何一個普通的函數不能引用this變數。
function hello(){ return 'hello,'+this.username; } var obj1={ hello:hello, username:'obj1' } var obj2={ hello:hello, username:'obj2' } obj1.hello();//"hello,obj1" obj2.hello();//"hello,obj2"
上面這段代碼的結構圖應該是這樣的。
如果直接調用
hello();//"hello,undefined"
一個非方法(nonmethod)的函數調用會將全局對象作為接收者,這時全局對象沒有名為username的屬性所以產生了undefined。
如果方法中需要使用this變數,則將方法作為函數調用則毫無用處,因為沒有理由希望全局對象匹配調用對象中的方法。事實上,將this變數綁定到全局對象是有問題的,ES5嚴格模式將this變數的預設綁定值改為undefined
function hello(){ 'use strict'; return 'hello,'+this.username; } hello();
結果如圖
這樣做可以有助於更快地捕獲偶然地將方法錯誤地作為純函數使用的情況。
通過構造函數使用
就像方法和純函數一樣,構造函數也是由function運算符定義的。function User(name,pwd){ this.name=name; this.pwd=pwd; } var u=new User('li lei','asdfxov2-3409'); u.name;//"li lei"
與函數調用和方法調用不同的是,構造函數調用將一個全新的對象作為this變數的值,並隱式返回這個新對象作為調用結果。構造函數的主要職責是初始化該新對象。
提示
-
方法調用將被查找方法屬性的對象作為調用接收者(this綁定)
-
函數調用將全局對象(處於嚴格模式下則為undefined)作為其接收者。很少使用函數調用語法來調用方法。
-
構造函數需要通過new運算符調用,並產生一個新的對象作為其接收者