一走越、對(duì)象與類
對(duì)象(object)是 JavaScript 最重要的數(shù)據(jù)結(jié)構(gòu)城舞。
類是一種數(shù)據(jù)類型,是具有相同特性(數(shù)據(jù)元素)和行為(功能)的對(duì)象的抽象狭魂。
1. 類和對(duì)象的區(qū)別
- 類實(shí)例化的結(jié)果就是對(duì)象猖闪,類描述了一組有相同特性(屬性)和相同行為的對(duì)象吹榴。
- 類是對(duì)象的模板
//定義類
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
console.log(this.name)
}
}
let person1 = new Person("張三", 18);
person1.sayName();
let person2 = new Person("李四", 20);
2. 對(duì)象定義(聲明)的兩種方式
2.1 字面量的方式進(jìn)行定義
var obj = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
2.2 使用 new Object() 進(jìn)行定義
var obj = new Object();
//定義屬性
obj.name = "Tom ";
obj.sex = " man";
obj.age = 19;
//定義方法
obj.run = function(){
console.log("一天跑一公里");
}
二胧洒、創(chuàng)建對(duì)象的方式
1. 工廠模式
- 使用簡(jiǎn)單的函數(shù)創(chuàng)建對(duì)象畏吓,為對(duì)象添加屬性和方法墨状,然后返回對(duì)象
// Class 模板
function Person(name,sex,age){
var obj = {};
obj.name = name;
obj.sex = sex;
obj.age = age;
obj.run = function(){
console.log("每天堅(jiān)持跑步");
}
return obj;
}
// 實(shí)例化
var person1 = Person("Tom","sex",19);
//操作
person1.run(); // 輸出結(jié)果:每天堅(jiān)持跑步
工廠模式的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
1、 在工廠模式中菲饼,用戶只需要知道所要生產(chǎn)的具體東西肾砂,無(wú)須關(guān)心具體的創(chuàng)建過(guò)程,甚至不需要具體產(chǎn)品類的類名宏悦。
2通今、 在系統(tǒng)增加新的產(chǎn)品時(shí),我們只需要添加一個(gè)具體產(chǎn)品類和對(duì)應(yīng)的實(shí)現(xiàn)工廠肛根,無(wú)需對(duì)原工廠進(jìn)行任何修改辫塌,很好地符合了“開(kāi)閉原則”。
缺點(diǎn):
1派哲、 每次增加一個(gè)產(chǎn)品時(shí)臼氨,都需要增加一個(gè)具體類和對(duì)象實(shí)現(xiàn)工廠,使得系統(tǒng)中類的個(gè)數(shù)成倍增加芭届,在一定程度上增加了系統(tǒng)的復(fù)雜度储矩,同時(shí)也增加了系統(tǒng)具體類的依賴。這并不是什么好事褂乍。
2. 構(gòu)造函數(shù)模式(new)
- 創(chuàng)建自定義引用類型持隧,可以像創(chuàng)建內(nèi)置對(duì)象實(shí)例一樣使用new操作符,這種方法的缺點(diǎn)是逃片,構(gòu)造函數(shù)的每個(gè)成員都無(wú)法復(fù)用屡拨,每次創(chuàng)建出的對(duì)象都只有私有變量和私有方法,不能實(shí)現(xiàn)共用
//構(gòu)造函數(shù)(這里就創(chuàng)建了一個(gè)Class模板)
function Person(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
this.run = function(){
console.log("每天堅(jiān)持跑步");
}
}
// 實(shí)例化 ( new Object())
var person1 = new Person("Tom","man",19);
//操作
person1.run();// 每天堅(jiān)持跑步
//改造構(gòu)造函數(shù)褥实,把方法抽出來(lái)呀狼,定義成公共方法
// 構(gòu)造全局的對(duì)象
var action = {
run:function(){
console.log("每天堅(jiān)持跑步");
}
}
//構(gòu)造函數(shù)
function Person(name,sex,age){
...
this.run = action.run;
}
//實(shí)例化
var person1 = new Person("Tom","man",19);
person1.run();
使用new操作符實(shí)例化類時(shí),相當(dāng)于使用new調(diào)用其的構(gòu)造函數(shù)损离。構(gòu)造流程圖如下:
- 創(chuàng)建一個(gè)空對(duì)象哥艇,作為將要返回的對(duì)象實(shí)例。
- 將這個(gè)空對(duì)象的原型僻澎,指向構(gòu)造函數(shù)的
prototype
屬性貌踏。- 將這個(gè)空對(duì)象賦值給函數(shù)內(nèi)部的this關(guān)鍵字。
- 開(kāi)始執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼窟勃。(完成賦值等操作)
- 最后返回這個(gè)對(duì)象祖乳。
3. 原型模式
- 使用構(gòu)造函數(shù)的prototype屬性來(lái)指定共享的屬性和方法,即使用構(gòu)造函數(shù)定義實(shí)例屬性拳恋,使用原型定義共享的屬性和方法
//構(gòu)造函數(shù)
function Person(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
}
//使用原型對(duì)象 Object.prototype
Person.prototype.run = function() {
console.log("每天堅(jiān)持跑步");
}
//實(shí)例化
var person1 = new Person("Tom","man",19);
person1.run();// 每天堅(jiān)持跑步
三凡资、對(duì)象的方法
JS對(duì)象方法 | 作用 |
---|---|
Object.defineProperty(obj, prop,descriptor) |
定義/修改一個(gè)對(duì)象中的屬性 |
Object.defineProperties(obj.props) |
在一個(gè)對(duì)象上定義新的屬性或修改現(xiàn)有屬性,并返回該對(duì)象。 |
Object.getOwnPropertyDescriptor(obj,prop) |
獲取對(duì)象中的一個(gè)屬性描述 |
Object.freeze(obj) |
凍結(jié)一個(gè)對(duì)象,再也不能被修改 |
Object.isFrozen(obj) |
返回布爾值隙赁,判斷對(duì)象是否被凍結(jié) |
Object.getOwnPropertyNames(obj) |
返回指定對(duì)象所有屬性垦藏,同時(shí)也包括不可枚舉屬性組成的數(shù)組(除了Symbol屬性) |
Object.getOwnPropertySymbols(obj) |
返回一個(gè)給定對(duì)象自身的所有Symbol屬性的數(shù)組 |
Object.isExtensible(obj) |
判斷對(duì)象是否具備可擴(kuò)展性,返回布爾值 |
Object.create(obj伞访,propertiesObject)** ** |
創(chuàng)建一個(gè)新對(duì)象掂骏,使用現(xiàn)有對(duì)象來(lái)提供新創(chuàng)建對(duì)象的proto |
Object.isSealed(obj) |
返回boolean, 判斷對(duì)象是否為封閉對(duì)象 |
十九厚掷、Object.Seal(obj) |
封閉一個(gè)對(duì)象弟灼,阻止添加新屬性并將所有現(xiàn)有屬性標(biāo)記為不可配置 |
ES6新增的對(duì)象方法 | |
Object.is(Value1 , Value2) |
判斷兩個(gè)值是否為"相同的值" |
Object.assign(target, source1, source2) |
用于對(duì)象合并,將源對(duì)象(source)所有可枚舉屬性冒黑,復(fù)制到目標(biāo)對(duì)象(target) |
Object.getOwnPropertyDescriptors(obj) |
獲取目標(biāo)對(duì)象中的所有屬性描述 |
Object.setPrototypeOf(obj,property) |
設(shè)置一個(gè)指定的對(duì)象的原型對(duì)象 |
Object.getPrototypeOf(obj) |
返回指定對(duì)象的原型對(duì)象 |
Object.keys(obj) |
獲取一個(gè)對(duì)象中所有的鍵名key (除了不可枚舉屬性和Symbol屬性) |
Object.values(obj) |
獲取一個(gè)對(duì)象中所有的鍵值value(除了不可枚舉屬性和Symbol屬性) |
Object.entries(obj) |
獲取一個(gè)對(duì)象中所有的鍵值對(duì)(key和value) |
Object.fromEntries(obj) |
用于將一個(gè)鍵值對(duì)數(shù)組轉(zhuǎn)為對(duì)象田绑。 |
四、判斷對(duì)象類型
1. typeof
- typeof 常用來(lái)判斷基本數(shù)據(jù)類型抡爹,無(wú)法做到準(zhǔn)確的判斷對(duì)象類型掩驱,返回值字符串
function sum(a,b){
return a+b
}
var symbol1 = Symbol("a")
console.log(typeof 42); // "number"
console.log(typeof NaN); // "number"
console.log(typeof Infinity); // "number"
console.log(typeof new String(1)); // "object"
console.log(typeof new Number(1)); //"object"
console.log(typeof String(1)); // "string"
console.log(typeof Number(1)); //"number"
console.log(typeof 'string'); //"string"
console.log(typeof true);//"boolean"
console.log(typeof sum); //"function"
console.log(typeof symbol1);// "symbol"
console.log(typeof null); //"object"
console.log(typeof undefined); // "undefined"
console.log(typeof Array);
console.log(typeof Date);
console.log(typeof Object);
console.log(typeof new Array());
console.log(typeof new Date());
console.log(typeof Object());
console.log(typeof Bigint);
2. instanceof
- ES6新增,為了解決typeof 無(wú)法檢查出具體對(duì)象類型冬竟,返回布爾值
- instanceof的本質(zhì):檢測(cè)構(gòu)造函數(shù)(右邊)的 prototype 屬性是否出現(xiàn)在某個(gè)實(shí)例對(duì)象(左邊)的原型鏈上
// 檢查是否屬于某個(gè)構(gòu)造函數(shù)
function A() {
return "A"
}
var a = new A();
console.log(a instanceof A) // true
var b = {};
console.log(b instanceof Object); //true
var c = [];
console.log(c instanceof Object); //true
console.log(c instanceof Array); //true
console.log( ({a:1}) instanceof Object) // true
let obj = Object.create(null)
console.log(obj instanceof Object) // false
// Object.create(null) 例外
//[].proto 原型是指向Array.prototype的欧穴,說(shuō)明兩個(gè)對(duì)象是屬于同一條原型鏈的,返回true
3. constructor
- 通過(guò)constructor來(lái)判斷數(shù)據(jù)的類型,但是除了null泵殴、undefined涮帘,因?yàn)樗麄儾皇怯蓪?duì)象構(gòu)建。
{1:"1"}.__proto__.contructor === Object; //true
1.__proto__.contructor === Number; // true
[1].__proto__.contructor === Array; // true
4.Object.prototype.toString.call()
- 通過(guò)Object.prototype.toString返回對(duì)象類型字符串笑诅,判斷類型
- 建議:加上call() 改變this指向调缨,因?yàn)槿绻谠蜕隙x了toString方法,this的指向會(huì)指向?yàn)樵投x的方法苟鸯,可能達(dá)不到預(yù)期目的
Object.prototype.toString.call('1') // [object String]
Object.prototype.toString.call(1) // [object Number]
Object.prototype.toString.call([1]) // [object Array]
Object.prototype.toString.call(true) // [object Boolean]
Object.prototype.toString.call(undefined) // [object Undefined]
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.call(new Array()); // [object Array]
Object.prototype.toString.call(new Function()); // [object Function]
Object.prototype.toString.call(new Date()); // [object Date]
Object.prototype.toString.call(new Object()); // [object Object]
Object.prototype.toString.call(new RegExp()); // [object RegExp]
Object.prototype.toString.call(new Error()); // [object Error]
五同蜻、ES6對(duì)象新特性
1. 屬性的簡(jiǎn)潔表示法
ES6 允許在大括號(hào)里面,直接寫(xiě)入變量和函數(shù)早处,作為對(duì)象的屬性和方法。這樣的書(shū)寫(xiě)更加簡(jiǎn)潔瘫析。
- 如果對(duì)象的屬性值和屬性如果發(fā)生重名砌梆,我們只寫(xiě)一個(gè)屬性名即可,他會(huì)根據(jù)相同的屬性名來(lái)獲取相應(yīng)的屬性值贬循;
- 方法也可以簡(jiǎn)寫(xiě)咸包。
let birth = '2000/01/01';
const Person = { //大括號(hào)里面,直接寫(xiě)入變量和函數(shù)杖虾,作為對(duì)象的屬性和方法
name: '張三',
//等同于birth: birth
birth,
// 等同于hello: function ()...
hello() { console.log('我的名字是', this.name); }
};
2. 屬性名表達(dá)式
// 方法一 用標(biāo)識(shí)符作為屬性名,ES5烂瘫,ES6使用字面量方式定義對(duì)象可用
obj.foo = true;
// 方法二 用表達(dá)式作為屬性名,ES6使用字面量方式定義對(duì)象可用
obj['a' + 'bc'] = 123;
3. 方法的 name 屬性
- 對(duì)象中方法函數(shù)里面name隱式屬性的值就是方法名
const person = {
sayName() {
//隱式屬性name:"sayName"
console.log('hello!');
},
};
person.sayName.name // "sayName"
4. 屬性的可枚舉性和遍歷
可枚舉性:對(duì)象的每個(gè)屬性都有一個(gè)描述對(duì)象(Descriptor),用來(lái)控制該屬性的行為坟比。Object.getOwnPropertyDescriptor
方法可以獲取該屬性的描述對(duì)象芦鳍。
屬性的遍歷:
遍歷對(duì)象屬性的方法 | 區(qū)別 |
---|---|
for...in |
循環(huán)遍歷對(duì)象自身的和繼承的可枚舉屬性(不含 Symbol 屬性) |
Object.keys(obj) |
返回一個(gè)數(shù)組,包括對(duì)象自身的(不含繼承的)所有可枚舉屬性(不含 Symbol 屬性)的鍵名 |
Object.getOwnPropertyNames(obj) |
返回一個(gè)數(shù)組葛账,包含對(duì)象自身的所有屬性(不含 Symbol 屬性柠衅,但是包括不可枚舉屬性)的鍵名 |
Object.getOwnPropertySymbols(obj) |
返回一個(gè)數(shù)組,包含對(duì)象自身的所有 Symbol 屬性的鍵名 |
Reflect.ownKeys(obj) |
返回一個(gè)數(shù)組籍琳,包含對(duì)象自身的(不含繼承的)所有鍵名菲宴,不管鍵名是 Symbol 或字符串,也不管是否可枚舉 |
5. super 關(guān)鍵字(做對(duì)象使用)
ES6 又新增了另一個(gè)類似的關(guān)鍵字
super
趋急,指向當(dāng)前對(duì)象的原型對(duì)象喝峦。super()
的另一種使用場(chǎng)景:作為函數(shù)使用,子類必須在constructor
方法中調(diào)用super
方法,繼承父類的屬性和方法呜达。
6. 對(duì)象的擴(kuò)展運(yùn)算符
- 擴(kuò)展運(yùn)算符是三個(gè)點(diǎn)(
...
)愈犹,將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列。
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
7. AggregateError 錯(cuò)誤對(duì)象
AggregateError
在一個(gè)錯(cuò)誤對(duì)象里面闻丑,封裝了多個(gè)錯(cuò)誤漩怎。如果某個(gè)單一操作,同時(shí)引發(fā)了多個(gè)錯(cuò)誤嗦嗡,需要同時(shí)拋出這些錯(cuò)誤勋锤,那么就可以拋出一個(gè) AggregateError 錯(cuò)誤對(duì)象,把各種錯(cuò)誤都放在這個(gè)對(duì)象里面侥祭。AggregateError
本身是一個(gè)構(gòu)造函數(shù)叁执,用來(lái)生成 AggregateError 實(shí)例對(duì)象。
-
AggregateError(errors[, message])
的實(shí)例對(duì)象有三個(gè)屬性矮冬。name:錯(cuò)誤名稱谈宛,默認(rèn)為“AggregateError”。
message:錯(cuò)誤的提示信息胎署。
errors:數(shù)組吆录,每個(gè)成員都是一個(gè)錯(cuò)誤對(duì)象。