ES6 對象的新增方法

2020-06-11 11:24 更新

1. Object.is()

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

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

  1. Object.is('foo', 'foo')
  2. // true
  3. Object.is({}, {})
  4. // false

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

  1. +0 === -0 //true
  2. NaN === NaN // false
  3. Object.is(+0, -0) // false
  4. Object.is(NaN, NaN) // true

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

  1. Object.defineProperty(Object, 'is', {
  2. value: function(x, y) {
  3. if (x === y) {
  4. // 針對+0 不等于 -0的情況
  5. return x !== 0 || 1 / x === 1 / y;
  6. }
  7. // 針對NaN的情況
  8. return x !== x && y !== y;
  9. },
  10. configurable: true,
  11. enumerable: false,
  12. writable: true
  13. });

2. Object.assign()

基本用法

Object.assign方法用于對象的合并,將源對象(source)的所有可枚舉屬性,復制到目標對象(target)。

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

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

注意,如果目標對象與源對象有同名屬性,或多個源對象有同名屬性,則后面的屬性會覆蓋前面的屬性。

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

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

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

如果該參數(shù)不是對象,則會先轉成對象,然后返回。

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

由于 undefined 和 null 無法轉成對象,所以如果它們作為參數(shù),就會報錯。

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

如果非對象參數(shù)出現(xiàn)在源對象的位置(即非首參數(shù)),那么處理規(guī)則有所不同。首先,這些參數(shù)都會轉成對象,如果無法轉成對象,就會跳過。這意味著,如果 undefined 和 null 不在首參數(shù),就不會報錯。

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

其他類型的值(即數(shù)值、字符串和布爾值)不在首參數(shù),也不會報錯。但是,除了字符串會以數(shù)組形式,拷貝入目標對象,其他值都不會產生效果。

  1. const v1 = 'abc';
  2. const v2 = true;
  3. const v3 = 10;
  4. const obj = Object.assign({}, v1, v2, v3);
  5. console.log(obj); // { "0": "a", "1": "b", "2": "c" }

上面代碼中, v1 、 v2 、 v3 分別是字符串、布爾值和數(shù)值,結果只有字符串合入目標對象(以字符數(shù)組的形式),數(shù)值和布爾值都會被忽略。這是因為只有字符串的包裝對象,會產生可枚舉屬性。

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

上面代碼中,布爾值、數(shù)值、字符串分別轉成對應的包裝對象,可以看到它們的原始值都在包裝對象的內部屬性 [[PrimitiveValue]] 上面,這個屬性是不會被 Object.assign 拷貝的。只有字符串的包裝對象,會產生可枚舉的實義屬性,那些屬性則會被拷貝。

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

  1. Object.assign({b: 'c'},
  2. Object.defineProperty({}, 'invisible', {
  3. enumerable: false,
  4. value: 'hello'
  5. })
  6. )
  7. // { b: 'c' }

上面代碼中, Object.assign要拷貝的對象只有一個不可枚舉屬性 invisible ,這個屬性并沒有被拷貝進去。

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

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

注意點

(1)淺拷貝

Object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,如果源對象某個屬性的值是對象,那么目標對象拷貝得到的是這個對象的引用。

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

上面代碼中,源對象 obj1 的 a 屬性的值是一個對象, Object.assign 拷貝得到的是這個對象的引用。這個對象的任何變化,都會反映到目標對象上面。

(2)同名屬性的替換

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

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

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

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

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

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

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

上面代碼中, Object.assign 把數(shù)組視為屬性名為 0、1、2 的對象,因此源數(shù)組的 0 號屬性 4 覆蓋了目標數(shù)組的 0 號屬性 1 。

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

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

  1. const source = {
  2. get foo() { return 1 }
  3. };
  4. const target = {};
  5. Object.assign(target, source)
  6. // { foo: 1 }

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

常見用途

Object.assign 方法有很多用處。

(1)為對象添加屬性

  1. class Point {
  2. constructor(x, y) {
  3. Object.assign(this, {x, y});
  4. }
  5. }

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

(2)為對象添加方法

  1. Object.assign(SomeClass.prototype, {
  2. someMethod(arg1, arg2) {
  3. ···
  4. },
  5. anotherMethod() {
  6. ···
  7. }
  8. });
  9. // 等同于下面的寫法
  10. SomeClass.prototype.someMethod = function (arg1, arg2) {
  11. ···
  12. };
  13. SomeClass.prototype.anotherMethod = function () {
  14. ···
  15. };

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

(3)克隆對象

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

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

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

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

(4)合并多個對象

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

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

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

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

(5)為屬性指定默認值

  1. const DEFAULTS = {
  2. logLevel: 0,
  3. outputFormat: 'html'
  4. };
  5. function processContent(options) {
  6. options = Object.assign({}, DEFAULTS, options);
  7. console.log(options);
  8. // ...
  9. }

上面代碼中, DEFAULTS 對象是默認值, options 對象是用戶提供的參數(shù)。 Object.assign 方法將 DEFAULTS 和 options 合并成一個新對象,如果兩者有同名屬性,則 options 的屬性值會覆蓋 DEFAULTS 的屬性值。

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

  1. const DEFAULTS = {
  2. url: {
  3. host: 'example.com',
  4. port: 7070
  5. },
  6. };
  7. processContent({ url: {port: 8000} })
  8. // {
  9. // url: {port: 8000}
  10. // }

上面代碼的原意是將 url.port 改成 8000, url.host 不變。實際結果卻是 options.url 覆蓋掉 DEFAULTS.url ,所以 url.host 就不存在了。

3. Object.getOwnPropertyDescriptors()

ES5 的 Object.getOwnPropertyDescriptor()方法會返回某個對象屬性的描述對象(descriptor)。ES2017 引入了Object.getOwnPropertyDescriptors()方法,返回指定對象所有自身屬性(非繼承屬性)的描述對象。

  1. const obj = {
  2. foo: 123,
  3. get bar() { return 'abc' }
  4. };
  5. Object.getOwnPropertyDescriptors(obj)
  6. // { foo:
  7. // { value: 123,
  8. // writable: true,
  9. // enumerable: true,
  10. // configurable: true },
  11. // bar:
  12. // { get: [Function: get bar],
  13. // set: undefined,
  14. // enumerable: true,
  15. // configurable: true } }

上面代碼中,Object.getOwnPropertyDescriptors()方法返回一個對象,所有原對象的屬性名都是該對象的屬性名,對應的屬性值就是該屬性的描述對象。

該方法的實現(xiàn)非常容易。

  1. function getOwnPropertyDescriptors(obj) {
  2. const result = {};
  3. for (let key of Reflect.ownKeys(obj)) {
  4. result[key] = Object.getOwnPropertyDescriptor(obj, key);
  5. }
  6. return result;
  7. }

該方法的引入目的,主要是為了解決 Object.assign() 無法正確拷貝 get 屬性和 set 屬性的問題。

  1. const source = {
  2. set foo(value) {
  3. console.log(value);
  4. }
  5. };
  6. const target1 = {};
  7. Object.assign(target1, source);
  8. Object.getOwnPropertyDescriptor(target1, 'foo')
  9. // { value: undefined,
  10. // writable: true,
  11. // enumerable: true,
  12. // configurable: true }

上面代碼中, source對象的 foo屬性的值是一個賦值函數(shù), Object.assign 方法將這個屬性拷貝給 target1 對象,結果該屬性的值變成了 undefined 。這是因為 Object.assign 方法總是拷貝一個屬性的值,而不會拷貝它背后的賦值方法或取值方法。

這時, Object.getOwnPropertyDescriptors() 方法配合 Object.defineProperties() 方法,就可以實現(xiàn)正確拷貝。

  1. const source = {
  2. set foo(value) {
  3. console.log(value);
  4. }
  5. };
  6. const target2 = {};
  7. Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source));
  8. Object.getOwnPropertyDescriptor(target2, 'foo')
  9. // { get: undefined,
  10. // set: [Function: set foo],
  11. // enumerable: true,
  12. // configurable: true }

上面代碼中,兩個對象合并的邏輯可以寫成一個函數(shù)。

  1. const shallowMerge = (target, source) => Object.defineProperties(
  2. target,
  3. Object.getOwnPropertyDescriptors(source)
  4. );

Object.getOwnPropertyDescriptors() 方法的另一個用處,是配合 Object.create() 方法,將對象屬性克隆到一個新對象。這屬于淺拷貝。

  1. const clone = Object.create(Object.getPrototypeOf(obj),
  2. Object.getOwnPropertyDescriptors(obj));
  3. // 或者
  4. const shallowClone = (obj) => Object.create(
  5. Object.getPrototypeOf(obj),
  6. Object.getOwnPropertyDescriptors(obj)
  7. );

上面代碼會克隆對象 obj 。

另外, Object.getOwnPropertyDescriptors() 方法可以實現(xiàn)一個對象繼承另一個對象。以前,繼承另一個對象,常常寫成下面這樣。

  1. const obj = {
  2. __proto__: prot,
  3. foo: 123,
  4. };

ES6 規(guī)定 proto 只有瀏覽器要部署,其他環(huán)境不用部署。如果去除 proto ,上面代碼就要改成下面這樣。

  1. const obj = Object.create(prot);
  2. obj.foo = 123;
  3. // 或者
  4. const obj = Object.assign(
  5. Object.create(prot),
  6. {
  7. foo: 123,
  8. }
  9. );

有了 Object.getOwnPropertyDescriptors() ,我們就有了另一種寫法。

  1. const obj = Object.create(
  2. prot,
  3. Object.getOwnPropertyDescriptors({
  4. foo: 123,
  5. })
  6. );

Object.getOwnPropertyDescriptors() 也可以用來實現(xiàn) Mixin(混入)模式。

  1. let mix = (object) => ({
  2. with: (...mixins) => mixins.reduce(
  3. (c, mixin) => Object.create(
  4. c, Object.getOwnPropertyDescriptors(mixin)
  5. ), object)
  6. });
  7. // multiple mixins example
  8. let a = {a: 'a'};
  9. let b = {b: 'b'};
  10. let c = {c: 'c'};
  11. let d = mix(c).with(a, b);
  12. d.c // "c"
  13. d.b // "b"
  14. d.a // "a"

上面代碼返回一個新的對象 d ,代表了對象 a 和 b 被混入了對象 c 的操作。

出于完整性的考慮, Object.getOwnPropertyDescriptors() 進入標準以后,以后還會新增 Reflect.getOwnPropertyDescriptors() 方法。

4. proto 屬性,Object.setPrototypeOf(),Object.getPrototypeOf()

JavaScript語言的對象繼承是通過原型鏈實現(xiàn)的。ES6 提供了更多原型對象的操作方法。

proto屬性

__proto__ 屬性(前后各兩個下劃線),用來讀取或設置當前對象的原型對象(prototype)。目前,所有瀏覽器(包括 IE11)都部署了這個屬性。

  1. // es5 的寫法
  2. const obj = {
  3. method: function() { ... }
  4. };
  5. obj.__proto__ = someOtherObj;
  6. // es6 的寫法
  7. var obj = Object.create(someOtherObj);
  8. obj.method = function() { ... };

該屬性沒有寫入 ES6 的正文,而是寫入了附錄,原因是 proto 前后的雙下劃線,說明它本質上是一個內部屬性,而不是一個正式的對外的 API,只是由于瀏覽器廣泛支持,才被加入了 ES6。標準明確規(guī)定,只有瀏覽器必須部署這個屬性,其他運行環(huán)境不一定需要部署,而且新的代碼最好認為這個屬性是不存在的。因此,無論從語義的角度,還是從兼容性的角度,都不要使用這個屬性,而是使用下面的 Object.setPrototypeOf()(寫操作)、 Object.getPrototypeOf()(讀操作)、 Object.create() (生成操作)代替。

實現(xiàn)上, __proto__ 調用的是Object.prototype.__proto__,具體實現(xiàn)如下。

  1. Object.defineProperty(Object.prototype, '__proto__', {
  2. get() {
  3. let _thisObj = Object(this);
  4. return Object.getPrototypeOf(_thisObj);
  5. },
  6. set(proto) {
  7. if (this === undefined || this === null) {
  8. throw new TypeError();
  9. }
  10. if (!isObject(this)) {
  11. return undefined;
  12. }
  13. if (!isObject(proto)) {
  14. return undefined;
  15. }
  16. let status = Reflect.setPrototypeOf(this, proto);
  17. if (!status) {
  18. throw new TypeError();
  19. }
  20. },
  21. });
  22. function isObject(value) {
  23. return Object(value) === value;
  24. }

如果一個對象本身部署了 proto 屬性,該屬性的值就是對象的原型。

  1. Object.getPrototypeOf({ __proto__: null })
  2. // null

Object.setPrototypeOf()

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

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

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

  1. function setPrototypeOf(obj, proto) {
  2. obj.__proto__ = proto;
  3. return obj;
  4. }

下面是一個例子。

  1. let proto = {};
  2. let obj = { x: 10 };
  3. Object.setPrototypeOf(obj, proto);
  4. proto.y = 20;
  5. proto.z = 40;
  6. obj.x // 10
  7. obj.y // 20
  8. obj.z // 40

上面代碼將proto 對象設為 obj對象的原型,所以從 obj 對象可以讀取 proto 對象的屬性。

如果第一個參數(shù)不是對象,會自動轉為對象。但是由于返回的還是第一個參數(shù),所以這個操作不會產生任何效果。

  1. Object.setPrototypeOf(1, {}) === 1 // true
  2. Object.setPrototypeOf('foo', {}) === 'foo' // true
  3. Object.setPrototypeOf(true, {}) === true // true

由于 undefined 和 null 無法轉為對象,所以如果第一個參數(shù)是 undefined 或 null ,就會報錯。

  1. Object.setPrototypeOf(undefined, {})
  2. // TypeError: Object.setPrototypeOf called on null or undefined
  3. Object.setPrototypeOf(null, {})
  4. // TypeError: Object.setPrototypeOf called on null or undefined

Object.getPrototypeOf()

該方法與Object.setPrototypeOf方法配套,用于讀取一個對象的原型對象。

  1. Object.getPrototypeOf(obj);

下面是一個例子。

  1. function Rectangle() {
  2. // ...
  3. }
  4. const rec = new Rectangle();
  5. Object.getPrototypeOf(rec) === Rectangle.prototype
  6. // true
  7. Object.setPrototypeOf(rec, Object.prototype);
  8. Object.getPrototypeOf(rec) === Rectangle.prototype
  9. // false

如果參數(shù)不是對象,會被自動轉為對象。

  1. // 等同于 Object.getPrototypeOf(Number(1))
  2. Object.getPrototypeOf(1)
  3. // Number {[[PrimitiveValue]]: 0}
  4. // 等同于 Object.getPrototypeOf(String('foo'))
  5. Object.getPrototypeOf('foo')
  6. // String {length: 0, [[PrimitiveValue]]: ""}
  7. // 等同于 Object.getPrototypeOf(Boolean(true))
  8. Object.getPrototypeOf(true)
  9. // Boolean {[[PrimitiveValue]]: false}
  10. Object.getPrototypeOf(1) === Number.prototype // true
  11. Object.getPrototypeOf('foo') === String.prototype // true
  12. Object.getPrototypeOf(true) === Boolean.prototype // true

如果參數(shù)是 undefined 或 null ,它們無法轉為對象,所以會報錯。

  1. Object.getPrototypeOf(null)
  2. // TypeError: Cannot convert undefined or null to object
  3. Object.getPrototypeOf(undefined)
  4. // TypeError: Cannot convert undefined or null to object

5. Object.keys(),Object.values(),Object.entries()

Object.keys()

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

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

ES2017 引入了跟 Object.keys配套的Object.valuesObject.entries ,作為遍歷一個對象的補充手段,供 for...of 循環(huán)使用。

  1. let {keys, values, entries} = Object;
  2. let obj = { a: 1, b: 2, c: 3 };
  3. for (let key of keys(obj)) {
  4. console.log(key); // 'a', 'b', 'c'
  5. }
  6. for (let value of values(obj)) {
  7. console.log(value); // 1, 2, 3
  8. }
  9. for (let [key, value] of entries(obj)) {
  10. console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
  11. }

Object.values()

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

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

返回數(shù)組的成員順序,與本章的《屬性的遍歷》部分介紹的排列規(guī)則一致。

  1. const obj = { 100: 'a', 2: 'b', 7: 'c' };
  2. Object.values(obj)
  3. // ["b", "c", "a"]

上面代碼中,屬性名數(shù)值的屬性,是按照數(shù)值大小,從小到大遍歷的,因此返回的順序是 b 、 c 、 a 。

Object.values 只返回對象自身的可遍歷屬性。

  1. const obj = Object.create({}, {p: {value: 42}});
  2. Object.values(obj) // []

上面代碼中, Object.create 方法的第二個參數(shù)添加的對象屬性(屬性 p ),如果不顯式聲明,默認是不可遍歷的,因為 p 的屬性描述對象的 enumerable 默認是 false , Object.values 不會返回這個屬性。只要把 enumerable 改成 true , Object.values 就會返回屬性 p 的值。

  1. const obj = Object.create({}, {p:
  2. {
  3. value: 42,
  4. enumerable: true
  5. }
  6. });
  7. Object.values(obj) // [42]

Object.values 會過濾屬性名為 Symbol 值的屬性。

  1. Object.values({ [Symbol()]: 123, foo: 'abc' });
  2. // ['abc']

如果 Object.values 方法的參數(shù)是一個字符串,會返回各個字符組成的一個數(shù)組。

  1. Object.values('foo')
  2. // ['f', 'o', 'o']

上面代碼中,字符串會先轉成一個類似數(shù)組的對象。字符串的每個字符,就是該對象的一個屬性。因此, Object.values 返回每個屬性的鍵值,就是各個字符組成的一個數(shù)組。

如果參數(shù)不是對象, Object.values 會先將其轉為對象。由于數(shù)值和布爾值的包裝對象,都不會為實例添加非繼承的屬性。所以, Object.values 會返回空數(shù)組。

  1. Object.values(42) // []
  2. Object.values(true) // []

Object.entries()

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

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

除了返回值不一樣,該方法的行為與 Object.values 基本一致。

如果原對象的屬性名是一個 Symbol 值,該屬性會被忽略。

  1. Object.entries({ [Symbol()]: 123, foo: 'abc' });
  2. // [ [ 'foo', 'abc' ] ]

上面代碼中,原對象有兩個屬性,Object.entries只輸出屬性名非 Symbol 值的屬性。將來可能會有Reflect.ownEntries()方法,返回對象自身的所有屬性。

Object.entries 的基本用途是遍歷對象的屬性。

  1. let obj = { one: 1, two: 2 };
  2. for (let [k, v] of Object.entries(obj)) {
  3. console.log(
  4. `${JSON.stringify(k)}: ${JSON.stringify(v)}`
  5. );
  6. }
  7. // "one": 1
  8. // "two": 2

Object.entries 方法的另一個用處是,將對象轉為真正的 Map 結構。

  1. const obj = { foo: 'bar', baz: 42 };
  2. const map = new Map(Object.entries(obj));
  3. map // Map { foo: "bar", baz: 42 }

自己實現(xiàn) Object.entries 方法,非常簡單。

  1. // Generator函數(shù)的版本
  2. function* entries(obj) {
  3. for (let key of Object.keys(obj)) {
  4. yield [key, obj[key]];
  5. }
  6. }
  7. // 非Generator函數(shù)的版本
  8. function entries(obj) {
  9. let arr = [];
  10. for (let key of Object.keys(obj)) {
  11. arr.push([key, obj[key]]);
  12. }
  13. return arr;
  14. }

6. Object.fromEntries()

Object.fromEntries()方法是Object.entries()的逆操作,用于將一個鍵值對數(shù)組轉為對象。

  1. Object.fromEntries([
  2. ['foo', 'bar'],
  3. ['baz', 42]
  4. ])
  5. // { foo: "bar", baz: 42 }

該方法的主要目的,是將鍵值對的數(shù)據(jù)結構還原為對象,因此特別適合將 Map 結構轉為對象。

  1. // 例一
  2. const entries = new Map([
  3. ['foo', 'bar'],
  4. ['baz', 42]
  5. ]);
  6. Object.fromEntries(entries)
  7. // { foo: "bar", baz: 42 }
  8. // 例二
  9. const map = new Map().set('foo', true).set('bar', false);
  10. Object.fromEntries(map)
  11. // { foo: true, bar: false }

該方法的一個用處是配合URLSearchParams對象,將查詢字符串轉為對象。

  1. Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))
  2. // { foo: "bar", baz: "qux" }
以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號