JS數(shù)據(jù)類型之Object(二)創(chuàng)建對象

創(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é)果:


圖片.png

優(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é)果:


圖片.png
使用new操作符執(zhí)行的操作
new操作的執(zhí)行流程.png

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ù)之后得到的對象新娜。

構(gòu)造函數(shù)、原型既绩、實例關(guān)系圖.png
  • 只要創(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原型的原型是nullObject.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)建原型。

  • 使用場景

    1. 合并對象:多個對象進(jìn)行合并。
    2. 復(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:非枚舉
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市叹谁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乘盖,老刑警劉巖焰檩,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異订框,居然都是意外死亡析苫,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來衩侥,“玉大人国旷,你說我怎么就攤上這事∶K溃” “怎么了跪但?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長峦萎。 經(jīng)常有香客問我屡久,道長,這世上最難降的妖魔是什么爱榔? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任被环,我火速辦了婚禮,結(jié)果婚禮上详幽,老公的妹妹穿的比我還像新娘筛欢。我一直安慰自己,他們只是感情好唇聘,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布版姑。 她就那樣靜靜地躺著,像睡著了一般雳灾。 火紅的嫁衣襯著肌膚如雪漠酿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天谎亩,我揣著相機與錄音炒嘲,去河邊找鬼。 笑死匈庭,一個胖子當(dāng)著我的面吹牛夫凸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阱持,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼夭拌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衷咽?” 一聲冷哼從身側(cè)響起鸽扁,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎镶骗,沒想到半個月后桶现,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡鼎姊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年陵霉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片整慎。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖钮科,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情婆赠,我是刑警寧澤绵脯,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站页藻,受9級特大地震影響桨嫁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜份帐,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一璃吧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧废境,春花似錦畜挨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至驮宴,卻和暖如春逮刨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堵泽。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工修己, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人迎罗。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓睬愤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纹安。 傳聞我的和親對象是個殘疾皇子尤辱,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容