1. 程式人生 > >JavaScript 深入瞭解物件中的屬性

JavaScript 深入瞭解物件中的屬性

轉載:JavaScript 深入瞭解物件中的屬性

JavaScript 深入瞭解物件中的屬性

  本篇主要介紹JS中物件的屬性,包括:屬性的分類、訪問方式、檢測屬性、遍歷屬性以及屬性特性等內容。

目錄

1. 介紹:描述屬性的命名方式、查詢路徑以及分類

2. 屬性的訪問方式:介紹'.'訪問方式、'[ ]'中括號訪問方式

3. 刪除屬性:通過delete關鍵字刪除物件的某個屬性

4. 檢測屬性:介紹三種判斷某個屬性是否為物件的例項屬性:in、obj.hasOwnProperty、obj.propertyIsEnumerable

5. 

遍歷屬性:介紹三種遍歷物件的屬性:for / in 語句塊、Object.keys(obj) 、Object.getOwnPropertyNames(obj)

6. 屬性特性:在Escript5中,增加了屬性特性這一內容,可設定屬性是否可列舉、可修改等特性

 

1. 介紹

1.1 描述

  屬性,特指物件的成員,不單單為'屬性'(欄位),也包含了方法。

 

1.2 命名方式

屬性名稱可以包含英文字元、數字(不能開頭)、特殊符號(如:-、_、$等等)。

但一般使用純英文字元,在特殊情況下會新增-(橫槓:-webkit-、-moz- )以及 _(下劃線)。

若屬性名稱包含了-(橫槓),屬性訪問方式只能採用'[ ]'中括號訪問:

1

2

3

4

5

6

7

8

9

10

11

var o = {

    x: 1,

    y: 2,

    '-x': 3,

    '-showX'function () {

        alert(

this.x);

    }

}

// o.-x; // 此訪問方式會報異常

console.log(o['-x']); // => 3 :讀取帶-(橫槓)名稱的屬性,只能採用'[ ]'中括號訪問方式

o['-showX'](); // => 彈出1 :若方法名稱帶-(橫槓),執行方式很彆扭

 

1.3 屬性的查詢路徑

  假設讀取某個物件的屬性x,首先會在此物件的例項屬性中查詢。若沒有找到,將會在此物件的原型物件中查詢屬性x。若原型物件也沒有屬性x,將繼續查詢這個原型物件的原型(假設原型物件含有原型),一直到找到屬性x或者無原型為止。

 

1.4 屬性的分類

物件中的屬性,根據是否自身的可分為自有屬性和繼承屬性。

① 自有屬性:也可叫例項屬性;指物件自身的屬性。

② 繼承屬性:也可叫原型屬性;指物件從原型中繼承的屬性。

 

2. 屬性的訪問方式

可分為 ' . '點訪問方式和' [ ] '中括號方法方式 。

說明:若讀取一個不存在的屬性,將返回undefined。若設定一個物件不存在的屬性,將會向物件新增此屬性。

2.1 ' . '點訪問方式 

語法:obj.propertyName

說明:屬性名稱必須為一個標示符(靜態字串),不能為變數。

示例:

1

2

var o = {};

o.x = '1';

 

2.2 ' [ ] '中括號訪問方式

語法:obj[propertyName]

說明:屬性名稱可以為一個靜態字串,也可以為一個變數。若為變數,訪問的屬性為變量表示的值。

特點:與'.'訪問方式不同,'[ ]'中括號訪問方式靈活性很大:可動態訪問(變數指定屬性名)、可訪問包含某些特殊字元的屬性(如:屬性名稱帶'-')

示例:

1

2

3

4

var o = { x: 1, y: 2 };

console.log(o['x']); // => 1 :訪問x屬性

var a = 'y';

console.log(o[a]); // => 2 :訪問的是y屬性(變數a的值)

 

3. delete 刪除屬性

語法:delete obj.propertyName 或者 delete obj[propertyName]

說明:delete只能刪除物件的自有屬性,不能刪除繼承屬性。

示例:

1

2

3

4

5

6

7

8

9

10

var o = {};

o.x = '1';

console.log(o.x); // => 1

delete o.x;

console.log(o.x); // => undefined :訪問不存在的屬性,返回undefined

 

o.constructor.prototype.y = '2'// 在原型物件上新增一個y屬性

console.log(o.y); // => 2

delete o.y; // 刪除繼承屬性y

console.log(o.y); // => 2 :還是可以訪問繼承屬性y

 

4. 檢測屬性

  檢測物件是否包含某個屬性。

4.1 in 運算子

說明:判斷物件是否包含某個屬性,會從物件的例項屬性、繼承屬性裡進行檢測。

語法:propertyName in obj

返回值:

{bool} 判斷物件的例項屬性或繼承是否包含此屬性。

true:物件的例項屬性或繼承屬性包含此屬性;

false:物件的例項屬性或繼承屬性不包含此屬性。 

示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

function People(name) {

    this.name = name;

}

function Student(age) {

    this.age = age;

}

Student.prototype = new People(); // 設定Student的原型為People物件

 

var s = new Student(22);

 

console.log('age' in s); // => true :age為例項屬性

console.log('name' in s); // => true :name為繼承屬性

console.log('address' in s); // => false :address不存在此物件呢,返回false

 

4.2 obj.hasOwnProperty(propertyName) 

說明:判斷物件是否擁有一個指定名稱的例項屬性,不會檢查繼承屬性。

引數:

①propertyName {string} :屬性名稱。

語法:obj.hasOwnProperty(propertyName) 

返回值: 

{bool} 判斷物件是否擁有一個指定名稱的例項屬性;此方法不會檢查物件原型鏈中的屬性。

true :屬性為物件的例項屬性,非繼承。

false :屬性不為物件的例項屬性。

示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

var Student = function (name) {

    this.name = name;

};

// 給Student的原型新增一個sayHello方法

Student.prototype.sayHello = function () {

    alert('Hello,' this.name);

}

// 給Student的原型新增一個age屬性

Student.prototype.age = '';

  

var st = new Student('張三'); // 初始化物件st

console.log(st.hasOwnProperty('name')); // => true :呼叫建構函式時,通過this.name附加到例項物件上

console.log(st.hasOwnProperty('sayHello')); // => false :sayHello方法為原型上的成員

console.log(st.hasOwnProperty('age')); // => false :age屬性為原型上的成員

 

4.3 obj.propertyIsEnumerable(propertyName)

說明:判斷指定名稱的屬性是否為例項屬性並且是可列舉的(可用for/in迴圈列舉)

引數:

①propertyName {string} :屬性名稱。

語法:obj.propertyIsEnumerable(propertyName)

返回值:

{bool} 判斷屬性是否為例項屬性並且是可列舉的(可用for/in迴圈列舉),不考慮原型鏈中的成員。

true :屬性為物件的例項屬性並且是可列舉的。

false :屬性不為物件的例項屬性或不可列舉的。

示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

var o = Object.create({}, {

    name: {

        value: 'tom',

        enumerable: true // 可列舉

    },

    age: {

        value: 22,

        enumerable: false // 不可列舉

    }

});

 

console.log(o.propertyIsEnumerable('name')); // => true :name為例項屬性並且可列舉

console.log(o.propertyIsEnumerable('age')); // => false :age為例項屬性但不可列舉

 

console.log(o.hasOwnProperty('age')); // => true :hasOwnProperty()方法只判斷屬性是否為例項屬性

 

4.4 總結

檢測方式 語法 檢測屬性的範圍   返回值
in 運算子 propertyName in obj 例項屬性、繼承屬性 {bool} true:符合條件;fasle:不符合
obj.hasOwnProperty(propertyName)  obj.hasOwnProperty(propertyName)  例項屬性 {bool} true:符合條件;fasle:不符合
obj.propertyIsEnumerable(propertyName) obj.propertyIsEnumerable(propertyName) 可列舉的例項屬性 {bool} true:符合條件;fasle:不符合

 

5. 遍歷屬性

  即遍歷物件的例項屬性、繼承屬性。

5.1 for / in 語句塊

說明:遍歷物件可列舉的例項屬性和繼承屬性

語法:

for (p in obj) { 
  // p表示遍歷的屬性名稱
}

示例:

1

2

3

4

5

6

7

var po = { px: 1, py: 2 };

var o = { x: 1, y: 2 };

o.__proto__ = po; // 設定o的原型為po

for (property in o) {

    console.log(property); // => 輸出屬性的名稱:x、y、px、py

    console.log(o[property]); // => 採用中括號訪問方式,輸出屬性的值

}

 

5.2 Object.keys(obj) 

說明:返回一個數組,包含物件可列舉的例項屬性名稱

引數:

①obj {object} :例項物件

返回值:

{Array} 返回一個數組,包含物件可列舉的例項屬性名稱

示例:

1

2

3

4

5

6

7

var po = { px: 1, py: 2 };

var o = { x: 1, y: 2 };

o.__proto__ = po; // 設定o的原型為po

var propertyArray = Object.keys(o); // => 返回一個包含了可列舉的例項屬性名稱的陣列

for (var i = 0, len = propertyArray.length; i < len; i++) {

    console.log(propertyArray[i]); // => 輸出例項屬性名稱:x、y

}

 

5.3 Object.getOwnPropertyNames(obj) 

說明:返回一個數組,包含物件的所有例項屬性名稱。包括可列舉和不可列舉的

引數:

①obj {object} :例項物件

返回值:

{Array} 返回一個數組,包含物件所有例項屬性名稱

與Object.keys()的差別:Object.keys()只返回可列舉的例項屬性,Object.getOwnPropertyNames()返回所有例項屬性

示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

var po = { px: 1, py: 2 };

var o = { x: 1, y: 2 };

// 設定物件o的屬性特性:屬性x為可列舉,屬性y為不可列舉

Object.defineProperties(o, {

    x: {

        enumerable: true

    },

    y: {

        enumerable: false

    }

});

o.__proto__ = po; // 設定o的原型為po

 

// 1.Object.keys():獲取一個可列舉的例項屬性名稱的陣列

var propertyArray = Object.keys(o);

for (var i = 0, len = propertyArray.length; i < len; i++) {

    console.log(propertyArray[i]); // => 輸出例項屬性名稱:x

}

 

// 2.Object.getOwnPropertyNames():獲取一個包含的例項屬性名稱的陣列,不管例項屬性是否可列舉

propertyArray = Object.getOwnPropertyNames(o);

for (var i = 0, len = propertyArray.length; i < len; i++) {

    console.log(propertyArray[i]); // => 輸出例項屬性名稱:x、y

}

 

5.4 總結

檢測方式 語法 遍歷屬性的範圍   返回值
for / in 語句塊 for (p in obj) { 
  // p表示遍歷的屬性名稱
}
可列舉的例項屬性和繼承屬性 {String} 屬性的名稱
Object.keys(obj) Object.keys(obj) 可列舉的例項屬性 {Array} 返回一個數組,包含物件可列舉的例項屬性名稱
Object.getOwnPropertyNames(obj) Object.getOwnPropertyNames(obj) 包含物件的所有例項屬性名稱。包括可列舉和不可列舉的 {Array} 返回一個數組,包含物件所有例項屬性名稱

 

6.屬性描述符

分為資料屬性和訪問器屬性;

兩者可相互轉換,若轉換後未設定enumerable和configurable特性(兩類屬性描述符都包含這2個特性),將預設採用轉換前的值。

6.1 資料屬性

說明:包含屬性的操作特性;如:設定值、是否可列舉等等

特性名稱 描述 預設值
value 設定屬性的值 undefined
writable 是否可修改屬性的值;true:可修改屬性的值;false:不可修改屬性的值 false  
enumerable 是否可列舉屬性;true:可列舉,可通過for/in語句列舉屬性;false:不可列舉 false
configurable 是否可修改屬性的特性;true:可修改屬性的特性(如把writable從false改為true);false:不可修改屬性的特性 false

 

 

 

 

預設值:

1)在使用Object.defineProperty、Object.defineProperties 或 Object.create 函式的情況下新增資料屬性,writable、enumerable和configurable預設值為false。

2)使用物件直接量建立的屬性,writable、enumerable和configurable特性預設為true。

示例:

1

2

3

4

5

6

7

8

9

10

11

// 1)物件直接量;屬性特性預設為true

var o1 = {

    name: 'tom'

};

console.log(Object.getOwnPropertyDescriptor(o1, 'name')); // => Object {value: "tom", writable: true, enumerable: true, configurable: true}

 

// 2)通過Object.create建立,屬性特性預設為false

var o2 = Object.create(null, {

    name: {value:'tom'}

});

console.log(Object.getOwnPropertyDescriptor(o2, 'name')); // => Object {value: "tom", writable: false, enumerable: false, configurable: false}

 

6.2 訪問器屬性

說明:設定屬性的訪問方式;set、get特性等

特性名稱 描述 預設值
get 屬性的返回值函式 undefined
set 屬性的設定值函式;含有一個賦值引數 undefined
enumerable 是否可列舉屬性;true:可列舉,可通過for/in語句列舉屬性;false:不可列舉 false
configurable 是否可修改屬性的特性;true:可修改屬性的特性(如把writable從false改為true);false:不可修改屬性的特性 false

 

 

 

 

示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

var obj = {};

 

// 新增一個屬性,並設定為訪問器屬性

Object.defineProperty(obj, "name", {

    get: function () {

        return this._name; // get和set裡的變數不要使用屬性,如:屬性為name,get和set用的是_name

    },

    set: function (x) {

        if (isNaN(x)) {

            this._name = x;

        else {

            this._name = 'name不能為純數字';

        }

    },

    enumerable: true,

    configurable: true

});

 

console.log(Object.getOwnPropertyDescriptor(obj, 'name')); // => Object {get: function, set: function, enumerable: true, configurable: true}

obj.name = '12';

console.log(obj.name); // => name不能為純數字