ES6對象的新增方法

Object.is()
Object.assign()

1.Object.is()

ES5 比較兩個值是否相等,只有兩個運算符:相等運算符(==)和嚴(yán)格相等運算符(===)。它們都有缺點,前者會自動轉(zhuǎn)換數(shù)據(jù)類型封断,后者的NaN不等于自身捡鱼,以及+0等于-0们何。JavaScript 缺乏一種運算岩遗,在所有環(huán)境中扇商,只要兩個值是一樣的,它們就應(yīng)該相等宿礁。

ES6 提出“Same-value equality”(同值相等)算法案铺,用來解決這個問題。Object.is就是部署這個算法的新方法梆靖。它用來比較兩個值是否嚴(yán)格相等控汉,與嚴(yán)格比較運算符(===)的行為基本一致。

Object.is('foo', 'foo')
// true
Object.is({}, {})
// false

不同之處只有兩個:一是+0不等于-0返吻,二是NaN等于自身姑子。

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

ES5 可以通過下面的代碼,部署Object.is测僵。

Object.defineProperty(Object, 'is', {
  value: function(x, y) {
    if (x === y) {
      // 針對+0 不等于 -0的情況
      return x !== 0 || 1 / x === 1 / y;
    }
    // 針對NaN的情況
    return x !== x && y !== y;
  },
  configurable: true,
  enumerable: false,
  writable: true
});

2.Object.assign()

基本用法

Object.assign()方法用于對象的合并街佑,將源對象(source)的所有可枚舉屬性,復(fù)制到目標(biāo)對象(target)捍靠。

const target = { a: 1 };

const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

Object.assign()方法的第一個參數(shù)是目標(biāo)對象舆乔,后面的參數(shù)都是源對象。

注意剂公,如果目標(biāo)對象與源對象有同名屬性希俩,或多個源對象有同名屬性,則后面的屬性會覆蓋前面的屬性纲辽。

const target = { a: 1, b: 1 };

const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

如果只有一個參數(shù)颜武,Object.assign()會直接返回該參數(shù)。

const obj = {a: 1};
Object.assign(obj) === obj // true

如果該參數(shù)不是對象拖吼,則會先轉(zhuǎn)成對象鳞上,然后返回。

typeof Object.assign(2) // "object"

由于undefinednull無法轉(zhuǎn)成對象吊档,所以如果它們作為參數(shù)篙议,就會報錯。

Object.assign(undefined) // 報錯
Object.assign(null) // 報錯

如果非對象參數(shù)出現(xiàn)在源對象的位置(即非首參數(shù))怠硼,那么處理規(guī)則有所不同鬼贱。首先,這些參數(shù)都會轉(zhuǎn)成對象香璃,如果無法轉(zhuǎn)成對象这难,就會跳過。這意味著葡秒,如果undefinednull不在首參數(shù)姻乓,就不會報錯嵌溢。

let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true

其他類型的值(即數(shù)值、字符串和布爾值)不在首參數(shù)蹋岩,也不會報錯赖草。但是,除了字符串會以數(shù)組形式剪个,拷貝入目標(biāo)對象秧骑,其他值都不會產(chǎn)生效果。

const v1 = 'abc';
const v2 = true;
const v3 = 10;

const obj = Object.assign({}, v1, v2, v3);
console.log(obj); // { "0": "a", "1": "b", "2": "c" }

上面代碼中禁偎,v1腿堤、v2阀坏、v3分別是字符串如暖、布爾值和數(shù)值,結(jié)果只有字符串合入目標(biāo)對象(以字符數(shù)組的形式)忌堂,數(shù)值和布爾值都會被忽略盒至。這是因為只有字符串的包裝對象,會產(chǎn)生可枚舉屬性士修。

Object(true) // {[[PrimitiveValue]]: true}
Object(10)  //  {[[PrimitiveValue]]: 10}
Object('abc') // {0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}

上面代碼中枷遂,布爾值、數(shù)值棋嘲、字符串分別轉(zhuǎn)成對應(yīng)的包裝對象酒唉,可以看到它們的原始值都在包裝對象的內(nèi)部屬性[[PrimitiveValue]]上面,這個屬性是不會被Object.assign()拷貝的沸移。只有字符串的包裝對象痪伦,會產(chǎn)生可枚舉的實義屬性,那些屬性則會被拷貝雹锣。

Object.assign()拷貝的屬性是有限制的网沾,只拷貝源對象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性(enumerable: false)蕊爵。

Object.assign({b: 'c'},
  Object.defineProperty({}, 'invisible', {
    enumerable: false,
    value: 'hello'
  })
)
// { b: 'c' }

上面代碼中辉哥,Object.assign()要拷貝的對象只有一個不可枚舉屬性invisible,這個屬性并沒有被拷貝進(jìn)去攒射。

屬性名為 Symbol 值的屬性醋旦,也會被Object.assign()拷貝。

Object.assign({ a: 'b' }, { [Symbol('c')]: 'd' })
// { a: 'b', Symbol(c): 'd' }

注意點

(1)淺拷貝

Object.assign()方法實行的是淺拷貝会放,而不是深拷貝浑度。也就是說,如果源對象某個屬性的值是對象鸦概,那么目標(biāo)對象拷貝得到的是這個對象的引用箩张。

const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);

obj1.a.b = 2;
obj2.a.b // 2

上面代碼中甩骏,源對象obj1a屬性的值是一個對象,Object.assign()拷貝得到的是這個對象的引用先慷。這個對象的任何變化饮笛,都會反映到目標(biāo)對象上面。

(2)同名屬性的替換

對于這種嵌套的對象论熙,一旦遇到同名屬性福青,Object.assign()的處理方法是替換,而不是添加脓诡。

const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }

上面代碼中无午,target對象的a屬性被source對象的a屬性整個替換掉了,而不會得到{ a: { b: 'hello', d: 'e' } }的結(jié)果祝谚。這通常不是開發(fā)者想要的宪迟,需要特別小心。

一些函數(shù)庫提供Object.assign()的定制版本(比如 Lodash_.defaultsDeep()方法)交惯,可以得到深拷貝的合并次泽。

(3)數(shù)組的處理

Object.assign()可以用來處理數(shù)組,但是會把數(shù)組視為對象席爽。

Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]

上面代碼中意荤,Object.assign()把數(shù)組視為屬性名為 0、1只锻、2 的對象玖像,因此源數(shù)組的 0 號屬性4覆蓋了目標(biāo)數(shù)組的 0 號屬性1

(4)取值函數(shù)的處理

Object.assign()只能進(jìn)行值的復(fù)制齐饮,如果要復(fù)制的值是一個取值函數(shù)捐寥,那么將求值后再復(fù)制。

const source = {
  get foo() { return 1 }
};
const target = {};

Object.assign(target, source)
// { foo: 1 }

上面代碼中沈矿,source對象的foo屬性是一個取值函數(shù)上真,Object.assign()不會復(fù)制這個取值函數(shù),只會拿到值以后羹膳,將這個值復(fù)制過去睡互。

常見用途

Object.assign()方法有很多用處。

(1)為對象添加屬性

class Point {
  constructor(x, y) {
    Object.assign(this, {x, y});
  }
}

上面方法通過Object.assign()方法陵像,將x屬性和y屬性添加到Point類的對象實例就珠。

2)為對象添加方法

Object.assign(SomeClass.prototype, {
  someMethod(arg1, arg2) {
    ···
  },
  anotherMethod() {
    ···
  }
});

// 等同于下面的寫法
SomeClass.prototype.someMethod = function (arg1, arg2) {
  ···
};
SomeClass.prototype.anotherMethod = function () {
  ···
};

上面代碼使用了對象屬性的簡潔表示法,直接將兩個函數(shù)放在大括號中醒颖,再使用assign()方法添加到SomeClass.prototype之中妻怎。

(3)克隆對象

function clone(origin) {
  return Object.assign({}, origin);
}

上面代碼將原始對象拷貝到一個空對象,就得到了原始對象的克隆泞歉。

不過逼侦,采用這種方法克隆匿辩,只能克隆原始對象自身的值,不能克隆它繼承的值榛丢。如果想要保持繼承鏈铲球,可以采用下面的代碼。

function clone(origin) {
  let originProto = Object.getPrototypeOf(origin);
  return Object.assign(Object.create(originProto), origin);
}

(4)合并多個對象

將多個對象合并到某個對象晰赞。

const merge =
  (target, ...sources) => Object.assign(target, ...sources);

如果希望合并后返回一個新對象稼病,可以改寫上面函數(shù),對一個空對象合并掖鱼。

const merge =
  (...sources) => Object.assign({}, ...sources);

(5)為屬性指定默認(rèn)值

const DEFAULTS = {
  logLevel: 0,
  outputFormat: 'html'
};

function processContent(options) {
  options = Object.assign({}, DEFAULTS, options);
  console.log(options);
  // ...
}

上面代碼中然走,DEFAULTS對象是默認(rèn)值,options對象是用戶提供的參數(shù)戏挡。Object.assign()方法將DEFAULTSoptions合并成一個新對象芍瑞,如果兩者有同名屬性,則options的屬性值會覆蓋DEFAULTS的屬性值增拥。

注意啄巧,由于存在淺拷貝的問題寻歧,DEFAULTS對象和options對象的所有屬性的值掌栅,最好都是簡單類型,不要指向另一個對象码泛。否則猾封,DEFAULTS對象的該屬性很可能不起作用。

const DEFAULTS = {
  url: {
    host: 'example.com',
    port: 7070
  },
};

processContent({ url: {port: 8000} })
// {
//   url: {port: 8000}
// }

上面代碼的原意是將url.port改成8000噪珊,url.host不變晌缘。實際結(jié)果卻是options.url覆蓋掉DEFAULTS.url,所以url.host就不存在了痢站。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末磷箕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子阵难,更是在濱河造成了極大的恐慌岳枷,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件呜叫,死亡現(xiàn)場離奇詭異空繁,居然都是意外死亡,警方通過查閱死者的電腦和手機朱庆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門盛泡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人娱颊,你說我怎么就攤上這事傲诵】常” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵拴竹,是天一觀的道長果覆。 經(jīng)常有香客問我,道長殖熟,這世上最難降的妖魔是什么局待? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮菱属,結(jié)果婚禮上钳榨,老公的妹妹穿的比我還像新娘。我一直安慰自己纽门,他們只是感情好薛耻,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赏陵,像睡著了一般饼齿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝙搔,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天缕溉,我揣著相機與錄音,去河邊找鬼吃型。 笑死证鸥,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的勤晚。 我是一名探鬼主播枉层,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赐写!你這毒婦竟也來了鸟蜡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤挺邀,失蹤者是張志新(化名)和其女友劉穎揉忘,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悠夯,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡癌淮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了沦补。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乳蓄。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖夕膀,靈堂內(nèi)的尸體忽然破棺而出虚倒,到底是詐尸還是另有隱情美侦,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布魂奥,位于F島的核電站菠剩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏耻煤。R本人自食惡果不足惜具壮,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哈蝇。 院中可真熱鬧棺妓,春花似錦、人聲如沸炮赦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吠勘。三九已至性芬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間剧防,已是汗流浹背植锉。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诵姜,地道東北人汽煮。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓搏熄,卻偏偏與公主長得像棚唆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子心例,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355