創(chuàng)建對象
1等脂、字面量
let obj = {
property_i : value_i,
}
2序愚、Object構(gòu)造函數(shù)
let obj = new Object();
大部分情況下爆雹,我們都是通過構(gòu)造函數(shù)創(chuàng)建對象臼闻。常用的對象有:new String()|new Number()|new Boolean()|new Date()|new RegExp()| new Function()
以上兩種方法的缺點:創(chuàng)建具有同樣接口的多個對象需要重復(fù)多個代碼读恃。
3隧膘、工廠模式
兩步走:
1、創(chuàng)建工廠
2寺惫、運行工廠
// 1疹吃、創(chuàng)建工廠
function createPerson(name, age, job) {
let o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
console.log(this.name)
}
return o;
}
// 2、運行工廠
let person = createPerson("張三", 18, "程序員");
console.dir(person)
運行結(jié)果:
優(yōu)點:解決創(chuàng)建多個類似對象的問題
缺點:沒有解決對象標(biāo)識問題(即新創(chuàng)建的對象是Object類型西雀,沒有具體化)
4萨驶、構(gòu)造函數(shù)模式
兩步走:
1、通過創(chuàng)建一個構(gòu)造函數(shù)來定義對象的類型艇肴,首字母大寫是非常普通而且很恰當(dāng)?shù)膽T用法腔呜。
2、通過new
創(chuàng)建對象實例再悼。
注意事項:
1.使用this關(guān)鍵字
2.首字母大寫
// 第一步
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
this.driver = function () {
console.log("driver")
} // 可以將此函數(shù)定義在構(gòu)造函數(shù)的外部核畴,但是不規(guī)范【全局作用域被搞亂了】
// return this; // 會自動return this
}
// 第二步
var car1 = new Car("Nissan", "300ZX", 1992);
var car2 = new Car("Nissan1", "300ZX1", 2000);
console.dir(car1)
console.log(car1.driver == car2.driver)
運行結(jié)果:
使用new操作符執(zhí)行的操作
1、在內(nèi)存中創(chuàng)建一個新對象冲九。
2谤草、在這個新對象內(nèi)部的[[Prototype]]
特性被賦值為構(gòu)造函數(shù)的prototype
屬性。
3莺奸、構(gòu)造函數(shù)的內(nèi)部的this
被賦值為這個新對象(this指向新對象)
4丑孩、執(zhí)行構(gòu)造函數(shù)內(nèi)部的代碼(給新對象添加屬性)
5、如果構(gòu)造函數(shù)返回非空對象灭贷,則返回該對象温学;否則,返回剛創(chuàng)建的新對象
構(gòu)造函數(shù) VS 函數(shù)
構(gòu)造函數(shù)與普通函數(shù)唯一的區(qū)別就是調(diào)用方式不同甚疟。
構(gòu)造函數(shù)的優(yōu)點:解決對象標(biāo)識問題
構(gòu)造函數(shù)的缺點:構(gòu)造函數(shù)中定義的方法會在每個實例上都創(chuàng)建一遍仗岖,各個實例會定義不同的Function實例。
5古拴、原型模式
每個函數(shù)都會創(chuàng)建一個prototype
屬性箩帚,這個屬性是一個對象,包含應(yīng)該由特定類型的實例共享的屬性和方法黄痪。
function Person() {}
Person.prototype.name = "張三";
Person.prototype.age = 30;
Person.prototype.job = "程序員";
Person.prototype.sayName = function() {
console.log(this.name)
}
let person1 = new Person();
let person2 = new Person();
person1.sayName() // 張三
console.log(person1.sayName == person2.sayName) // true
原型性質(zhì)
- 原型的寫法
1紧帕、單個寫
這樣寫只是在原型上新增屬性和方法,已有的屬性和方法不會受到影響。
function Person() {}
Person.prototype.name = "張三";
Person.prototype.sayName = function() {
console.log(this.name)
}
2是嗜、合并寫
給構(gòu)造函數(shù)的原型重新賦值時愈案,原來的原型將被替換,其中最重要的屬性是constructor鹅搪,constructor指向構(gòu)造函數(shù)站绪,而且還是不可迭代的。[[Enumerable]]的值為false丽柿。
function Person() {}
Person.prototype = {
name: "張三",
sayName: function() {
console.log(this.name);
}
} // 對象重置恢准,原有的屬性均消失
Object.defineProperty(Person.prototype, "constructor", {
enumerable: false,
value: Person
});
原型的動態(tài)性
任何時候?qū)υ退龅男薷臅趯嵗戏从吵鰜怼W⒁獠皇墙o原型重新賦值甫题。原生對象原型
不要修改原生對象的原型馁筐,因為可能造成誤會或命名沖突。推薦的做法是創(chuàng)建一個自定義的類型坠非,繼承原生對象敏沉。
原型模式的缺點:弱化了構(gòu)造函數(shù)傳遞初始化參數(shù)的能力;原型模式的共享特性的弊端炎码,所有實例都會影響共享特性盟迟。
構(gòu)造函數(shù) VS 原型 VS 實例
構(gòu)造函數(shù):類似與類,與函數(shù)類似潦闲,只是通過new使用
原型:所有的JavaScript對象至少繼承于一個對象攒菠,被繼承的對象被稱為原型。JS中的每個函數(shù)都有一個prototype原型屬性矫钓,這個屬性也是一個對象要尔,用途是包括能夠由特定類型的全部實例共享的屬性和方法。
實例:new 構(gòu)造函數(shù)之后得到的對象新娜。
- 只要創(chuàng)建一個函數(shù)概龄,就會按照特定的規(guī)則為這個函數(shù)創(chuàng)建一個
prototype
屬性,指向原型對象饲握,原型是一個實例對象私杜。 - 默認(rèn)情況下,所有原型對象自動獲取一個名為
constructor
屬性救欧,指回與之關(guān)聯(lián)的構(gòu)造函數(shù)衰粹,即循環(huán)引用。Person.prototype.constructor = Person
- 實例化對象中的
__proto__
屬性指向原型笆怠,構(gòu)造函數(shù)中的prototype
屬性指向原型铝耻,即person.__proto__ = Person.prototype
- 原型中的
__proto__
指向父原型的prototype
,即Person.prototype.__proto__ == Object.prototype
- 正常的原型鏈都會終止與
Object
的原型,即Person.prototype.__proto__.constructor == Object
- Object原型的原型是null
Object.prototype.__proto__ == null; // true
- instanceof 操作符檢查實例的原型鏈中是否包含指定構(gòu)造函數(shù)的原型瓢捉。
- 使用原型的
isPrototypeOf()
方法確定是否屬于這個原型频丘。 - 獲取一個實例的原型
Object.getPrototypeOf(實例)
- 設(shè)置一個實例的原型
Object.setPrototypeOf(實例, 原型)
;此方法會嚴(yán)重影響代碼性能泡态,可以使用Object.create()
方法創(chuàng)建一個指定原型的對象搂漠。
通過Object.create()
方法創(chuàng)建時,我們可以為創(chuàng)建的對象選定一個原型對象某弦,而不用定義構(gòu)造函數(shù)桐汤。
- 參數(shù):
proto:新創(chuàng)建對象的原型對象;
propertiesObject:為新創(chuàng)建的對象添加指定的屬性值和對應(yīng)的屬性描述符靶壮。 - 返回值:一個新對象惊科,帶著指定的原型對象和屬性。
- 注意事項:
Object.create(object, propertiesObject)中propertiesObject是null或非原始包裝對象亮钦,則會拋出TyperError異常馆截。
// 使用對象初始化器創(chuàng)建一個對象
var Animal = {
type: "Invertebrates", // 屬性默認(rèn)值
displayType : function() { // 用于顯示type屬性的方法
console.log(this.type);
}
}
// 通過Object.create()創(chuàng)建對象animal
var animal1 = Object.create(Animal);
animal1.displayType(); // Output:Invertebrates
// 創(chuàng)建一種新的動物——Fishes
var fish = Object.create(Animal);
fish.type = "Fishes";
fish.displayType(); // Output:Fishes
原型層級
-
訪問屬性和方法的流程
通過對象訪問屬性的時候,根據(jù)屬性名稱從對象自身開始搜索蜂莉,如果自身有此屬性蜡娶,則返回對應(yīng)的值;如果自身沒有此屬性映穗,則到最近原型上搜索窖张,直到原型為null或搜索到此屬性。
- 屬性的覆蓋
實例是有與原型同名的屬性蚁滋,會將原型上同名的屬性給覆蓋宿接。
屬性的位置
hasOwnProperty() |
in | |
---|---|---|
作用 | 判斷自身是否有此屬性 | 訪問自身或原型上的屬性 |
使用方法 | in操作符:判斷對象是否有此屬性[原型和自身] for..in:遍歷對象上可迭代的屬性[原型和自身] |
屬性枚舉
以下方法受到enumerable
和原型鏈
的影響。
方法 | for...in循環(huán) | Object.keys(o) | Object.getOwnPropertyNames(o) | Object.getOwnPropertySymbols(o) |
---|---|---|---|---|
含義 | 返回對象及原型鏈上可枚舉的屬性 | 返回自身的所有可枚舉屬性 | 返回自身所有屬性 | 返回自身所有的Symbols屬性 |
是否可枚舉 | 可 | 可 | 不關(guān)心 | Symbol |
是否訪問原型鏈 | 訪問 | 不訪問 | 不訪問 | 不訪問 |
是否訪問Symbol | 不訪問 | 不訪問 | 不訪問 | 訪問 |
- Object.getOwnPropertyNames()
作用:返回一個由指定對象的所有自身屬性的屬性名(包括不可枚舉屬性但不包括Symbol值作為名稱的屬性)組成的數(shù)組辕录。 - Object.getOwnPropertySymbols()
作用:返回一個給定對象自身的所有 Symbol 屬性的數(shù)組睦霎。
6、使用Object.assign方法
Object.assign()
方法用于將所有可枚舉屬性的值從一個或多個源對象分配到目標(biāo)對象走诞。它將返回目標(biāo)對象副女。
Object.assig(target, ...sources)
參數(shù):
target:目標(biāo)對象
sources:源對象返回值:
目標(biāo)對象過程:
Object.assign方法只會拷貝源對象自身并可枚舉的屬性到目標(biāo)對象。該方法會使用源對象的getter和setter方法蚣旱。如果目標(biāo)對象中的屬性具有相同的鍵碑幅,則屬性將被源對象中的屬性覆蓋。后面的源對象的屬性將類似地覆蓋前面源對象的屬性塞绿。注意事項
1沟涨、Object.assign()`是一個淺拷貝。
2异吻、繼承屬性和不可枚舉屬性是不能拷貝的
3裹赴、Object.assgin()方法沒有創(chuàng)建原型。-
使用場景
- 合并對象:多個對象進(jìn)行合并。
- 復(fù)制對象:對象的淺拷貝篮昧。
對象的迭代
枚舉一個對象的屬性
以下方法受到enumerable
和原型鏈
的影響赋荆。
方法 | for...in循環(huán) | Object.keys(o) | Object.getOwnPropertyNames(o) | Object.getOwnPropertySymbols(o) |
---|---|---|---|---|
含義 | 返回對象及原型鏈上可枚舉的屬性 | 返回自身的所有可枚舉屬性 | 返回自身所有屬性 | 返回自身所有的Symbols屬性 |
是否可枚舉 | 可 | 可 | 不關(guān)心 | Symbol |
是否訪問原型鏈 | 訪問 | 不訪問 | 不訪問 | 不訪問 |
是否訪問Symbol | 不訪問 | 不訪問 | 不訪問 | 訪問 |
for...in
作用:以任意順序遍歷一個對象的除Symbol以外的可枚舉屬性【包含原型鏈上可枚舉的屬性】
Object.keys()
作用:返回一個由一個給定對象的自身可枚舉屬性組成的數(shù)組,數(shù)組中屬性名的排列順序和正常循環(huán)遍歷該對象時返回的順序一致 懊昨。
對象迭代
ES2017新增兩個靜態(tài)方法Object.values()窄潭、Object.entries(),用于將對象內(nèi)容轉(zhuǎn)換為序列化的酵颁、可迭代的的格式嫉你。
Object.values(Object)
作用:返回一個給定對象自身的所有可枚舉屬性值的數(shù)組。
Object.entries(Object)
作用:返回一個給定對象自身可枚舉屬性的鍵值對數(shù)組
對象的繼承
所有的JavScript對象至少繼承于一個對象躏惋,被繼承的對象被稱為原型幽污。
每個對象可以通過構(gòu)造函數(shù)的prototype
屬性找到原型 或 每個實例對象有一個私有屬性__proto__
指向原型
獲取對象原型
方法一:Object.getPrototypeOf()
方法返回指定對象的原型。
方法二:實例化對象.__proto__
Object.getPrototypeOf(object)
- 參數(shù)
obj:要返回其原型的對象 - 返回值
給定對象的原型簿姨,如果沒有繼承屬性距误,則返回null
設(shè)置或修改對象原型
方法一:Object.create()
創(chuàng)建對象的時候指定原型.
方法二:Object.prototype.__proto__
方法三:Objcet.setPrototypeOf()
方法四:Reflect.setPrototypeOf()
Object.create(proto, propertiesObject)
:
- 參數(shù):
proto:新創(chuàng)建對象的原型對象
propertiesObject:可選 - 返回值
一個新對象,帶著指定的原型對象的屬性扁位。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script type="text/javascript">
"use strict"
// Shape - 父類(superclass)
function Shape() {
this.x = 0;
this.y = 0;
}
// 父類的方法
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - 子類(subclass)
function Rectangle() {
Shape.call(this); // call super constructor.
}
// 子類續(xù)承父類准潭,以下兩句話一般同時存在
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.dir(rect) // rect --> Rectangle---->Shape---->Object
</script>
</body>
</html>
Objcet.setPrototypeOf(obj, prototype)
- 參數(shù):
obj:設(shè)置其原型對象
prototype:對象的新原型(對象或null) - 過程:
如果對象的原型被修改成不可擴展(通過Object.isExtensible()
)的,則拋出TypeError異常域仇。
如果prototype新原型參數(shù)不是對象或努力了刑然,則什么也不做。
否則暇务,該方法修改對象的原型泼掠。
Reflect.setPrototypeOf(target, prototype)
- 參數(shù):
target:設(shè)置其原型對象
prototype:對象的新原型(對象或null) - 返回值:
返回一個boolean類型表明是否原型已經(jīng)設(shè)置成功。 - 過程:
如果參數(shù)target不是Object垦细,或者prototype既不是對象择镇,也不是null,則拋出TypeError異常蝠检。
Object原型與屬性相關(guān)的方法
方法 | 作用 | 參數(shù) | 返回值 |
---|---|---|---|
obj.hasOwnProperty() | 判斷屬性是否在某個對象自身上 {不含原型鏈} | prop:要檢測的屬性 | true:有 false:無 |
prop in obj | 判斷屬性是否在某個對象上 {含原型鏈} | prop:要檢測的屬性 | true:有 false:無 |
prototypeObj.isPrototypeOf(obj) | 測試一個對象是否在另一個對象的原型鏈上 | object:在該對象的原型鏈上搜尋 | true:在 false:不 |
instanceof操作符 | 檢測構(gòu)造函數(shù)的prototype屬性是否會出現(xiàn)在某個實例對象的原型鏈上 | 操作符沐鼠,不是函數(shù) | true:在 false:不在 |
obj.propertyIsEnumerable(prop) | 判斷屬性名是否可枚舉 | prop需要測試的屬性 | true:枚舉 false:非枚舉 |