ES6入門標(biāo)準(zhǔn)讀書筆記8(對象的擴(kuò)展)

1.屬性的簡潔表示法

ES6 允許直接寫入變量和函數(shù)佃扼,作為對象的屬性和方法。這樣的書寫更加簡潔连锯。

const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};

除了屬性簡寫撮竿,方法也可以簡寫泉手。

const o = {
? method() {
? ? return "Hello!";
? }
};
// 等同于
const o = {
? method: function() {
? ? return "Hello!";
? }
};

4.Object.is()

ES5 比較兩個(gè)值是否相等铣口,只有兩個(gè)運(yùn)算符:相等運(yùn)算符(==)和嚴(yán)格相等運(yùn)算符(===)滤钱。它們都有缺點(diǎn),前者會(huì)自動(dòng)轉(zhuǎn)換數(shù)據(jù)類型枷踏,后者的NaN不等于自身,以及+0等于-0掰曾。JavaScript 缺乏一種運(yùn)算旭蠕,在所有環(huán)境中,只要兩個(gè)值是一樣的旷坦,它們就應(yīng)該相等掏熬。

它用來比較兩個(gè)值是否嚴(yán)格相等,與嚴(yán)格比較運(yùn)算符(===)的行為基本一致秒梅。

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

不同之處只有兩個(gè):一是+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
});

5.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方法的第一個(gè)參數(shù)是目標(biāo)對象,后面的參數(shù)都是源對象锰茉。

注意呢蔫,如果目標(biāo)對象與源對象有同名屬性,或多個(gè)源對象有同名屬性飒筑,則后面的屬性會(huì)覆蓋前面的屬性片吊。

如果該參數(shù)不是對象绽昏,則會(huì)先轉(zhuǎn)成對象,然后返回俏脊。

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

由于undefined和null無法轉(zhuǎn)成對象全谤,所以如果它們作為參數(shù),就會(huì)報(bào)錯(cuò)联予。

Object.assign(undefined) // 報(bào)錯(cuò)
Object.assign(null) // 報(bào)錯(cuò)

如果非對象參數(shù)出現(xiàn)在源對象的位置(即非首參數(shù))啼县,那么處理規(guī)則有所不同。首先沸久,這些參數(shù)都會(huì)轉(zhuǎn)成對象季眷,如果無法轉(zhuǎn)成對象,就會(huì)跳過卷胯。這意味著子刮,如果undefined和null不在首參數(shù),就不會(huì)報(bào)錯(cuò)窑睁。

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

其他類型的值(即數(shù)值挺峡、字符串和布爾值)不在首參數(shù),也不會(huì)報(bào)錯(cuò)担钮。但是橱赠,除了字符串會(huì)以數(shù)組形式,拷貝入目標(biāo)對象箫津,其他值都不會(huì)產(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ù)值和布爾值都會(huì)被忽略。這是因?yàn)橹挥凶址陌b對象教硫,會(huì)產(chǎn)生可枚舉屬性叨吮。

注意點(diǎn) § ?

(1)淺拷貝

Object.assign方法實(shí)行的是淺拷貝,而不是深拷貝瞬矩。也就是說挤安,如果源對象某個(gè)屬性的值是對象,那么目標(biāo)對象拷貝得到的是這個(gè)對象的引用丧鸯。

const obj1 = {a: {b: 1}};

const obj2 = Object.assign({}, obj1);

obj1.a.b = 2;

obj2.a.b // 2

上面代碼中蛤铜,源對象obj1的a屬性的值是一個(gè)對象,Object.assign拷貝得到的是這個(gè)對象的引用。這個(gè)對象的任何變化围肥,都會(huì)反映到目標(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屬性整個(gè)替換掉了榜轿,而不會(huì)得到{ a: { b: 'hello', d: 'e' } }的結(jié)果。這通常不是開發(fā)者想要的朵锣,需要特別小心谬盐。

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

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

Object.assign可以用來處理數(shù)組飞傀,但是會(huì)把數(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ù)制的值是一個(gè)取值函數(shù)家破,那么將求值后再復(fù)制颜说。

const source = {
? get foo() { return 1 }
};
const target = {};
Object.assign(target, source)
// { foo: 1 }

上面代碼中,source對象的foo屬性是一個(gè)取值函數(shù)员舵,Object.assign不會(huì)復(fù)制這個(gè)取值函數(shù)脑沿,只會(huì)拿到值以后藕畔,將這個(gè)值復(fù)制過去马僻。


常見用途 § ?

Object.assign方法有很多用處。

(1)為對象添加屬性

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

上面方法通過Object.assign方法注服,將x屬性和y屬性添加到Point類的對象實(shí)例韭邓。

(2)為對象添加方法

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

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

(3)克隆對象

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

上面代碼將原始對象拷貝到一個(gè)空對象,就得到了原始對象的克隆辜御。

不過鸭你,采用這種方法克隆,只能克隆原始對象自身的值,不能克隆它繼承的值袱巨。如果想要保持繼承鏈阁谆,可以采用下面的代碼。

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

(4)合并多個(gè)對象

將多個(gè)對象合并到某個(gè)對象愉老。

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

如果希望合并后返回一個(gè)新對象场绿,可以改寫上面函數(shù),對一個(gè)空對象合并嫉入。

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方法將DEFAULTS和options合并成一個(gè)新對象熬拒,如果兩者有同名屬性,則option的屬性值會(huì)覆蓋DEFAULTS的屬性值映九。

注意梦湘,由于存在淺拷貝的問題,DEFAULTS對象和options對象的所有屬性的值件甥,最好都是簡單類型捌议,不要指向另一個(gè)對象。否則引有,DEFAULTS對象的該屬性很可能不起作用瓣颅。

const DEFAULTS = {
? url: {
? ? host: 'example.com',
? ? port: 7070
? },
};
processContent({ url: {port: 8000} })
// {
//? url: {port: 8000}
// }

上面代碼的原意是將url.port改成 8000,url.host不變譬正。實(shí)際結(jié)果卻是options.url覆蓋掉DEFAULTS.url宫补,所以url.host就不存在了。

Object.setPrototypeOf()

Object.setPrototypeOf方法的作用與__proto__相同曾我,用來設(shè)置一個(gè)對象的prototype對象粉怕,返回參數(shù)對象本身。它是 ES6 正式推薦的設(shè)置原型對象的方法抒巢。

// 格式
Object.setPrototypeOf(object, prototype)
// 用法
const o = Object.setPrototypeOf({}, null);

該方法等同于下面的函數(shù)贫贝。

function (obj, proto) {
? obj.__proto__ = proto;
? return obj;
}

下面是一個(gè)例子。

let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);
proto.y = 20;
proto.z = 40;
obj.x // 10
obj.y // 20
obj.z // 40

上面代碼將proto對象設(shè)為obj對象的原型蛉谜,所以從obj對象可以讀取proto對象的屬性稚晚。

9.super 關(guān)鍵字 § ?

我們知道,this關(guān)鍵字總是指向函數(shù)所在的當(dāng)前對象型诚,ES6 又新增了另一個(gè)類似的關(guān)鍵字super客燕,指向當(dāng)前對象的原型對象。

const proto = {
? foo: 'hello'
};
const obj = {
? foo: 'world',
? find() {
? ? return super.foo;
? }
};
Object.setPrototypeOf(obj, proto);
obj.find() // "hello"

上面代碼中狰贯,對象obj的find方法之中也搓,通過super.foo引用了原型對象proto的foo屬性赏廓。

注意,super關(guān)鍵字表示原型對象時(shí)傍妒,只能用在對象的方法之中楚昭,用在其他地方都會(huì)報(bào)錯(cuò)。

Object.keys()拍顷,Object.values()抚太,Object.entries()

都返回一個(gè)數(shù)組

ES2017 引入了跟Object.keys配套的Object.values和Object.entries,作為遍歷一個(gè)對象的補(bǔ)充手段昔案,供for...of循環(huán)使用尿贫。

let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
? console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
? console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
? console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}

Object.keys() § ?

ES5 引入了Object.keys方法,返回一個(gè)數(shù)組踏揣,成員是參數(shù)對象自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵名庆亡。

var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]

Object.values() § ?

Object.values方法返回一個(gè)數(shù)組,成員是參數(shù)對象自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值捞稿。

const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]

Object.entries § ?

Object.entries方法返回一個(gè)數(shù)組又谋,成員是參數(shù)對象自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值對數(shù)組。

const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]

11.對象的擴(kuò)展運(yùn)算符

《數(shù)組的擴(kuò)展》一章中娱局,已經(jīng)介紹過擴(kuò)展運(yùn)算符(...)彰亥。

const [a, ...b] = [1, 2, 3];
a // 1
b // [2, 3]

ES2018 將這個(gè)運(yùn)算符引入了對象。

解構(gòu)賦值

對象的解構(gòu)賦值用于從一個(gè)對象取值衰齐,相當(dāng)于將目標(biāo)對象自身的所有可遍歷的(enumerable)任斋、但尚未被讀取的屬性,分配到指定的對象上面耻涛。所有的鍵和它們的值废酷,都會(huì)拷貝到新對象上面。

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

上面代碼中抹缕,變量z是解構(gòu)賦值所在的對象澈蟆。它獲取等號右邊的所有尚未讀取的鍵(a和b),將它們連同值一起拷貝過來卓研。

由于解構(gòu)賦值要求等號右邊是一個(gè)對象趴俘,所以如果等號右邊是undefined或null,就會(huì)報(bào)錯(cuò)鉴分,因?yàn)樗鼈儫o法轉(zhuǎn)為對象哮幢。

let { x, y, ...z } = null; // 運(yùn)行時(shí)錯(cuò)誤
let { x, y, ...z } = undefined; // 運(yùn)行時(shí)錯(cuò)誤

解構(gòu)賦值必須是最后一個(gè)參數(shù)带膀,否則會(huì)報(bào)錯(cuò)志珍。

let { ...x, y, z } = obj; // 句法錯(cuò)誤
let { x, ...y, ...z } = obj; // 句法錯(cuò)誤

上面代碼中,解構(gòu)賦值不是最后一個(gè)參數(shù)垛叨,所以會(huì)報(bào)錯(cuò)伦糯。

注意柜某,解構(gòu)賦值的拷貝是淺拷貝,即如果一個(gè)鍵的值是復(fù)合類型的值(數(shù)組敛纲、對象喂击、函數(shù))、那么解構(gòu)賦值拷貝的是這個(gè)值的引用淤翔,而不是這個(gè)值的副本翰绊。

let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市旁壮,隨后出現(xiàn)的幾起案子监嗜,更是在濱河造成了極大的恐慌,老刑警劉巖抡谐,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件裁奇,死亡現(xiàn)場離奇詭異,居然都是意外死亡麦撵,警方通過查閱死者的電腦和手機(jī)刽肠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來免胃,“玉大人音五,你說我怎么就攤上這事「嵘常” “怎么了放仗?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長撬碟。 經(jīng)常有香客問我诞挨,道長,這世上最難降的妖魔是什么呢蛤? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任惶傻,我火速辦了婚禮,結(jié)果婚禮上其障,老公的妹妹穿的比我還像新娘银室。我一直安慰自己,他們只是感情好励翼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布蜈敢。 她就那樣靜靜地躺著,像睡著了一般汽抚。 火紅的嫁衣襯著肌膚如雪抓狭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天造烁,我揣著相機(jī)與錄音否过,去河邊找鬼午笛。 笑死,一個(gè)胖子當(dāng)著我的面吹牛苗桂,可吹牛的內(nèi)容都是我干的药磺。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼煤伟,長吁一口氣:“原來是場噩夢啊……” “哼癌佩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起便锨,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤驼卖,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后鸿秆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酌畜,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年卿叽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了桥胞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡考婴,死狀恐怖贩虾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情沥阱,我是刑警寧澤缎罢,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站考杉,受9級特大地震影響策精,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜崇棠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一咽袜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧枕稀,春花似錦询刹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至哆档,卻和暖如春蔽挠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背虐呻。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工象泵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斟叼。 一個(gè)月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓偶惠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親朗涩。 傳聞我的和親對象是個(gè)殘疾皇子忽孽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

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