和所有的值類型一樣,對象有屬性。事實上,你可以將對象當作一組屬性的集合,每個屬性都是一對(鍵和值)。鍵是字符串,值可以是任意JavaScript值。到目前為止,我們僅僅見過鍵是標識符的屬性,因為點操作符處理的鍵必須為標識符。在這節(jié),你講見到另一種訪問屬性的方法,能將任意字符串作為鍵。
在JavaScript中,你可以直接創(chuàng)建對象,通過對象字面量:
var jane = {
name: 'Jane',
describe: function () {
'use strict';
return 'Person named '+this.name;
}
};
上面的對象有兩個屬性:name
和 describe
。你能讀(“get
”)和 寫(“set
”)屬性:
> jane.name // get
'Jane'
> jane.name = 'John'; // set
> jane.newProperty = 'abc'; // 自動創(chuàng)建
屬性是函數如 describe 可以被當作方法調用。當調用他們時可以在它們內部通過this引用對象。
> jane.describe() // 調用方法
'Person named John'
> jane.name = 'Jane';
> jane.describe()
'Person named Jane'
in 操作符用來檢測一個屬性是否存在:
> 'newProperty' in jane
true
> 'foo' in jane
false
若讀取一個不存在的屬性,將會得到undefined值。因此上面的兩個檢查也可以像下面這樣:
> jane.newProperty !== undefined
true
> jane.foo !== undefined
false
delete操作符用來刪除一個屬性:
> delete jane.newProperty
true
> 'newProperty' in jane
false
屬性的鍵可以是任意字符串。到目前為止,我們看到的對象字面量中的和點操作符后的屬性關鍵字。按這種方法你只能使用標識符。如果你想用其他任意字符串作為鍵名,你必須在對象字面量里加上引號,并使用方括號獲取和設置屬性。
> var obj = { 'not an identifier': 123 };
> obj['not an identifier']
123
> obj['not an identifier'] = 456;
方括號允許你動態(tài)計算屬性關鍵字:
> var x = 'name';
> jane[x]
'Jane'
> jane['na'+'me']
'Jane'
如果你引用一個方法,它將失去和對象的連接。就其本身而言,函數不是方法,其中的this值為undefined(嚴格模式下)。
> var func = jane.describe;
> func()
TypeError: Cannot read property 'name' of undefined
解決辦法是使用函數內置的bind()方法。它創(chuàng)建一個新函數,其this值固定為給定的值。
> var func2 = jane.describe.bind(jane);
> func2()
'Person named Jane'
每個函數都有一個特殊變量this。如果你在方法內部嵌入函數是很不方便的,因為你不能從函數中訪問方法的this。下面是一個例子,我們調用forEach循環(huán)一個數組:
var jane = {
name: 'Jane',
friends: [ 'Tarzan', 'Cheeta' ],
logHiToFriends: function () {
'use strict';
this.friends.forEach(function (friend) {
// 這里的“this”是undefined
console.log(this.name+' says hi to '+friend);
});
}
}
調用 logHiToFriends 會產生錯誤:
> jane.logHiToFriends()
TypeError: Cannot read property 'name' of undefined
有兩種方法修復這問題。
logHiToFriends: function () {
'use strict';
var that = this;
this.friends.forEach(function (friend) {
console.log(that.name+' says hi to '+friend);
});
}
logHiToFriends: function () {
'use strict';
this.friends.forEach(function (friend) {
console.log(this.name+' says hi to '+friend);
}, this);
}
在JavaScript中函數表達式經常被用作函數參數。時刻小心函數表達式中的this。
目前為止,你可能認為JavaScript的對象僅是鍵值的映射,通過JavaScript對象字面量可以得出這個觀點,看起來很像其他語言中的地圖/字典(map/dictionary)。然而,JavaScript對象也支持真正意義上的面向對象特性:繼承(inheritance)。本節(jié)不會完全講解JavaScript中繼承的工作原理,但會給你以此為開始的簡單模式。如果你想得到更多知識,請查閱這篇文章“JavaScript inheritance by example”。 除了作為“真正”的函數和方法,函數還在JavaScript中扮演第三種角色:如果通過new操作符調用,他們會變?yōu)闃嬙旌瘮担瑢ο蟮墓S。構造函數是對其他語言中的類的粗略模擬。約定俗成,構造函數的第一個字母大寫。例如:
// 設置實例數據
function Point(x, y) {
this.x = x;
this.y = y;
}
// 方法
Point.prototype.dist = function () {
return Math.sqrt(this.x*this.x + this.y*this.y);
};
我們看到構造函數分為兩部分:首先,Point函數設置實例數據。其次,Point.prototype屬性包含對象的方法。前者的數據是每個實例私有的,后面的數據是所有實例共享的。 我們通過new操作符調用Point:
> var p = new Point(3, 5);
> p.x
3
> p.dist()
5.830951894845301
p是Point的一個實例:
> p instanceof Point
true
> typeof p
'object'
更多建議: