對象
是無序屬性的集合,其屬性可以包含基本值,對象,或者函數。可以將對象想象成散列表:鍵值對,其中值可以是數據或者函數。ECMAScript中的對象其實就是一組數據(屬性)和功能(方法)的集合。
題外話:睡了,明天再搞,中秋節快樂鴨!!!!!
對象是一個包含相關數據和方法的集合(通常由一些變量和函數組成,我們稱之為對象裏面的屬性和方法)
比如在現實生活中,每一個人都是一個對象。對象有它的屬性,如身高和體重,方法有走路或跑步等;所有人都有這些屬性,但是每個人的屬性都不盡相同,每個人都擁有這些方法,但是方法被執行的時間都不盡相同。
- 而在 JavaScript中,幾乎所有的事物都是對象。
以下代碼為變量 person 設置值為 "張三" :
var person = "張三";
- 對象也是一個變量,但對象可以包含多個值(多個變量),每個值以 key:value鍵值對的方式 呈現。
var person = {
//注意屬性和屬性之間用逗號隔開
name:"張三",
height:1.71,
gender: 'male'
};
對象的創建
對象的初始化有兩種方式,構造函數模式和字面量模式
- 字面量模式
對象使用"{}"作為對象的邊界,對象是由多個屬性組成,屬性與屬性之間通過","隔開,屬性名與屬性值通過":"隔開;屬性名一般不添加引號(當屬性名中出現特殊字符的時候需要添加引號),屬性值如果是字符串的一定添加引號
例如:
var obj = {
name:"terry",
age:12,
sayName:function(){
console.log("my name is ",this.name);
}
}
- 構造函數模式
使用Object或者使用自定義構造函數來初始化對象
var obj = new Object();
obj.name = "terry";
obj.age = 12;
//sayName是obj對象的一個方法,可以看作是obj的一個屬性
obj.sayName = function(){
console.log("my name is",this.name);
}
//等價於 <==>
var obj={};
obj.name="terry";
obj.age=12;
對象的訪問
- 屬性訪問
屬性訪問方式也有兩種,點訪問、中括號訪問
點後面直接跟的是對象的屬性,如果屬性存在可以訪問到,如果屬性不存在,得到undefined。 中括號中放的是變量,中括號可以將該變量進行解析。
例如
obj.name //'terry'
obj['name'] //'terry'
name = "age"
obj['name'] //12
- 方法的訪問
方法的訪問主要是為了執行該對象中的方法,需要按照函數調用的方式去使用
例如
var obj = {
name: 'zhang',
age: 13,
sayName: function () {
console.log(this.name); //zhang
}
}
obj.sayName();//zhang //obj方法的使用
obj.sayName; //訪問的是obj對象的方法
console.log(obj.sayName); //[Function: sayName]
- 遍歷對象中的屬性
普通版的for循環可以遍歷數組,但無法遍歷對象
增強版的for循環: for..in用於遍歷數組或者對象的屬性
(題外話:之前同學區面試京東的前端實習,面試官有問到這個。。。。。)
for(自定義變量名 in 數組/對象){
執行代碼
}
for(var key in obj){
var value=obj[key];
}
用法示例:
// 增強版的for循環:
//循環對象屬性:
var obj = {
name:"autumn",
age:22,
salary:10000
};
// for..in用於遍歷數組或者對象的屬性
for (var key in obj) {
console.log(key + '-------' + obj[key]);
//name-------autumn
// age-------22
// salary-------10000
}
新增刪除對象中的屬性
只能刪除對象的自有屬性
var obj = {
name: 'zhang',
age: 13,
sayName: function () {
console.log(this.name); //zhang
}
}
// 刪除對象中的屬性 只能刪除對象的自有屬性
delete obj.name;
console.log(obj); //{ age: 13, sayName: [Function: sayName] }
delete obj.sayName //從obj對象中刪除sayName屬性
console.log(obj); //{ age: 13 }
新增屬性
obj.newpropname=”value”
var obj = {
name: 'zhang',
age: 13,
sayName: function () {
console.log(this.name); //zhang
}
}
// 新增對象中的屬性
obj.gender = 'male'
console.log(obj);
// {
// name: 'zhang',
// age: 13,
// sayName: [Function: sayName],
// gender: 'male'
// }
Object顯式類型轉換(強制類型轉換)
- ECMAScript中可用的3種強制類型轉換如下:
Boolean(value):把給定的值轉換成Boolean型
String(value):把給定的值轉換成字符串
Number(value):把給定的值轉換成數字(可以是整數或浮點數)
* Object類型到Boolean類型
| 數據類型 | 轉換為true的值 | 轉換為false的值 |
|---|---|---|
| Boolean | true | false |
| String | 任何非空的字符串 | ""(空字符串) |
| Number | 任何非零數字(包括無窮大) | 0和NaN(非數值) |
| Object | 任何對象 | null |
| Undefined | 無 | undefined |
// 除了空引用(null)會轉換為false,其他都被轉換為true
var obj = {
name: "briup",
age: 13
};
// 使用Boolean包裝器進行轉換
console.log(Boolean(obj)); //true
console.log(Boolean(!obj)); //false
console.log(Boolean(null)); //false
console.log(Boolean(undefined)); //false
console.log(Boolean(111)); //true
console.log(Boolean('')); //false
console.log(Boolean(0)); //false
console.log(Boolean(NaN)); //false
console.log(Boolean()); //false
- Object類型轉String類型
轉換規則:
顯示轉換與隱式轉換規則類似,當要將對象轉換為String時,類似隱式轉換中的PreferredType為String
1.先調用對象的toString方法
2.判斷該方法的返回值是否為基礎數據類型(Number,String,Boolean,Undefined,Null)
3.若返回值為基礎數據類型,則轉換規則按照相應數據類型的轉換規則對其進行轉換
4.若返回值不為基礎數據類型,則在該返回值的基礎上繼續調用valueOf方法
5.判斷valueOf的返回值是否為基礎數據類型
6.判斷是否為基礎數據類型,若是基礎數據類型則進行操作3
7.若仍舊不為基礎數據類型則報錯
//直接用toString()方法
var obj = {
name: 'zhangsan',
age: 12,
// 可以重寫toString方法,進行我們想要的轉換
toString:function(){
return this.name+"<-->"+this.age; //zhangsan<-->12
}
};
//兩種輸出方式
console.log(obj.toString(), typeof obj.toString()); //zhangsan<-->12 string
console.log(String(obj), typeof String(obj)); // zhangsan<-->12 string
-
Object類型轉Number類型
轉換規則:
顯示轉換與隱式轉換規則類似,當要將對象轉換為Number時,類似隱式轉換中的PreferredType為Number
1.先調用對象的valueOf方法
2.判斷該方法的返回值是否為基礎數據類型(Number,String,Boolean,Undefined,Null)
3.若返回值為基礎數據類型,則轉換規則按照相應數據類型的轉換規則對其進行轉換
4.若返回值不為基礎數據類型,則在該返回值的基礎上繼續調用toString方法
5.判斷toString的返回值是否為基礎數據類型
6.判斷是否為基礎數據類型,若是基礎數據類型則進行操作3
7.若仍舊不為基礎數據類型則報錯
// Object類型轉Number類型
var obj = {
name: "zhang",
age: 12,
//重寫toString方法和valueOf方法
//兩個方法都重寫了 則調用valueOf()
valueOf: function () {
return 20;
},
toString: function () {
return 100;
},
};
/*
1.如果只重寫了valueOf()或者toString()方法,則調用該方法,並將返回值用Number()轉換。
2.如果兩個方法都重寫了,則調用valueOf(),並將返回值用Number()轉換。
3.如果兩個方法都沒有重寫,則返回NaN
*/
// 先使用Number 進行轉換
//如果兩個方法都重寫了,則調用valueOf(),並將返回值用Number()轉換。
console.log(Number(obj)); //20
檢測屬性
檢測一個屬性是否屬於某個對象。常用的方式主要有3種:
in
檢測某屬性是否是某對象的自有屬性或者是繼承屬性
var obj = {
name: 'zhangsan',
age: 18,
school: 'xx大學'
}
//in運算符的左側為屬性名稱,右側為對象
console.log('name' in obj); //true
console.log('age' in obj); //true
console.log('gender' in obj); //false
//如果用in判斷一個屬性存在,這個屬性不一定是obj的,它可能是obj繼承得到的,如:
'toString' in obj; // true
////因為toString定義在object對象中,而所有對象最終都會在原型鏈上指向object,所以obj也擁有toString屬性。
Object.prototype.hasOwnProperty()
檢測給定的屬性是否是對象的自有屬性,對於繼承屬性將返回false
var obj = {
name: 'zhangsan', age: 18, school: 'xx大學'}console.log(obj.hasOwnProperty('name')); //trueconsole.log(obj.hasOwnProperty('age')); //trueconsole.log(obj.hasOwnProperty('toString')); //false,toString為繼承屬性console.log(obj.hasOwnProperty('gender')); //false
Object.prototype.propertyIsEnumerable() ----->> obj.propertyIsEnumerable()
propertyIsEnumerable()是hasOwnProperty()的增強版,除了是自身屬性外,還要求是可枚舉屬性,即我們創建的屬性。
var obj = {
name: 'zhangsan',
age: 18,
school: 'xx大學'}
console.log(obj.propertyIsEnumerable('name')); //trueconsole.log(obj.propertyIsEnumerable('age')); //trueconsole.log(obj.propertyIsEnumerable('toString')); //false,不可枚舉
console.log(obj.propertyIsEnumerable('gender')); //false
Object原型屬性及方法(原型方法,實例可以調用的方法)
在Object的構造函數的原型對象中的屬性和方法都可以被Object構造函數的實例所繼承。
Object原型中的所具有的任何屬性和方法也同樣存在於其他對象中,任何對象繼承自Object。
總結:每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,實例都包含一個指向原型對象的內部指針。 ----《JavaScript高級程序設計》
Object原型中常用的方法:
constructor
保存用户創建當前對象的函數,與原型對象對應的構造函數
hasOwnProperty(propertyName)
檢查給定的屬性名是否是對象的自有屬性
propertyIsEnumerable(propertyName)
檢查給定的屬性在當前對象實例中是否存在
valueOf()
返回對象的字符串,數值,布爾值的表示
toLocaleString()
返回對象的字符串表示,該字符串與執行環境的地區對應
toString()
返回對象的字符串表示
isPrototypeOf(object)
檢查傳入的對象的原型
a.isPrototypeOf(b) 如果a是b的原型,則返回true。如果b不是對象,或者a不是b的原型,則返回false。
// 使用構造函數創建實例對象
var obj = new Object()// 調用原型對象中繼承的方法console.log(obj.toString());
console.log(obj.__proto__.toString());// 構造函數 Objectconsole.log(Object); //[Function: Object]// 原型對象 Object.prototypeconsole.log(Object.prototype); // {}// 原型對象中的constructor屬性 原型對象中的constructor屬性指向構造函數console.log(Object.prototype.constructor); //[Function: Object]console.log(Object === Object.prototype.constructor); //true// 實例__proto__ 指向 原型對象console.log(obj.__proto__ === Object.prototype); //true// 創建Date對象var now = new Date();
console.log(now);// 使用原型對象中的方法console.log(now.toString());//Mon Aug 23 2021 23:22:35 GMT+0800 (GMT+08:00) (中國標準時間)
console.log(now.toLocaleString());//2021-8-23 23:22:35
7.深入理解對象-定義屬性
ECMAScript中有兩種屬性:數據屬性、訪問器屬性。這兩種屬性用於設置屬性的高級屬性,例如該屬性是否可以配置,是否可以讀寫,是否可以遍歷,並且可以通過setter,getter來監聽數據的改變。
-
數據屬性特性
數據屬性 例如name屬性
包含一個屬性值的位置,這個位置可以讀取和寫入值。數據屬性特性如下
[[Configurable]] ----->>表示是否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或者能否把屬 性修改為訪問器屬性(屬性直接定義在對象中,默認為true)。 當為false時,不能重新定義不能使用delete刪除。
[[Enumerable]]------>>表示能否通過for-in循環返回屬性。(屬性直接定義在對象中,默認為true)
[[Writable]] ------>>表示能否修改屬性的值。(屬性直接定義在對象中,默認為true)
[[Value]] ---------->>包含這個屬性的數據值 name:jacky
要修改屬性默認的特性,必須使用ECMAScript5的
Object.defineProperty(屬性所在的對象,屬性的名字,一個描述符對象)方法
對象是由多個鍵/值對組成的無序的集合。對象中每個屬性可以是任意類型的值。
定義對象可以使用構造函數或字面量的形式:
var obj = new Object();
obj.name = 'zhangsan';
obj.say = function () {};
除了以上添加屬性的方式,還可以使用Object.defineProperty定義新屬性或修改原有的屬性。
Object.defineProperty()
語法:
Object.defineProperty(obj, prop, descriptor)
參數説明:
- obj:必需。目標對象
- prop:必需。需定義或修改的屬性的名字
- descriptor:必需。目標屬性所擁有的特性
返回值:
傳入函數的對象。即第一個參數obj;
Object.defineProperty(obj,'name',{
configurable:true,
enumerable:true,
writable:true,
value:'terry'})
console.log(obj.name);
Object.defineProperty(obj,"name",{
enumerable:false
})
obj.propertyIsEnumerable("name");//false
注意:當我們創建一個對象並且為對象設置一個屬性的時候,該屬性默認特性Configurable、Enumerable、Writable默認都為true,value為該屬性的值。
Object.defineProperties()
語法:
Object.defineProperties(obj, props)
參數説明:
- obj:必需。目標對象
- props:該對象的一個或多個鍵值對定義了將要為對象添加或修改的屬性的具體配置 鍵值對
返回值:
傳入函數的對象。即第一個參數obj;
var obj = new Object();
Object.defineProperties(obj, {
name: {
value: 'zhangsan',
configurable: false,
writable: true,
enumerable: true
},
age: {
value: 18,
configurable: true
}})
console.log(obj.name, obj.age) // zhangsan, 18
-
讀取屬性的特性
Object.getOwnPropertyDescriptor()
功能:
該方法返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不需要從原型鏈上進行查找的屬性)
語法: Object.getOwnPropertyDescriptor(obj, prop)
obj: 需要查找的目標對象
prop: 目標對象內屬性名稱
var person = {
name: '張三',
age: 18}
var desc = Object.getOwnPropertyDescriptor(person, 'name'); console.log(desc)
結果如下// {// configurable: true,
// enumerable: true,
// writable: true,
// value: "張三"
// }
Object. getOwnPropertyDescriptors()
功能:
所指定對象的所有自身屬性的描述符,如果沒有任何自身屬性,則返回空對象。
語法: Object.getOwnPropertyDescriptors(obj)
obj: 需要查找的目標對象
var person = { name: '張三', age: 18}
var desc = Object.getOwnPropertyDescriptors(person);
console.log(desc) //{
// configurable: true,
// enumerable: true,
// value: '張三',
// writable: true//}
-
訪問器屬性特性
訪問器屬性:這個屬性不包含數據值,包含的是一對get和set方法,在讀寫訪問器屬性時,就是通過這兩個方法來進行操作處理的。
訪問器屬性包含的四個特性:
[[Configurable]]------>>表示能否通過delete刪除屬性從而重新定義屬性,能否修改屬性的特性,或能否把屬性修改為訪問器屬性, 默認為false
[[Enumerable]]------->>表示能否通過for-in循環返回屬性,默認為false
[[Get]]-------->>在讀取屬性時調用的函數,默認值為undefined
[[Set]]-------->>在寫入屬性時調用的函數,默認值為undefined
這裏要注意下,訪問器屬性不能直接定義,要通過Object.defineProperty()這個方法來定義。
//訪問器屬性:這個屬性不包含數據值,包含的是一對get和set方法,在讀寫訪問器屬性時,就是通過這兩個方法來進行操作處理的。
var book = {
_year:2020, //下劃線表示是內部屬性,只能通過對象的方法來讀寫
editor: 1
}
//訪問器屬性 Object.defineProperty(obj, prop, descriptor)
// 1. obj:必需。目標對象
// 2. prop:必需。需定義或修改的屬性的名字
// 3. descriptor:必需。目標屬性所擁有的特性
// 可以使用`Object.defineProperty`定義新屬性或修改原有的屬性。
Object.defineProperty(book, 'year', {
// get 函數 如果只寫了get方法,當前的year屬性就是隻讀的
get: function () {
// 返回私有屬性
return this._year;
},
//修改 // 若只指定get方法,不指定set方法,那就默認該屬性是隻讀的
set:function (newYear) {
//判斷 如果兩個值不同
if (newYear !== this._year) {
this._year = newYear;
this.editor++
}
}
})
// 測試訪問屬性中的get,set方法
console.log('未修改的year:' + book.year); //未修改的year:2020
book.year = 2023;
console.log('修改後的year:' + book.year); //修改後的year:2023
console.log('修改year後的editor:' + book.editor); //修改year後的editor:2
// 訪問器屬性可以通過Object.getOwnPropertyDescriptor()查詢
console.log(Object.getOwnPropertyDescriptor(book, '_year')); //{ value: 2023, writable: true, enumerable: true, configurable: true }
由此可以想到數據的雙向綁定:
在一個對象(book)中設置一個私有屬性(_year:開頭下劃線代表私有屬性),再為這個對象設置訪問器屬性year(本身還未在對象中定義),當book.year進行修改時觸發set函數,通過這個函數可以進行數據的操作,比如數據的判斷賦值等一系列操作,從而實現數據的雙向綁定。這個原理是vue的本質原理。vue是數據驅動框架,當數據發生改變的時候,視圖自動更新。
8.對象序列化
對象序列化是指將對象的狀態轉換為字符串,也可以反序列化,將字符串還原為對象函數。
RegExp,Error對象,undefined值不能序列化和反序列化。
//涉及深拷貝和淺拷貝的問題
JSON.stringify(obj) 將對象序列化為JSON字符串,只能序列化對象可枚舉的自有屬性
JSON.parse(jsonStr) 反序列化
var obj = {
name:'zhang',
age:14
}
// 對象序列化是指將對象的狀態轉換為字符串,也可以反序列化,將字符串還原為對象函數
//JSON.stringify(obj) 將對象序列化為JSON字符串,只能序列化對象可枚舉的自有屬性
var jsonStr = JSON.stringify(obj)
console.log(jsonStr,typeof jsonStr); //{"name":"zhang","age":14} string
// JSON.parse(jsonStr) 反序列化 引用地址發生改變
var jsonObj = JSON.parse(jsonStr)
console.log(jsonObj,typeof jsonObj); //{ name: 'zhang', age: 14 } object
console.log(obj); //{ name: 'zhang', age: 14 }
console.log(jsonObj == obj); //false
jsonObj.name = 'xxxxx'
console.log(jsonObj); //{ name: 'xxxxx', age: 14 }
console.log(obj);