你不知道的Object

1鸡号、Object.assign

Object.assign 方法只會拷貝源對象自身的并且可枚舉的屬性到目標對象。注意這里有個詞叫做可枚舉
Object.assign(target,...source)

1-1临梗、基礎(chǔ)用法

const t1 = {a:1,b:2};
const t2 = {b:3,c:4};
const t3 = {c:5,d:6};
const t4 = Object.assign(t1,t2,t3);
此時t1和t4是相同的 {a: 1, b: 3, c: 5, d: 6}
t2、t3此時是不變的

Object.assign會改變目標對象上的屬性和值,所以我們一般對對象進行合并一般使用const result = Object.assign({},...source);給予目標對象為一個空對象扣典,這樣就可以不用改變已有的值了负甸。

1-2流强、改變結(jié)果的屬性/屬性值痹届,那么目標對象是否會改變?

如果此時我們改變t4上面的屬性值打月,那么想想t1會不會被改變队腐??

const t1 = {a:1,b:2};
const t2 = {b:3,c:4};
const t3 = {c:5,d:6};
const t4 = Object.assign(t1,t2,t3);
t4.d = 100;
console.log(t1)//想想為什么奏篙?

console.log(t4)

結(jié)果卻是都一起被改變了柴淘,為什么會被改變?我們知道在程序中秘通,任何一個變量其實都被引用了一段16位進制的空間地址为严,在上述程序中其實t4的引用了t1的空間地址,上述我們可以理解為const t4 = t1;而t1在Object.assign運算中已被改變了

1-3肺稀、給其中一個源對象增加原型鏈增加屬性/方法

猜想下給其中一個源對象增加原型鏈增加屬性/方法,那么會有什么不同呢第股?

const t1 = {a:1,b:2};
const t2 = {b:3,c:4};
const t3 = {c:5,d:6};
t2.__proto__.e = 100;
t2.__proto__.print = function(){console.log(this)};
const t4 = Object.assign(t1,t2,t3);
console.log(t1.__proto__);
console.log(t2.__proto__);
console.log(t3.__proto__);
console.log(t4.__proto__);

結(jié)果我們發(fā)現(xiàn)竟然發(fā)現(xiàn)所有的源對象上的原型鏈包括結(jié)果和目標對象都有了新的屬性/方法這是為什么?话原?夕吻??
其實當(dāng)你真正的理解了什么是原型鏈這個結(jié)果就不意外了繁仁。
即使我們新建一個對象 不參與Object.assign運算也會發(fā)現(xiàn)這個新建的對象的原型鏈也有了這個新的屬性

const t1 = {a:1,b:2};
const t2 = {b:3,c:4};
const t3 = {c:5,d:6};
t2.__proto__.e = 100;
t2.__proto__.print = function(){console.log(this)};
const t4 = Object.assign(t1,t2,t3);
const t5 = {test:100};//不參與運算
console.log(t5.__proto__)其實都有了
console.log(new Object());其實都有了

1-4梭冠、什么是可枚舉

可枚舉值得是可以遍歷到的屬性,在這里的案例我們需要用到Object.defineProperty的用法了

const t1 = { a: 1, b: 2 };
const t2 = { b: 3, c: 4 };
const t3 = Object.defineProperty({}, "c", {
    value: 100
})
const t4 = Object.assign(t1, t2, t3);
console.log(t4); 此時這個值是多少?

我們可以知道Object.defineProperty的可枚舉屬性enumerable默認為false改备,所以此時t4的屬性c還是4控漠,但如果設(shè)置為true,可枚舉

const t1 = { a: 1, b: 2 };
const t2 = { b: 3, c: 4 };
const t3 = Object.defineProperty({}, "c", {
    value: 100,
    enumerable:true//可枚舉
})
const t4 = Object.assign(t1, t2, t3)
那么這里的t4屬性c就會變?yōu)?00

這就是說拷貝可枚舉的屬性

1-5、不會拷貝原型上的屬性或者方法

當(dāng)然這個前提是你不能更改Object上的屬性和方法悬钳,因為這個1-3的原因是一樣的盐捷,你改變了祖父上的屬性和方法,那么任何子類上都會繼承

function t1() {
    this.a = 1;
    this.b = 2
}
t1.prototype.c = 3;
t1.prototype.say = function () { };
const t2 = Object.assign({}, new t1());
console.log(t2);此時t2上沒有c默勾、say的屬性

1-6碉渡、面試題

猜想下下面的結(jié)果會是什么?

const t1 = 123;
const t2 = "456";
const t3 = false;
const t4 = function () { };
const t5 = Object.assign({},t1, t2, t3, t4)
console.log(t5);

解析母剥,Object.assign是復(fù)制對象滞诺,如果不是對象那么則會強制轉(zhuǎn)為對象

const r1 = new Number(t1);
const r2 = new String(t2);
const r3 = new Boolean(t3);
const r4 = new Function(t4);
for(let k in r1){console.log(k,r1[k]);}//沒打印
for(let k in r2){console.log(k,r2[k]);}//打印了
for(let k in r3){console.log(k,r3[k]);}//沒打印
for(let k in r4){console.log(k,r4[k]);}//沒打印

所以這道題的t5值真正的為t2的對象{0:4,1:5,2:6}

2、Object.create

Object.create方法創(chuàng)建一個新對象环疼,使用現(xiàn)有的對象來提供新創(chuàng)建的對象的__proto__习霹。其實這個語法和接下來學(xué)習(xí)的Object.defineProperty語法有關(guān)系

2-1、語法

@param proto
        新創(chuàng)建對象的原型對象炫隶。
@param propertiesObject
    可選淋叶。需要傳入一個對象,該對象的屬性類型參照Object.defineProperties()的第二個參數(shù)伪阶。
    如果該參數(shù)被指定且不為undefined煞檩,
    該傳入對象的自有可枚舉屬性(即其自身定義的屬性处嫌,而不是其原型鏈上的枚舉屬性)
    將為新創(chuàng)建的對象添加指定的屬性值和對應(yīng)的屬性描述符。

Object.create(proto斟湃,[propertiesObject])

2-2熏迹、基礎(chǔ)用法

let a = Object.create({b:1});
console.log(a);

我們會發(fā)現(xiàn)這個b屬性會在原型鏈上而不是本身的對象屬性上。


image.png

2-3凝赛、我們加上第二參數(shù)

當(dāng)然你要熟悉Object.defineProperty的用法

let a = Object.create({ a: "a" }, {
    b: {
        value: "b",
        writable : true
    },
    c: {
        value: "c",
        configurable:false
    },
    d: {
        enumerable:false,
        value: "d"
    }
})
console.log(a);
image.png

2-4注暗、思考題

const t1 = Object.create(null)
console.log(t1);

此時你會發(fā)現(xiàn)當(dāng)前這個t1連原型都沒有了

3、Object.defineProperty

我相信這個應(yīng)該有不少人都熟悉它哄酝,因為vue2.x的響應(yīng)式原理用的就是該屬性,當(dāng)然vue3.x已經(jīng)全面改成Proxy了,當(dāng)然這個不在本章節(jié)范圍內(nèi)祷膳。

3-1陶衅、語法

@param obj 要定義屬性的對象。
@param prop 要定義或修改的屬性的名稱直晨。
@descriptor 要定義或修改的屬性描述符搀军。
Object.defineProperty(obj, prop, descriptor)

3-2 、descriptor詳解

其實Object.defineProperty真正的靈魂就是descriptor這個參數(shù)了
該參數(shù)有六個屬性:
value:該屬性對應(yīng)的值勇皇。
configurable:該屬性是否可以被刪除,默認值為false罩句,不可被刪除
enumerable:該屬性是否可以被枚舉,默認值為false,不可被枚舉(也就是不能被循環(huán)遍歷到);想到這個應(yīng)該能想到Object.assign了吧
writable:該屬性是否可以被重新賦值敛摘,默認置為false,不可被改寫
get 屬性的 getter 函數(shù)门烂,如果沒有 getter,則為 undefined兄淫。當(dāng)訪問該屬性時屯远,會調(diào)用此函數(shù)。
set屬性的 setter 函數(shù)捕虽,如果沒有 setter慨丐,則為 undefined。當(dāng)屬性值被修改時泄私,會調(diào)用此函數(shù)房揭。

3-3、用法

要注意的是writable晌端、value不能和get捅暴、set方法同時出現(xiàn)

const t1 = Object.defineProperty({},"a",{
    value:"1",
    enumerable:true,//可枚舉
    configurable : true ,//可刪除
    writable : true,//可賦值
})
console.log(t1);
//有g(shù)et、set方法
let tValue = 1;
const t1 = Object.defineProperty({},"a",{
    enumerable:true,//可枚舉
    configurable : true ,//可刪除
    get(){
        return tValue
    },
    set(v){
        tValue = v
    }
})
console.log(t1);

3-4咧纠、面試題

請設(shè)計當(dāng)前程序讓它滿足一下的判斷條件
if(a === 1 && a=== 2 && a === 3){
  console.log("條件判斷正確");
  console.log(a)?
}
答案:
要想一個變量同時滿足三個條件常規(guī)操作肯定不行伶唯,我們知道每次訪問變量其實就是
調(diào)用了getter方法獲取這個值,二全局變量都在window對象上所以
let _a = 0;
Object.defineProperty(window,"a",{
  get (){
    return ++_a;
  }
})

為什么這樣就可以了惧盹?因為我們每次進行a變量比較都是在獲取這個a的值乳幸,但是我們的getter方法每次訪問都會加1.

4瞪讼、Object.entries

Object.entries意義:方法返回一個給定對象自身可枚舉屬性的鍵值對數(shù)組(白話就是,這個方法返回一個數(shù)組粹断,且每個數(shù)組元素就是該對象的key和value),請注意必須是一個可枚舉的屬性/方法才能轉(zhuǎn)換,但是它不會轉(zhuǎn)換原型上的屬性/方法

4-1符欠、用法

let a = {a:"1",b:"b",c:"測試"};
let r = Object.entries(a);
console.log(r);這是一個二維數(shù)組
image.png

4-2 、測試不能枚舉的屬性能否轉(zhuǎn)換

let a = Object.defineProperties({},{
    a:{
        value:1
    },
    b:{
        value : 2,
        enumerable:true
    },
    c:{
        value : 3,
        enumerable : true
    }
})
console.log(Object.entries(a));

會發(fā)現(xiàn)屬性a沒有在數(shù)組中

4-3瓶埋、將對象轉(zhuǎn)為map對象

let a = {a:1,b:2,c:3};
let b=  new Map(a);//直接轉(zhuǎn)換會報錯的希柿。
let b = new Map(Object.entries(a));//成功

4-4、測試原型上的屬性养筒、方法

function Test(){
  this.a = 1;
  this.b = 2
}
Test.prototype.c = 3;
Test.prototype.say=function(){}
console.log(Object.entries(new Test()));
for (let k in t) {
    console.log(k);雖然c和say能打印但是卻不能轉(zhuǎn)換
}

會發(fā)現(xiàn)c和say都不會出現(xiàn)在結(jié)果中

5曾撤、Object.fromEntries

其實這個方法就是Object.entries的對應(yīng)方法,一個是將對象轉(zhuǎn)為數(shù)組晕粪,一個將數(shù)組轉(zhuǎn)為json

5-1挤悉、用法

let a = [["a",1],["b",2],["c",3]]
console.log(Object.fromEntries(a));
//{a: 1, b: 2, c: 3}結(jié)果

5-2、將Map對象轉(zhuǎn)為json

let a = new Map();
a.set("a",1)
a.set("b",2)
a.set("c",3)
console.log(Object.fromEntries(a));

6巫湘、Object.freeze

Object.freeze凍結(jié)一個對象装悲,并且返回源對象(返回值和源對象是一個引用),且這個凍結(jié)是淺凍結(jié)尚氛。
什么叫凍結(jié)诀诊?也就是這個對象不可被操作了

6-1、用法

let a = { a: 1, b: 2, c: 3 };
Object.freeze(a)
a.a = 2//不可改
console.log(a);
a.d = 4;//不可增
console.log(a);
delete a.c;//不可刪
console.log(a);

6-2阅嘶、利用構(gòu)造函數(shù)的原型鏈改變值

function Test(){
    this.a = 1;
    this.b = 2;
}
Test.prototype.c = 3
let t= new Test();
Object.freeze(t)
t.c = 5//即使是實例原型上的屬性/或者方法也不能操作
console.log(t);
//我們改變構(gòu)造函數(shù)的值
Test.prototype.c = 100;
console.log(t.c);//發(fā)現(xiàn)是可以修改的

如果一個對象被凍結(jié)了属瓣,其原型鏈上的方法/屬性也不會被修改,但是可通過其構(gòu)造函數(shù)的原型進行操作讯柔。

6-3奠涌、為什么說Object.freeze是淺凍結(jié)?

function Test(){
    this.a = 1;
    this.b = 2;
    this.d = {
        d:"這是子對象"
    }
    this.e = ["a","b","c"]
}
Test.prototype.c = 3
let t= new Test();
//我們是不可以直接改變d的值
t.d = "d"
console.log(t);
//但是我們可以改變d屬性里面的值
t.d.d = "我改變了值"
console.log(t);確實被改變了

通過這個案例我們會發(fā)現(xiàn)Object.freeze它只會凍結(jié)源對象的屬性磷杏,但是他不會凍結(jié)源對象中的對象和數(shù)組

6-4溜畅、被凍結(jié)的對象屬性即使通過getter/setter方法也不能被修改刪除

let a = { _a: 1, b: 2, get a() { 
    return this._a;
}, set a(v) { 
    this._a = v;
} }
Object.freeze(a)
a.a = 3;//a屬性并不會改變包括_a
console.log(a);

6-5、編寫深凍結(jié)方法

Object.deepFreeze = function (obj) {
    //let keys = Object.keys(obj);
    //注意Object.keys拿不到不可枚舉的key而getOwnPropertyNames能拿到
    let keys = Object.getOwnPropertyNames(obj);
    keys.forEach(k => {
        if (typeof obj[k] === "object" && obj[k] != null) {
            Object.deepFreeze(obj[k])
        }
    })
    return Object.freeze(obj);
}

7极祸、Object.isFrozen

Object.isFrozen判斷一個對象是否被凍結(jié)

7-1慈格、判斷Object.freeze到底是不是淺凍結(jié)

let a = {
    a:1,
    b:2,
    c:{
        c:3,
        d:4
    }
}
Object.freeze(a);
console.log(Object.isFrozen(a.c))//false
Object.freeze(a.c);
console.log(Object.isFrozen(a.c))//true

8、Object.seal遥金、Object.isSealed

Object.seal封閉對象它和Object.freeze差不多浴捆,但是它是可以修改值得

let a = {
    a:1,
    b:2,
}
Object.prototype.c = 3;
Object.seal(a)
a.d = 5;//不可增加
delete a.a//不可刪除
a.b = 100;//可以修改
a.__proto__.c = 333;//可以修改 
console.log(a);

8-1、為什么說Object.seal是淺封閉稿械?

let a = {
    a:1,
    b:2,
    c:{
        c:3
    }
}
a.__proto__.d = 4;
Object.seal(a);
//為true
console.log(Object.isSealed(a));
//為false
console.log(Object.isSealed(a.c));
a.c.d = 5;
console.log(a.c);//比沒有添加d屬性
Object.seal(a.c);
//為true
console.log(Object.isSealed(a.c));

8-2选泻、編寫深封閉

Object.deepSeal = function (obj) {
    //let keys = Object.keys(obj);
    //注意Object.keys拿不到不可枚舉的key而getOwnPropertyNames能拿到
    let keys = Object.getOwnPropertyNames(obj);
    keys.forEach(k => {
        if (typeof obj[k] === "object" && obj[k] != null) {
            Object.deepSeal (obj[k])
        }
    })
    return Object.seal(obj);
}

9、Object.preventExtensions

Object.preventExtensions方法讓一個對象變的不可擴展,也就是永遠不能再添加新的屬性页眯。

let a = {};
Object.preventExtensions(a)
a.a = 1;
a.__proto__.b = 2;//增加原型鏈上的屬性是可行的梯捕,但是切記不要這樣做,你會發(fā)現(xiàn)新的對象上也會有該屬性
console.log(a);
let b = {}
consoole.log(b) b屬性也會存在的

10窝撵、總結(jié)Object.freeze傀顾、Object.seal、Object.preventExtensions;

Object.freeze:凍結(jié)對象碌奉。不可修改短曾、不可刪除、不可擴展
Object.seal:封閉對象赐劣〖倒眨可修改、不可刪除魁兼、不可擴展
Object.preventExtensions:禁止擴展對象婉徘。可修改璃赡、可刪除判哥、不可擴展

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末献雅,一起剝皮案震驚了整個濱河市碉考,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挺身,老刑警劉巖侯谁,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異章钾,居然都是意外死亡墙贱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門贱傀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惨撇,“玉大人,你說我怎么就攤上這事府寒】茫” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵株搔,是天一觀的道長剖淀。 經(jīng)常有香客問我,道長纤房,這世上最難降的妖魔是什么纵隔? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上捌刮,老公的妹妹穿的比我還像新娘碰煌。我一直安慰自己,他們只是感情好糊啡,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布拄查。 她就那樣靜靜地躺著,像睡著了一般棚蓄。 火紅的嫁衣襯著肌膚如雪堕扶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天梭依,我揣著相機與錄音稍算,去河邊找鬼。 笑死役拴,一個胖子當(dāng)著我的面吹牛糊探,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播河闰,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼科平,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了姜性?” 一聲冷哼從身側(cè)響起瞪慧,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎部念,沒想到半個月后弃酌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡儡炼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年妓湘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乌询。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡榜贴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出妹田,到底是詐尸還是另有隱情唬党,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布秆麸,位于F島的核電站初嘹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏沮趣。R本人自食惡果不足惜屯烦,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驻龟,春花似錦温眉、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至露懒,卻和暖如春闯冷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背懈词。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工蛇耀, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人坎弯。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓纺涤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親抠忘。 傳聞我的和親對象是個殘疾皇子撩炊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

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