創(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或搜索到此屬性。
訪問屬性的流程.png - 屬性的覆蓋
實例是有與原型同名的屬性,會將原型上同名的屬性給覆蓋。
屬性的位置
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:非枚舉 |
