對象的屬性指對象的成員。講解屬性之前介紹一下Object對象,Object對象是所有JavaScript對象的超類(基類)。本文将會使用到Object對象的一些方法。
一、對象的屬性分類
我們先通過講屬性的一些分類,來明确一些概念
1. 屬性可分為自有屬性和繼承屬性
function Person(name,age){
this.trueName=name;
this.age=age;
}
Person.prototype.species='human';
Person.prototype.run=function () {
console.log(this.trueName+' is running');
}
var p1=new Person('Lilyan',18);
console.log(p1);
對象中的屬性,根據是否子屬于自身的可分為自有屬性和繼承屬性。
① 自有屬性(own property) :也可叫執行個體屬性;指對象自身的屬性,上述的p1對象中的姓名、年齡等都是自有屬性。
② 繼承屬性(inherited property):也可叫原型屬性;指對象從原型中繼承的屬性。
我們通過在控制台輸出p1來看一下:
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL5gTM4UDOxMTM4EDMxkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
2. 可分為屬性和方法
上面的代碼中run的屬性是一個函數,當屬性值是函數的時候,該屬性被稱為方法,可以說方法就是一種特殊的屬性。
3. 可分為公有屬性和私有屬性
關于公有屬性和私有屬性,裡面涉及到了很多名詞,如私有屬性、私有方法、公有屬性、公有方法、特權方法,中間存在一些概念模糊的地方,,我的說法不一定是對的,但我個人就這樣記憶了。
對于構造函數來說,構造函數的執行個體能夠通路的屬性和方法就是公有屬性公有方法,定義在函數内部且沒有通過this聲明的屬性和方法就是私有的屬性和方法。
function Person(name,age) {
this.name=name; //公有屬性
var _age=age; //私有屬性,約定私有屬性前加_
//私有方法
var checkAge=function(){
return (_age<18)?_age:'保密';
};
//公有方法-特權方法
this.introduce=function () {
console.log(this.name+'的年齡:'+checkAge(_age));
};
}
//公有方法
Person.prototype.species='人類';
Person.prototype.say=function () {
console.log(this.name+'的年齡:'+this._age);
};
var p=new Person('張三',19);
console.log(p);
p.introduce();
p.say();
簡單的說,列印執行個體時,能看到的就是公有屬性公有方法,定義了又看不到的是私有屬性/方法。
私有屬性和私有方法隻能在函數内部使用,所謂特權方法其實也是一種公有方法,它能夠在構造函數外,被其執行個體調用,并且能夠通路構造函數内的私有屬性和方法(如果你了解執行上下文的知識,就很好了解)。
上面的例子中,公有方法say沒有通路到私有屬性,特權方法introduce通路到了私有屬性和私有方法。
4.靜态屬性和靜态方法
靜态屬性和靜态方法一般指不需要構造函數的執行個體化,直接将構造函數作為對象,可以通路的屬性和方法。
function Person(name) {
this.name=name; //公有屬性
}
Person.species='人類';
Person.say=function () {
console.log(this.name+'的年齡:'+this._age);
};
console.log(new Person());
console.dir(Person);
二、屬性的通路方式
- 可用為 ’ . '點通路方式:obj.propertyName,屬性名稱必須為一個字元串,不能為變量。
-
可用’ [ ] '中括号方法方式 ,obj[propertyName],此方法通路屬性更加的靈活,可以使用變量來通路屬性
說明:通路一個不存在的屬性,将傳回undefined。給對象不存在的屬性指派,将會向該對象添加此屬性。
var p1={ "true name":"Lily", } var tn="true name"; console.log(p1[tn]); //Lily console.log(p1.gender); //undefined p1.gender='female'; //新增屬性 console.log(p1.gender); //female p1.gender='male'; //修改屬性值 console.log(p1.gender); //male
三、新增/修改屬性
上例中,通過給一個不存在的屬性指派的方法實際上實作了新增屬性;
給一個已經存在的屬性重新指派,就實作了修改屬性值。
四、删除屬性 delete
說明:通過delete方法可以删除對象的自有屬性。
function Person(name,age){
this.trueName=name;
this.age=age;
}
Person.prototype.species='human';
Person.prototype.run=function () {
console.log(this.trueName+' is running');
}
var p1=new Person('Lilyan',18);
delete p1.age;
delete p1['species']; //species是p1的繼承屬性,靜默失敗
五、檢測對象是否包含某個屬性
-
使用in運算符判斷對象是否包含某個屬性(會檢查自有屬性和繼承屬性);
文法:屬性 in 對象
傳回值:如果存在,傳回值為:true;不存在,則為:false。
console.log('age' in p1); //true,找到自由屬性age console.log('constructor' in p1); /true,在原型屬性中找到constructor
-
判斷對象是否擁有一個指定名稱的自有屬性;
文法:對象.hasOwnProperty(屬性)
傳回值:如果存在,傳回值為:true;不存在,則為:false。
console.log(p1.hasOwnProperty('age')); //true console.log(p1.hasOwnProperty('constructor')); //false,不會檢查原型
-
判斷指定名稱的屬性是否為可枚舉的自有屬性
文法:對象.propertyIsEnumerable(屬性)
前面的例子中,我們為p1增加了一個不可枚舉的屬性x
console.log(p1.propertyIsEnumerable('age')); //true console.log(p1.propertyIsEnumerable('x')); //false
六、屬性的周遊
這裡用一個構造函數的例子,來講解一下屬性的周遊
function Person(name,age){
this.trueName=name;
this.age=age;
}
Person.prototype.species='human';
Person.prototype.run=function () {
console.log(this.trueName+' is running');
}
var p1=new Person('Lilyan',18);
Object.defineProperty(p1,'x',{
value:'x',
enumerable:false
});
Object.defineProperty(Person.prototype,'y',{
value:'y',
enumerable:false
});
console.log(p1);
- for / in 語句 周遊對象可枚舉的自有屬性和繼承屬性
- Object對象的4個靜态屬性,Object.keys()、Object.values() 、Object.entries() 、Object.getOwnPropertyNames()可以實作對象的周遊
- Object.keys() 傳回一個給定對象==可枚舉的自有屬性(鍵)==組成的數組
- Object.values() 傳回一個給定對象可枚舉的自有屬性值組成的數組(ES6新增)
- Object.entries() 傳回一個給定對象可枚舉的自有屬性鍵值對組成的數組(ES6新增)
- Object.getOwnPropertyNames() 傳回一個給定對象對象不包括Symbol 屬性全部的自有屬性組成的數組。
上面的代碼中,對象p1既有自有屬性又有繼承屬性,其中還有不可枚舉的屬性x和y,下面就來周遊它
var forResult="for/in周遊結果(傳回可枚舉的自有屬性和繼承屬性)";
for(var key in p1){
forResult+="\n"+key+":"+p1[key];
}
console.log(forResult);
console.log("Object.getOwnPropertyNames()方法的周遊結果,傳回全部的自有屬性組成的數組(不包括Symbol屬性):");
console.log(Object.getOwnPropertyNames(p1));
console.log("Object.keys()方法的周遊結果(傳回可枚舉的自有屬性名組成的數組):");
console.log(Object.keys(p1));
console.log("Object.values()方法的周遊結果(傳回可枚舉的自有屬性值組成的數組):");
console.log(Object.values(p1));
console.log("Object.entries()方法的周遊結果(傳回可枚舉的自有屬性鍵值對組成的數組):");
console.log(Object.entries(p1));
七、對象字面量與JSON
對象字面量與JSON 字元串形式上看起來很像,JSON 是一種獨立的語言,JSON字元串現在常用于進行前後端的資料互動,JavaScript提供了一個内置對象JSON,可以實作js對象與json字元串的互轉。
JSON 文法規則
- 資料為 鍵/值 對。
- 資料由逗号分隔。
- 大括号儲存對象
- 方括号儲存數組
JSON.stringify傳回一個字元串,JS對象的可枚舉的自有屬性成為json字元串的鍵,屬性值成為鍵值;
方法名和方法會被過濾掉。
這個對象p1,轉成JSON字元串
PS:JavaScript的JSON對象
八 、屬性描述符對象
在前面我們多次提到可枚舉屬性,不可枚舉屬性,其實能更加微觀的角度去看屬性,還可以有可寫的屬性,不可寫的屬性;可配置的屬性不可配置的屬性等等。
在ES5 中定義了一個名叫“屬性描述符”的對象,用于描述對象屬性的各種特征,屬性的特征分為兩種類型,資料屬性和通路器屬性。
也就是說我們給對象配置一個屬性的同時,還可以配置這個屬性的特征。
使用Object.getOwnPropertyDescriptor() 和Object.getOwnPropertyDescriptors() 可以傳回指定對象屬性的描述
- 将資料屬性了解為某屬性作為資料表現出的特征,如屬性值是多少、能不能被修改等等;
- 通路器屬性指某屬性被讀取或修改時表現出的特征。
- 一個描述符不能同時有(value或writable)和(get或set)關鍵字(将會産生一個異常),如果一個描述符不具有value,writable,get 和 set 任意一個關鍵字,那麼它将被認為是一個資料描述符。
- 資料屬性包含的4個屬性:
資料屬性 預設值 說明 configrable true 描述屬性是否配置,以及可否删除 enumerable true 可枚舉性描述屬性是否會出現在for in 或者 Object.keys()的周遊中 writable true 可寫性,表示能否修改屬性的值。 value undefined 資料屬性,表示屬性的值 - 通路器屬性包含的4個屬性:
通路器屬性 預設值 說明 configrable false 描述屬性是否配置,以及可否删除 enumerable false 描述屬性是否會出現在for in 或者 Object.keys()的周遊中 get undefined 當通路該屬性時,該方法會被執行,沒有參數傳入,會傳入this對象 set undefined 該方法将接受唯一參數,并将該參數的新值配置設定給該屬性
使用for/in循環可以周遊對象的可枚舉屬性,下面我用Object對象的defineProperty方法為上面的p1對象增加一個不可枚舉屬性x
Object.defineProperty(p1,'x',{
value:'x',
enumerable:false
});
console.log(p1); //Person {trueName: "Lilyan", age: 18, x: "x"}
console.log(Object.getOwnPropertyDescriptor(p1, 'x')); //{value: "x", writable: false, enumerable: false, configurable: false}
for(var key in p1) {
console.log(key); //不會列印出x,x屬性不可枚舉
}
這裡用到了Object對象的兩個方法:
- Object.defineProperty(obj, propertyName, propertyDescriptor) :添加/修改對象指定屬性的特性
-
Object.getOwnPropertyDescriptor(object, propertyName) :傳回對象屬性的描述
可以跳轉到 JavaScript原生對象-Object對象詳解