JavaScript對象的屬性訪問與復(fù)制

很多時候我們需要復(fù)制目標(biāo)對象而非借助原型鏈訪問,比如對象拷貝掰读、各類繼承方法汪诉,這里總結(jié)下Js的屬性訪問方法以及注意事項

可以根據(jù)是否在原型鏈上與可枚舉來區(qū)分:
獲取對象直接包含的屬性的方法:

Object.keys(obj)  //返回可枚舉屬性 字符串?dāng)?shù)組
Object.entries(obj)  //返回可以枚舉屬性 鍵值對數(shù)組
Object.getOwnPropertyNames(obj)
Object.getOwnPropertySymbols(obj)
Object.getOwnPropertyDescriptors(obj)
Object.getOwnPropertyDescriptor(obj,prop)

不僅返回自身屬性,還能訪問原型鏈上屬性的只有一個方法(語句)

for..in  //遍歷對象可枚舉屬性列表

需要注意這些方法的返回值:Object.entries(...)不僅返回屬性還返回值括儒,組成鍵值對茧痒,Object.getOwnPropertyDescriptor(obj,prop)需要對象以及具體的屬性值肮韧,返回整個property descriptor對象,Object.getOwnPropertyDescriptors(...)返回一個property descriptor對象數(shù)組旺订。

比較符合使用習(xí)慣的是Object.keys(...)Object.getOwnPropertyNames(...)弄企,通過返回的代表屬性的字符串來進行某種操作。

涉及到具體的描述区拳,比如訪問器屬性拘领,就需要Object.getOwnPropertyDescriptors(...)這類方法

除去訪問方法,另外還有對應(yīng)的檢測方法(運算符)樱调,檢測存在性约素,均返回布爾值:

in
obj.hasOwnProperty(prop) //Object?.prototype?.has?OwnProperty(...)
obj.propertyIsEnumerable(prop) //Object?.prototype?.property?IsEnumerable(...)

我們可以對比這些方法來記憶:

for..inobj.propertyIsEnumerable(prop)Object.keys(obj): 針對可枚舉屬性笆凌,前者查找原型鏈
inobj.hasOwnProperty(prop):針對所有屬性(包括Symbol)圣猎,前者查找原型鏈
obj.hasOwnProperty(prop)Object.getOwnPropertyNames(obj):針對自身屬性,前者可用于屬性值為Symbol的情況乞而,而后者需要同類方法Object.getOwnPropertySymbols(obj)

在用這些方法進行訪問送悔、取值之前,還有兩個重要的方法需要介紹:

Object.assign(target, ...sources)
Object.create(proto, [propertiesObject])

兩個方法都創(chuàng)建了對象:assign將可枚舉屬性的值復(fù)制到target爪模,繼承屬性和不可枚舉屬性是不能拷貝的欠啤,source為多個對象時,相同屬性會被后續(xù)對象合并屋灌;create創(chuàng)建指定原型鏈的對象洁段,第二個參數(shù)指定可枚舉屬性。

可以開始操作了:

function MyClass() {
     SuperClass.call(this);
     OtherSuperClass.call(this);
}

// 繼承一個類
MyClass.prototype = Object.create(SuperClass.prototype);
// 混合其它
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// 重新指定constructor
MyClass.prototype.constructor = MyClass;

MyClass.prototype.myMethod = function() {
     // do a thing
};

上面是MDN里關(guān)于混入的例子共郭,實際上拷貝或者繼承的用法核心便是如此祠丝,借用或者拷貝屬性,具體一點可以是這樣:

function copy(target, source, overlay) {
    for (var key in source) {
        if (source.hasOwnProperty(key)
            && (overlay ? source[key] != null : target[key] == null)
        ) {
            target[key] = source[key];
        }
    }
    return target;
}
function mixin(target, source) {
    for (var key in source) {
        if (!(var key in target)) {
            target[key] = source[key];
        }
    }
    return target;
}

通過for.. in語句 獲得可枚舉屬性落塑,并篩選出直接屬性纽疟,當(dāng)然透過target[key] = source[key];也清楚這和Object.assign()一樣只能淺拷貝罐韩。
或者更具體的繼承用法:

function inherits(clazz, baseClazz) {
    var clazzPrototype = clazz.prototype;
    function F() {}
    F.prototype = baseClazz.prototype;
    clazz.prototype = new F();
    // clazz.prototype = Object.create(baseClazz.prototype)
    for (var prop in clazzPrototype) {
        clazz.prototype[prop] = clazzPrototype[prop];
    }
    clazz.prototype.constructor = clazz;
    clazz.superClass = baseClazz;
}

是否把基類原型鏈上的方法拷貝過來憾赁、是否覆蓋、是否只往上追溯一層原型鏈這些都視具體的應(yīng)用場景而定散吵。inherits會傾向于繼承關(guān)系(保持原型鏈的聯(lián)系)龙考,copy用于混入某些屬性(組合)蟆肆。

接下來總結(jié)一些注意事項
參考MDN上的分類,有這些容易忽略的情況:屬性是否為訪問描述符晦款,原始類型包裝炎功,原生方法覆蓋,以及異常處理是否中斷執(zhí)行缓溅。

1.Object.assign()使用了方法使用源對象的[[Get]]和目標(biāo)對象的[[Set]]蛇损,所以源對象的屬性為訪問器的話,只能獲得[[Get]]的值坛怪,如果要完整拷貝需要結(jié)合Object.getOwnPropertyDescriptor()Object.defineProperty()

2.Object.assign()的source參數(shù)可以是基本值淤齐,基本值會封裝為對象,null 和 undefined 會被忽略袜匿,并且只有字符串的包裝對象才可能有自身可枚舉屬性更啄。

  1. 數(shù)據(jù)描述符與訪問描述符的enumerable屬性默認(rèn)為 false。如果使用直接賦值的方式創(chuàng)建對象的屬性居灯,則這個屬性的enumerable為true祭务,這是相對于Object.defineProperty(...)方法而言,比如
const obj = {
  foo: 1,
  get bar() {
    return 2;
  }
};//"foo"與"bar"均可枚舉可配置
var o = {};
Object.defineProperty(o, "a", { value : 1 });
//"a"不可枚舉不可寫不可配置
  1. 原生方法可能被自定義的同名函數(shù)覆蓋怪嫌,這時候可以直接使用切換上下文的原生方法
var foo = {
    hasOwnProperty: function() {
        return false;
    },
    bar: 'Here be dragons'
};

({}).hasOwnProperty.call(foo, 'bar'); // true

// 也可以使用 Object 原型上的 hasOwnProperty 屬性
Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
  1. Object.assign 不會跳過那些nullundefined的源對象义锥,在出現(xiàn)錯誤的情況下,例如岩灭,如果屬性不可寫缨该,會引發(fā)TypeError,如果在引發(fā)錯誤之前添加了任何屬性川背,則可以更改target對象贰拿。Object.create如果propertiesObject參數(shù)是 null 或非原始包裝對象,同樣拋出一個TypeError熄云。

6.拷貝中常見等號賦值的操作如target[key] = source[key]膨更,clazz.prototype[prop] = clazzPrototype[prop],這個表達式同時有[[Get]]和[[Put]]的操作缴允,需要注意屬性設(shè)置[[Put]]可能發(fā)生屏蔽的狀況:如果target本來就具有key屬性荚守,那么賦值語句只是修改;如果沒有练般,就在其[[Prototype]]上尋找對應(yīng)key矗漾,①找到并且key為可寫的話,target會新增屏蔽屬性薄料,如果只讀則會被忽略(嚴(yán)格模式下報錯)敞贡,②key為setter,那么target不會新增key屬性摄职,只是會調(diào)用setter誊役。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末获列,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蛔垢,更是在濱河造成了極大的恐慌击孩,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鹏漆,死亡現(xiàn)場離奇詭異巩梢,居然都是意外死亡,警方通過查閱死者的電腦和手機艺玲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門且改,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人板驳,你說我怎么就攤上這事又跛。” “怎么了若治?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵慨蓝,是天一觀的道長。 經(jīng)常有香客問我端幼,道長礼烈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任婆跑,我火速辦了婚禮此熬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘滑进。我一直安慰自己犀忱,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布扶关。 她就那樣靜靜地躺著阴汇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪节槐。 梳的紋絲不亂的頭發(fā)上搀庶,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音铜异,去河邊找鬼哥倔。 笑死,一個胖子當(dāng)著我的面吹牛揍庄,可吹牛的內(nèi)容都是我干的咆蒿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼蜡秽!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缆镣,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤芽突,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后董瞻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體寞蚌,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年钠糊,在試婚紗的時候發(fā)現(xiàn)自己被綠了挟秤。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡抄伍,死狀恐怖艘刚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情截珍,我是刑警寧澤攀甚,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站岗喉,受9級特大地震影響秋度,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钱床,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一荚斯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧查牌,春花似錦事期、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至懂衩,卻和暖如春撞叨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背浊洞。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工牵敷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人法希。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓枷餐,卻偏偏與公主長得像,于是被迫代替她去往敵國和親苫亦。 傳聞我的和親對象是個殘疾皇子毛肋,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

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