chức năng ánh xạ cho các đối tượng (thay vì mảng)


1066

Tôi có một đối tượng:

myObject = { 'a': 1, 'b': 2, 'c': 3 }

Tôi đang tìm kiếm một phương thức riêng, tương tự như phương pháp Array.prototype.mapđó sẽ được sử dụng như sau:

newObject = myObject.map(function (value, label) {
    return value * value;
});

// newObject is now { 'a': 1, 'b': 4, 'c': 9 }

JavaScript có mapchức năng như vậy cho các đối tượng không? (Tôi muốn điều này cho Node.JS, vì vậy tôi không quan tâm đến các vấn đề trên trình duyệt chéo.)


1
Hầu hết các câu trả lời sử dụng Object.keys, không có bất kỳ thứ tự được xác định rõ. Đó có thể là vấn đề, tôi đề nghị sử dụng Object.getOwnPropertyNamesthay thế.
Oriol

14
Thật ngạc nhiên với tôi rằng JS đã không cung cấp cho nhiệm vụ cực kỳ thô sơ này.
jchook

3
@Oriol bạn có chắc về điều đó không? Theo các tài liệu web MDN, thứ tự của các phần tử mảng là phù hợp giữa Object.keysObject.getOwnPropertyNames. Xem developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
mẹo

@Bart Thứ tự Object.keysphụ thuộc vào việc thực hiện. Xem stackoverflow.com/a/30919039/1529630
Oriol

4
@Oriol Dù sao bạn cũng không nên dựa vào thứ tự các khóa trong các vật thể, vì vậy nó không liên quan đến câu hỏi - vì anh ấy không bao giờ quy định rằng thứ tự quan trọng với anh ấy. Và nếu mệnh lệnh quan trọng với anh ta, dù sao anh ta cũng không nên sử dụng một vật thể.
BT

Câu trả lời:


1543

Không có nguồn gốc mapcủa Objectđối tượng, nhưng làm thế nào về điều này:

var myObject = { 'a': 1, 'b': 2, 'c': 3 };

Object.keys(myObject).map(function(key, index) {
  myObject[key] *= 2;
});

console.log(myObject);
// => { 'a': 2, 'b': 4, 'c': 6 }

Nhưng bạn có thể dễ dàng lặp lại một đối tượng bằng cách sử dụng for ... in:

var myObject = { 'a': 1, 'b': 2, 'c': 3 };

for (var key in myObject) {
  if (myObject.hasOwnProperty(key)) {
    myObject[key] *= 2;
  }
}

console.log(myObject);
// { 'a': 2, 'b': 4, 'c': 6 }

Cập nhật

Rất nhiều người đang đề cập rằng các phương thức trước đó không trả về một đối tượng mới, mà hoạt động trên chính đối tượng đó. Đối với vấn đề đó, tôi muốn thêm một giải pháp khác trả về một đối tượng mới và để lại đối tượng ban đầu như sau:

var myObject = { 'a': 1, 'b': 2, 'c': 3 };

// returns a new object with the values at each key mapped using mapFn(value)
function objectMap(object, mapFn) {
  return Object.keys(object).reduce(function(result, key) {
    result[key] = mapFn(object[key])
    return result
  }, {})
}

var newObject = objectMap(myObject, function(value) {
  return value * 2
})

console.log(newObject);
// => { 'a': 2, 'b': 4, 'c': 6 }

console.log(myObject);
// => { 'a': 1, 'b': 2, 'c': 3 }

Array.prototype.reducegiảm một mảng thành một giá trị bằng cách hợp nhất phần nào giá trị trước đó với giá trị hiện tại. Chuỗi được khởi tạo bởi một đối tượng trống {}. Trên mỗi lần lặp, một khóa mới myObjectđược thêm vào với hai lần khóa là giá trị.

Cập nhật

Với các tính năng ES6 mới, có một cách để thể hiện thanh lịch hơn objectMap.

const objectMap = (obj, fn) =>
  Object.fromEntries(
    Object.entries(obj).map(
      ([k, v], i) => [k, fn(v, k, i)]
    )
  )
  
const myObject = { a: 1, b: 2, c: 3 }

console.log(objectMap(myObject, v => 2 * v)) 


3
Có, tôi sẽ không đề xuất giải pháp của mình cho loại vấn đề đó. Đó là lý do tại sao tôi cập nhật câu trả lời của mình bằng một giải pháp thay thế tốt hơn.
Amberlamp

1
Tôi đã cập nhật câu trả lời của mình - có vẻ như (khi đọc lại câu hỏi) rằng OP muốn một đối tượng mới có cùng khóa, trong đó các giá trị được thay đổi với hàm được cung cấp và không sửa đổi đối tượng ban đầu.
Alnitak

13
@KhalilRavanna Tôi nghĩ rằng bạn đã đọc sai mã ở đây - câu trả lời này không được sử dụng mapđúng bởi vì nó không thực hiện return- nó lạm dụng mapnhư thể đó là một forEachcuộc gọi. Nếu anh ta thực sự đã làm return myObject[value] * 2 thì kết quả sẽ là một mảng chứa các giá trị ban đầu được nhân đôi, thay vì một đối tượng chứa các khóa gốc có giá trị nhân đôi, thì rõ ràng đây là điều mà OP yêu cầu.
Alnitak

3
@Amberlamp .reduceví dụ của bạn là OK, nhưng IMHO vẫn còn thiếu một chút thuận tiện .mapcho các Đối tượng, vì .reducecuộc gọi lại của bạn không chỉ phải phù hợp với cách .reducehoạt động mà còn yêu cầu myObjectphải có sẵn trong phạm vi từ vựng. Điều thứ hai đặc biệt làm cho không thể chỉ chuyển một tham chiếu hàm trong cuộc gọi lại, thay vào đó yêu cầu một hàm ẩn danh tại chỗ.
Alnitak

8
TBH Tôi muốn đưa ra một câu trả lời mà chỉ (hoặc ban đầu) cung cấp giải pháp thứ hai được trình bày trong câu trả lời này. Cái đầu tiên hoạt động và không nhất thiết là sai, nhưng như những người khác đã nói, tôi không muốn thấy bản đồ được sử dụng theo cách đó. Khi tôi nhìn thấy bản đồ, tâm trí tôi tự động nghĩ đến "cấu trúc dữ liệu bất biến"
mjohnsonengr

308

Làm thế nào về một lớp lót với gán biến ngay lập tức trong JS đơn giản ( ES6 / ES2015 )?

Sử dụng toán tử trải rộng và cú pháp tên khóa được tính toán :

let newObj = Object.assign({}, ...Object.keys(obj).map(k => ({[k]: obj[k] * obj[k]})));

jsbin

Một phiên bản khác sử dụng giảm:

let newObj = Object.keys(obj).reduce((p, c) => ({...p, [c]: obj[c] * obj[c]}), {});

jsbin

Ví dụ đầu tiên là một hàm:

const oMap = (o, f) => Object.assign({}, ...Object.keys(o).map(k => ({ [k]: f(o[k]) })));

// To square each value you can call it like this:
let mappedObj = oMap(myObj, (x) => x * x);

jsbin

Nếu bạn muốn ánh xạ một đối tượng lồng nhau một cách đệ quy trong một chức năng phong cách, nó có thể được thực hiện như thế này:

const sqrObjRecursive = obj =>
  Object.keys(obj).reduce(
    (newObj, key) =>
      obj[key] && typeof obj[key] === "object"
        ? { ...newObj, [key]: sqrObjRecursive(obj[key]) } // recurse.
        : { ...newObj, [key]: obj[key] * obj[key] }, // square val.
    {}
  );       

jsbin

Hoặc bắt buộc hơn, như thế này:

const sqrObjRecursive = obj => {
  Object.keys(obj).forEach(key => {
    if (typeof obj[key] === "object") obj[key] = sqrObjRecursive(obj[key]);
    else obj[key] = obj[key] * obj[key];
  });
  return obj;
};

jsbin

ES7 / ES2016, bạn có thể sử dụng Object.entries()thay vì Object.keys()ví dụ như thế này:

let newObj = Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})));

ES2019 được giới thiệu Object.fromEntries(), giúp đơn giản hóa điều này hơn nữa:

let newObj = Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, v * v]));


Các thuộc tính được kế thừa và chuỗi nguyên mẫu:

Trong một số trường hợp hiếm hoi, bạn có thể cần ánh xạ một đối tượng giống như lớp chứa các thuộc tính của một đối tượng được kế thừa trên chuỗi nguyên mẫu của nó . Trong những trường hợp như vậy Object.keys()sẽ không hoạt động, vì Object.keys()không liệt kê các thuộc tính được thừa kế . Nếu bạn cần ánh xạ các thuộc tính được kế thừa , bạn nên sử dụng for (key in myObj) {...}.

Dưới đây là một ví dụ về một đối tượng kế thừa các thuộc tính của đối tượng khác và cách thức Object.keys()hoạt động trong kịch bản đó.

const obj1 = { 'a': 1, 'b': 2, 'c': 3}
const obj2 = Object.create(obj1);  // One of multiple ways to inherit an object in JS.

// Here you see how the properties of obj1 sit on the 'prototype' of obj2
console.log(obj2)  // Prints: obj2.__proto__ = { 'a': 1, 'b': 2, 'c': 3}

console.log(Object.keys(obj2));  // Prints: an empty Array.

for (key in obj2) {
  console.log(key);              // Prints: 'a', 'b', 'c'
}

jsbin

Tuy nhiên, xin vui lòng giúp tôi và tránh thừa kế . :-)


1
Xinh đẹp nhưng tôi đã bị bắt bởi thực tế là Object.keyskhông liệt kê tài sản thừa kế. Tôi đề nghị bạn thêm một cảnh báo.
David Braun

Để rút ngắn câu trả lời của bạn, chỉ cần sử dụng Object.entries({a: 1, b: 2, c: 3}).

1
Bạn có một số lỗi chính tả (bạn gọi (o, f)là đối số nhưng sử dụng objtrong phần thân.
kzahel

4
Vâng và sau đó để người tiếp theo dành vài phút để tìm hiểu chức năng này làm gì? :)
Andrey Popov

1
Giải pháp Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: v * v})))không hoạt động nếu objlà một đối tượng trống. Thay đổi thành : Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v}))).
blackcatweb

116

Không có phương thức riêng, nhưng lodash # mapValues sẽ thực hiện công việc một cách xuất sắc

_.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; });
// → { 'a': 3, 'b': 6, 'c': 9 }

6
Không cần thêm một cuộc gọi HTTP bổ sung và một thư viện bổ sung chỉ cho một chức năng. Trong mọi trường hợp, câu trả lời này hiện đã lỗi thời và bạn chỉ cần gọi Object.entries({a: 1, b: 2, c: 3})để lấy một mảng.

11
Tại sao nhận được một mảng hữu ích? Yêu cầu là đối với một đối tượng được ánh xạ. Ngoài ra, không có cuộc gọi HTTP ngụ ý nào khi sử dụng Lodash, một thư viện phổ biến về cơ bản được xây dựng cho loại điều này, mặc dù có khá nhiều điều mà ES6 đã loại trừ sự cần thiết phải sử dụng các thư viện chức năng tiện ích ở một mức độ nào đó gần đây.
corse32

2
Tôi gọi thêm HTTP để kéo Lodash, tôi đoán vậy. Nếu đây là trường hợp sử dụng duy nhất của bạn, thực sự đó là một quá mức cần thiết. Tuy nhiên, thật hợp lý khi có câu trả lời này cho Lodash là một thư viện rộng rãi như vậy.
igorsantos07

2
không đề cập đến việc bạn thực sự nên sử dụng _.map()để bạn lấy khóa làm đối số thứ hai - theo yêu cầu của OP.
igorsantos07

_.mapValues()cũng cung cấp khóa là đối số thứ 2. Cũng _.map()không hoạt động ở đây vì nó chỉ trả về mảng, không phải đối tượng:_.map({ 'a': 1, 'b': 2, 'c': 3}, n => n * 3) // [3, 6, 9]
MeltedPenguin

57

Thật dễ dàng để viết một:

Object.map = function(o, f, ctx) {
    ctx = ctx || this;
    var result = {};
    Object.keys(o).forEach(function(k) {
        result[k] = f.call(ctx, o[k], k, o); 
    });
    return result;
}

với mã ví dụ:

> o = { a: 1, b: 2, c: 3 };
> r = Object.map(o, function(v, k, o) {
     return v * v;
  });
> r
{ a : 1, b: 4, c: 9 }

NB: phiên bản này cũng cho phép bạn (tùy chọn) đặt thisbối cảnh cho cuộc gọi lại, giống như Arrayphương thức.

EDIT - đã thay đổi để loại bỏ việc sử dụng Object.prototype, để đảm bảo rằng nó không xung đột với bất kỳ thuộc tính hiện có nào có tên maptrên đối tượng.


3
Đồng ý. :) Một nhận xét về câu hỏi này đã đưa tôi đến đây. Tôi sẽ +1 điều này vì câu trả lời được chấp nhận rõ ràng là sử dụng sai map, nhưng tôi phải nói rằng sửa đổi Object.prototypekhông phù hợp với tôi, ngay cả khi nó không được liệt kê.
JLRishe

2
@JLRishe Cảm ơn. IMHO trong ES5 thực sự không còn lý do nào để không sửa đổi Object.prototypengoài rủi ro (lý thuyết) về va chạm với các phương pháp khác. FWIW, tôi không thể hiểu làm thế nào câu trả lời khác nhận được nhiều phiếu như nó có, nó hoàn toàn sai.
Alnitak

7
@JLRishe bạn là một lão già ... hãy hòa nhập với thời gian và sửa đổi nguyên mẫu đó!
Nick Manning

12
@NickManning Bạn là chủ hàng trẻ tuổi và hành vi vô trách nhiệm của bạn. Ra khỏi vườn cỏ của tôi!
JLRishe 6/03/2015

3
Điều này đã không hoạt động : o = {map: true, image: false}. Bạn đang mạo hiểm chỉ để viết o.map(fn)thay vìmap(o,fn)
fregante

25

Bạn có thể sử dụng Object.keysvà sau đó forEachqua mảng phím được trả về:

var myObject = { 'a': 1, 'b': 2, 'c': 3 },
    newObject = {};
Object.keys(myObject).forEach(function (key) {
    var value = myObject[key];
    newObject[key] = value * value;
});

Hoặc theo kiểu mô-đun hơn:

function map(obj, callback) {
    var result = {};
    Object.keys(obj).forEach(function (key) {
        result[key] = callback.call(obj, obj[key], key, obj);
    });
    return result;
}

newObject = map(myObject, function(x) { return x * x; });

Lưu ý rằng Object.keystrả về một mảng chỉ chứa các thuộc tính có thể đếm được của chính đối tượng, do đó, nó hoạt động giống như một for..invòng lặp với một hasOwnPropertykiểm tra.


20

Đây là bs thẳng và mọi người trong cộng đồng JS đều biết điều đó. Có nên có chức năng này:

const obj1 = {a:4, b:7};
const obj2 = Object.map(obj1, (k,v) => v + 5);

console.log(obj1); // {a:4, b:7}
console.log(obj2); // {a:9, b:12}

đây là cách thực hiện ngây thơ:

Object.map = function(obj, fn, ctx){

    const ret = {};

    for(let k of Object.keys(obj)){
        ret[k] = fn.call(ctx || null, k, obj[k]);
    });

    return ret;
};

thật là khó chịu khi phải tự mình thực hiện điều này;)

Nếu bạn muốn một cái gì đó tinh vi hơn một chút, điều đó không can thiệp vào lớp Object, hãy thử điều này:

let map = function (obj, fn, ctx) {
  return Object.keys(obj).reduce((a, b) => {
    a[b] = fn.call(ctx || null, b, obj[b]);
    return a;
  }, {});
};


const x = map({a: 2, b: 4}, (k,v) => {
    return v*2;
});

nhưng an toàn khi thêm chức năng bản đồ này vào Object, chỉ cần không thêm vào Object.prototype.

Object.map = ... // fairly safe
Object.prototype.map ... // not ok

Tại sao bạn thêm chức năng này vào Objectđối tượng toàn cầu ? Chỉ cần có const mapObject = (obj, fn) => { [...]; return ret; }.
Amberlamp

7
Bởi vì nó phải là một phương thức trên Object :)
Alexander Mills

1
Miễn là chúng ta không gây rối với Object.prototype thì chúng ta sẽ ổn thôi
Alexander Mills

1
Nếu bản đồ chỉ là một điều mơ hồ ngẫu nhiên, chắc chắn. Nhưng .mapthường được hiểu là giao diện Functor và không có định nghĩa duy nhất về Functor cho "Object" bởi vì hầu như mọi thứ trong javascript đều có thể là Object, bao gồm cả những thứ có giao diện / logic rất riêng biệt và được xác định.
Dtipson

1
Theo tôi, đối số đầu tiên của cuộc gọi lại phải là chính yếu tố lặp, không phải là khóa. Ví dụ, tôi giả sử nó sẽ cung cấp cho tôi cùng một đối tượng, như thường xảy ra với bản đồ chung: Object.map ({prop: 1}, el => el) nhưng nó trả về các khóa có giá trị cùng tên khóa ...
Gleb Dolzikov

17

Tôi đến đây để tìm và trả lời cho việc ánh xạ một đối tượng vào một mảng và kết quả là trang này. Trong trường hợp bạn đến đây để tìm kiếm cùng một câu trả lời tôi đã có, đây là cách bạn có thể ánh xạ và phản đối một mảng.

Bạn có thể sử dụng bản đồ để trả về một mảng mới từ đối tượng như vậy:

var newObject = Object.keys(myObject).map(function(key) {
   return myObject[key];
});

6
Điều này không hoạt động từ xa - nó chỉ trả về một mảng các giá trị của đối tượng, không phải là một đối tượng mới. Tôi không thể tin rằng nó có nhiều phiếu bầu.
Alnitak

1
Bạn đã đúng, nó không trả lời chính xác câu hỏi vì họ đang tìm kiếm một câu trả lời để ánh xạ một đối tượng và đối tượng. Tôi đến đây để tìm câu trả lời cho việc ánh xạ một đối tượng vào một mảng và kết quả là trang này, vì vậy tôi sẽ để lại câu trả lời của mình và chỉnh sửa nó để phản ánh rằng đó là một câu trả lời thay thế cho những người có thể đã đến đây do kết quả của tìm kiếm ánh xạ một đối tượng vào mảng.
JoeTron

5
Trong ES7, điều đó sẽ trở thành tầm thườngObject.values(myObject)
Alnitak

1
Đó là điều tốt đẹp để biết, nhưng một số người vẫn phải sử dụng mã kế thừa.
JoeTron

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

12

Câu trả lời được chấp nhận có hai nhược điểm:

  • Nó lạm dụng Array.prototype.reduce, bởi vì giảm có nghĩa là thay đổi cấu trúc của một loại hỗn hợp, điều này không xảy ra trong trường hợp này.
  • Nó không đặc biệt có thể tái sử dụng

Cách tiếp cận chức năng ES6 / ES2015

Xin lưu ý rằng tất cả các chức năng được xác định ở dạng curried.

// small, reusable auxiliary functions

const keys = o => Object.keys(o);

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

const map = f => xs => xs.map(x => f(x));

const mul = y => x => x * y;

const sqr = x => mul(x) (x);


// the actual map function

const omap = f => o => {
  o = assign(o); // A
  map(x => o[x] = f(o[x])) (keys(o)); // B
  return o;
};


// mock data

const o = {"a":1, "b":2, "c":3};


// and run

console.log(omap(sqr) (o));
console.log(omap(mul(10)) (o));

  • Trong dòng A ođược gán lại. Vì Javascript vượt qua các giá trị tham chiếu bằng cách chia sẻ , một bản sao nông ođược tạo ra. Bây giờ chúng ta có thể đột biến otrong omapmà không bị đột biến otrong phạm vi cha.
  • Trong mapgiá trị trả về của dòng B bị bỏ qua, vì mapthực hiện đột biến o. Vì tác dụng phụ này vẫn nằm trong phạm vi omapvà không thể nhìn thấy trong phạm vi cha mẹ, nên nó hoàn toàn có thể chấp nhận được.

Đây không phải là giải pháp nhanh nhất, mà là một giải pháp khai báo và tái sử dụng. Đây là cách thực hiện tương tự như một dòng, ngắn gọn nhưng ít đọc hơn:

const omap = f => o => (o = assign(o), map(x => o[x] = f(o[x])) (keys(o)), o);

Phụ lục - tại sao các đối tượng không được lặp lại theo mặc định?

ES2015 đã chỉ định các giao thức lặp và lặp. Nhưng các đối tượng vẫn không thể lặp lại và do đó không thể ánh xạ. Lý do là sự pha trộn của dữ liệu và cấp độ chương trình .


1
Có vẻ như một chút quá kỹ thuật; Tôi đếm 6 hàm cho những gì thực chất là một vòng lặp. Các giải pháp khác đơn giản hơn nhiều và câu trả lời được chấp nhận cũng nhanh hơn 5 lần.
fregante

4
@ bfred.it Mục đích bình luận của bạn là gì? Nếu bạn thích tối ưu hóa vi mô, bạn không nên sử dụng Array.prototype.reduce. Tất cả những gì tôi muốn minh họa ở đây là câu trả lời được chấp nhận bằng cách nào đó "lạm dụng" Array.prototype.reducevà làm thế nào một ánh xạ chức năng thuần túy có thể được thực hiện. Nếu bạn không quan tâm đến lập trình chức năng, hãy bỏ qua câu trả lời của tôi.

2
"Giảm có nghĩa là thay đổi cấu trúc của loại hỗn hợp" Tôi không nghĩ đó là sự thật. Một Array.reduce tạo ra một mảng mới có cùng độ dài chính xác hoặc thậm chí các giá trị chính xác giống nhau là hoàn toàn hợp pháp. Giảm có thể được sử dụng để tạo lại chức năng của bản đồ và / hoặc bộ lọc (hoặc cả hai, như trong một bộ chuyển đổi phức tạp, trong đó giảm là cơ sở). Trong FP, đó là một kiểu gấp và một nếp gấp kết thúc với cùng một kiểu vẫn là một nếp gấp.
Dtipson

2
@Dtipson Bạn hoàn toàn đúng. A foldlà chung chung hơn một map(functor). Tuy nhiên, đây là kiến ​​thức của tôi từ giữa năm 2016. Đó là một nửa vĩnh cửu: D

1
Hà, vâng. Tôi đã mất nhiều năm để nhận ra mức độ liên kết của tất cả các công cụ này và hệ sinh thái của các thuật ngữ và giao diện rộng hơn. Những thứ có vẻ như rất dễ trở nên phức tạp một cách khó tin và một số thứ có vẻ phức tạp đến mức không thể tóm tắt được khá gọn gàng. :)
Dtipson

10

JavaScript vừa có Object.fromEntriesphương thức mới .

Thí dụ

function mapObject (obj, fn) {
  return Object.fromEntries(
    Object
      .entries(obj)
      .map(fn)
  )
}

const myObject = { a: 1, b: 2, c: 3 }
const myNewObject = mapObject(myObject, ([key, value]) => ([key, value * value]))
console.log(myNewObject)

Giải trình

Đoạn mã trên chuyển đổi Object thành một Array ( [[<key>,<value>], ...]) mà bạn có thể ánh xạ. Object.fromEntrieschuyển đổi mảng trở lại một đối tượng.

Điều thú vị về mẫu này, đó là giờ đây bạn có thể dễ dàng lấy các khóa đối tượng trong khi ánh xạ.

Tài liệu

Hỗ trợ trình duyệt

Object.fromEntrieshiện chỉ được hỗ trợ bởi các trình duyệt / công cụ này , tuy nhiên vẫn có sẵn các polyfill (ví dụ @ babel / polyfill ).


2
Về cơ bản, Object.fromEntrieslà đối nghịch với Object.entries. Object.entrieschuyển đổi một đối tượng thành một danh sách các cặp khóa-giá trị. Object.fromEntrieschuyển đổi danh sách các cặp khóa-giá trị thành một đối tượng.
orad

8

Phiên bản tối thiểu (es6):

Object.entries(obj).reduce((a, [k, v]) => (a[k] = v * v, a), {})

Tôi nghĩ rằng điều này là không chính xác vì một lỗi đánh máy, tôi nghĩ bạn có nghĩa là => Object.entries(obj).reduce((a, [k, v]) => [a[k] = v * v, a], {}), dấu ngoặc nhọn thay vì dấu ngoặc đơn.
Alexander Mills

@AlexanderMills, mã của tôi là chính xác. Đọc thêm về toán tử dấu phẩy bên trong dấu ngoặc đơn: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Kẻ

Có nó, bạn có thể muốn giải thích điều đó vào lần tới, nhưng tôi đoán đó là những gì bình luận dành cho.
Alexander Mills

1
về cơ bản, mã của tôi tương đương với:Object.entries(obj).reduce((a, [k, v]) => {a[k] = v * v; return a}, {})
Yukulélé

1
Câu trả lời chính xác. Object.entries().reducelà giải pháp tốt nhất mà tôi nghĩ với ES6 + .Bạn có thêm upvotes nếu nó được sử dụng một returntuyên bố trong giảm hơn implicit returncommađiều hành - đó là gọn gàng nhưng khó đọc IMHO
Drenai

7

Để có hiệu suất tối đa.

Nếu đối tượng của bạn không thay đổi thường xuyên nhưng cần phải lặp đi lặp lại thường xuyên, tôi khuyên bạn nên sử dụng Bản đồ gốc làm bộ đệm.

// example object
var obj = {a: 1, b: 2, c: 'something'};

// caching map
var objMap = new Map(Object.entries(obj));

// fast iteration on Map object
objMap.forEach((item, key) => {
  // do something with an item
  console.log(key, item);
});

Object.entries đã hoạt động trong Chrome, Edge, Firefox và beta Opera vì vậy đây là một tính năng trong tương lai. Đó là từ ES7 vì vậy hãy điền vào https://github.com/es-shims/Object.entries cho IE khi nó không hoạt động.


Làm thế nào về việc sử dụng Hủy cấu trúc ?
Toàn cảnh

1
@ K._ trước đây nó rất chậm, nhưng tôi không biết về hiệu suất bây giờ. Có vẻ như V8 v 5.6 đã giới thiệu một số tối ưu hóa cho việc phá hủy nhưng điều đó phải được đo v8project.blogspot.co.uk
Pawel

Hoặc, ít hiệu suất hơn es7 nhưng không thay đổi:const fn = v => v * 2; const newObj = Object.entries(myObject).reduce((acc, [k,v]) => Object.assign({}, acc, {[k]: fn(v)}), {});
mikebridge

Tôi tự hỏi tại sao không có câu trả lời nào khác sử dụng Object.entries. Nó sạch sẽ hơn nhiều so với việc lặp qua các phím và sử dụng obj [key].
corwin.amber

6

bạn có thể sử dụng mapphương thức và forEachtrên các mảng nhưng nếu bạn muốn sử dụng nó Objectthì bạn có thể sử dụng nó với twist như bên dưới:

Sử dụng Javascript (ES6)

var obj = { 'a': 2, 'b': 4, 'c': 6 };   
Object.entries(obj).map( v => obj[v[0]] *= v[1] );
console.log(obj); //it will log as {a: 4, b: 16, c: 36}

var obj2 = { 'a': 4, 'b': 8, 'c': 10 };
Object.entries(obj2).forEach( v => obj2[v[0]] *= v[1] );
console.log(obj2); //it will log as {a: 16, b: 64, c: 100}

Sử dụng jQuery

var ob = { 'a': 2, 'b': 4, 'c': 6 };
$.map(ob, function (val, key) {
   ob[key] *= val;
});
console.log(ob) //it will log as {a: 4, b: 16, c: 36}

Hoặc bạn có thể sử dụng các vòng lặp khác cũng giống như $.eachphương pháp như ví dụ dưới đây:

$.each(ob,function (key, value) {
  ob[key] *= value;
});
console.log(ob) //it will also log as {a: 4, b: 16, c: 36}

Trong trường hợp $jquery là?
masterxilo

Có, bạn có thể sử dụng cả $ và jQuery
Haritsinh Gohil

1
@Ronald tôi đã hiểu lầm, hãy xem câu trả lời cập nhật của tôi, cảm ơn vì đã không hạ thấp nhưng thực sự nhận thức được lỗi lầm của mình, cảm ơn vì đã cải thiện cộng đồng.
Haritsinh Gohil

@bcoughlan vâng, đó chính xác là những gì tôi đã viết trong bình luận, nó bình phương các con số, bạn muốn gì sau đó?
Haritsinh Gohil

1
@HaritsinhGohil Tôi lấy nó để nói rằng anh ta đang chỉ trích bạn vì đã đưa ra một giải pháp jQuery. Đúng là ngày nay có một số động lực để di chuyển khỏi jQuery và tất nhiên là có Node, nhưng trừ khi OP yêu cầu cụ thể về JS hoặc Node thuần túy, tôi nghĩ sẽ ổn khi cho rằng ai đó đang làm việc trong môi trường web và jQuery đó là gần như chắc chắn có sẵn.
abalter

4

Điều map functionnày không tồn tại trên Object.prototypetuy nhiên bạn có thể mô phỏng nó như vậy

var myMap = function ( obj, callback ) {

    var result = {};

    for ( var key in obj ) {
        if ( Object.prototype.hasOwnProperty.call( obj, key ) ) {
            if ( typeof callback === 'function' ) {
                result[ key ] = callback.call( obj, obj[ key ], key, obj );
            }
        }
    }

    return result;

};

var myObject = { 'a': 1, 'b': 2, 'c': 3 };

var newObject = myMap( myObject, function ( value, key ) {
    return value * value;
});

Vấn đề nước hoa: typeof callback === 'function'hoàn toàn dư thừa. 1) mapkhông có ý nghĩa nếu không có cuộc gọi lại 2) nếu callbackkhông hoạt động, mapviệc triển khai của bạn chỉ chạy vòng lặp for vô nghĩa. Ngoài ra, Object.prototype.hasOwnProperty.call( obj, key )là một chút quá mức cần thiết.
ankhzet

3

Tôi đã xem đây là mục đầu tiên trong một tìm kiếm Google cố gắng học cách làm điều này và nghĩ rằng tôi sẽ chia sẻ cho các folsk khác tìm thấy giải pháp gần đây mà tôi tìm thấy, sử dụng gói npm bất biến.

Tôi nghĩ thật thú vị khi chia sẻ vì bất biến sử dụng tình huống CHÍNH XÁC của OP trong tài liệu riêng của họ - sau đây không phải là mã của riêng tôi mà được lấy từ tài liệu js bất biến hiện tại:

const { Seq } = require('immutable')
const myObject = { a: 1, b: 2, c: 3 }
Seq(myObject).map(x => x * x).toObject();
// { a: 1, b: 4, c: 9 } 

Không phải Seq có các thuộc tính khác ("Seq mô tả hoạt động lười biếng, cho phép chúng sử dụng hiệu quả chuỗi tất cả các phương pháp thu thập bậc cao (như bản đồ và bộ lọc) bằng cách không tạo các bộ sưu tập trung gian") và một số dữ liệu js bất biến khác cấu trúc cũng có thể làm công việc khá hiệu quả.

Tất cả mọi người sử dụng phương pháp này tất nhiên sẽ phải npm install immutablevà có thể muốn đọc các tài liệu:

https://facebook.github.io/immutable-js/


3

EDIT: Cách chính tắc sử dụng các tính năng JavaScript mới hơn là -

const identity = x =>
  x

const omap = (f = identity, o = {}) =>
  Object.fromEntries(
    Object.entries(o).map(([ k, v ]) =>
      [ k, f(v) ]
    )
  )

Đâu olà một số đối tượng và flà chức năng ánh xạ của bạn. Hoặc chúng ta có thể nói, được cung cấp một hàm từ a -> bvà một đối tượng có giá trị loại a, tạo ra một đối tượng có giá trị loại b. Là một chữ ký loại giả -

// omap : (a -> b, { a }) -> { b }

Câu trả lời ban đầu được viết để chứng minh một tổ hợp mạnh mẽ, mapReducecho phép chúng ta nghĩ về sự biến đổi của chúng ta theo một cách khác

  1. m, chức năng ánh xạ - cung cấp cho bạn cơ hội để chuyển đổi phần tử đến trước khi
  2. r, hàm khử - hàm này kết hợp bộ tích lũy với kết quả của phần tử được ánh xạ

Theo trực giác, mapReducetạo ra một bộ giảm tốc mới, chúng ta có thể cắm trực tiếp vào Array.prototype.reduce. Nhưng quan trọng hơn, chúng ta có thể triển khai thực hiện functor đối tượng của mình omapmột cách rõ ràng bằng cách sử dụng monoid đối tượng Object.assign{}.

const identity = x =>
  x
  
const mapReduce = (m, r) =>
  (a, x) => r (a, m (x))

const omap = (f = identity, o = {}) =>
  Object
    .keys (o)
    .reduce
      ( mapReduce
          ( k => ({ [k]: f (o[k]) })
          , Object.assign
          )
      , {}
      )
          
const square = x =>
  x * x
  
const data =
  { a : 1, b : 2, c : 3 }
  
console .log (omap (square, data))
// { a : 1, b : 4, c : 9 }

Lưu ý phần duy nhất của chương trình chúng tôi thực sự phải viết là bản thân việc thực hiện ánh xạ -

k => ({ [k]: f (o[k]) })

Điều đó nói rằng, đưa ra một đối tượng đã biết ovà một số khóa k, xây dựng một đối tượng và thuộc tính được tính toán klà kết quả của việc gọi fgiá trị của khóa , o[k].

Chúng ta có một cái nhìn thoáng qua về mapReducetiềm năng giải trình tự nếu chúng ta trừu tượng đầu tiênoreduce

// oreduce : (string * a -> string * b, b, { a }) -> { b }
const oreduce = (f = identity, r = null, o = {}) =>
  Object
    .keys (o)
    .reduce
      ( mapReduce
          ( k => [ k, o[k] ]
          , f
          )
      , r
      )

// omap : (a -> b, {a}) -> {b}
const omap = (f = identity, o = {}) =>
  oreduce
    ( mapReduce
        ( ([ k, v ]) =>
            ({ [k]: f (v) })
        , Object.assign
        )
    , {}
    , o
    )

Mọi thứ đều hoạt động như nhau, nhưng omapbây giờ có thể được xác định ở cấp độ cao hơn. Tất nhiên cái mới Object.entrieslàm cho điều này trông ngớ ngẩn, nhưng bài tập vẫn quan trọng đối với người học.

Bạn sẽ không thấy hết tiềm năng mapReduceở đây, nhưng tôi chia sẻ câu trả lời này bởi vì thật thú vị khi xem có bao nhiêu địa điểm có thể được áp dụng. Nếu bạn quan tâm đến cách nó có nguồn gốc và những cách khác có thể hữu ích, vui lòng xem câu trả lời này .


4
Hãy để chúng tôi sử dụng MapMap.entries, OK: D. Tôi mệt mỏi vì lạm dụng các đối tượng đơn giản như các kiểu dữ liệu bản đồ.

2
Tôi đồng ý Mapnên được sử dụng ở đâu / khi có thể, nhưng nó không hoàn toàn thay thế nhu cầu sử dụng các quy trình này trên các đối tượng JS đơn giản tho: D
Cảm ơn bạn

2

Dựa trên câu trả lời @Amberlamp, đây là một chức năng tiện ích (như một nhận xét trông nó xấu xí)

function mapObject(obj, mapFunc){
    return Object.keys(obj).reduce(function(newObj, value) {
        newObj[value] = mapFunc(obj[value]);
        return newObj;
    }, {});
}

và việc sử dụng là:

var obj = {a:1, b:3, c:5}
function double(x){return x * 2}

var newObj = mapObject(obj, double);
//=>  {a: 2, b: 6, c: 10}

2
var myObject = { 'a': 1, 'b': 2, 'c': 3 };


Object.prototype.map = function(fn){
    var oReturn = {};
    for (sCurObjectPropertyName in this) {
        oReturn[sCurObjectPropertyName] = fn(this[sCurObjectPropertyName], sCurObjectPropertyName);
    }
    return oReturn;
}
Object.defineProperty(Object.prototype,'map',{enumerable:false});





newObject = myObject.map(function (value, label) {
    return value * value;
});


// newObject is now { 'a': 1, 'b': 4, 'c': 9 }

enumerablemặc định làfalse
Cảm ơn bạn

2

Phản hồi của tôi chủ yếu dựa trên phản hồi được đánh giá cao nhất ở đây và hy vọng mọi người hiểu (cũng có lời giải thích tương tự trên GitHub của tôi). Đây là lý do tại sao sự áp đặt của anh ấy với bản đồ hoạt động:

Object.keys(images).map((key) => images[key] = 'url(' + '"' + images[key] + '"' +    
')');

Mục đích của hàm là lấy một đối tượng và sửa đổi nội dung ban đầu của đối tượng bằng một phương thức có sẵn cho tất cả các đối tượng (các đối tượng và mảng giống nhau) mà không trả về một mảng. Hầu hết mọi thứ trong JS là một đối tượng và vì lý do đó, các yếu tố tiếp tục đi xuống đường kế thừa có thể có khả năng sử dụng kỹ thuật những thứ có sẵn cho những người trên dòng (và ngược lại nó xuất hiện).

Lý do điều này hoạt động là do các hàm .map trả về một mảng YÊU CẦU mà bạn cung cấp RETURN rõ ràng hoặc ẩn của một mảng thay vì chỉ sửa đổi một đối tượng hiện có. Về cơ bản, bạn lừa chương trình nghĩ rằng đối tượng là một mảng bằng cách sử dụng Object.keys sẽ cho phép bạn sử dụng chức năng bản đồ với tác động của nó đối với các giá trị mà các khóa riêng lẻ được liên kết với (tôi thực sự vô tình trả lại mảng nhưng đã sửa nó). Miễn là không có sự trở lại theo nghĩa thông thường, sẽ không có mảng nào được tạo với đối tượng ban đầu còn nguyên vẹn và được sửa đổi như được lập trình.

Chương trình cụ thể này lấy một đối tượng được gọi là hình ảnh và lấy các giá trị của các khóa của nó và nối các thẻ url để sử dụng trong một chức năng khác. Bản gốc là đây:

var images = { 
snow: 'https://www.trbimg.com/img-5aa059f5/turbine/bs-md-weather-20180305', 
sunny: 'http://www.cubaweather.org/images/weather-photos/large/Sunny-morning-east-   
Matanzas-city- Cuba-20170131-1080.jpg', 
rain: 'https://i.pinimg.com/originals/23/d8
/ab/23d8ab1eebc72a123cebc80ce32b43d8.jpg' };

... và sửa đổi là đây:

var images = { 
snow: url('https://www.trbimg.com/img-5aa059f5/turbine/bs-md-weather-20180305'),     
sunny: url('http://www.cubaweather.org/images/weather-photos/large/Sunny-morning-   
east-Matanzas-city- Cuba-20170131-1080.jpg'), 
rain: url('https://i.pinimg.com/originals/23/d8
/ab/23d8ab1eebc72a123cebc80ce32b43d8.jpg') 
};

Cấu trúc ban đầu của đối tượng được giữ nguyên cho phép truy cập thuộc tính bình thường miễn là không có trả lại. KHÔNG có nó trả về một mảng như bình thường và mọi thứ sẽ ổn. Mục tiêu là THAM GIA các giá trị ban đầu (hình ảnh [khóa]) cho những gì được mong muốn và không phải bất cứ điều gì khác. Theo như tôi biết, để ngăn chặn đầu ra mảng, phải có TÁI TẠO hình ảnh [khóa] và không có yêu cầu ngầm hoặc rõ ràng nào để trả về một mảng (việc gán biến thực hiện điều này và bị trục trặc qua lại cho tôi).

BIÊN TẬP:

Đi đến giải quyết phương pháp khác của anh ấy về việc tạo đối tượng mới để tránh sửa đổi đối tượng ban đầu (và việc gán lại dường như vẫn cần thiết để tránh vô tình tạo một mảng làm đầu ra). Các hàm này sử dụng cú pháp mũi tên và nếu bạn chỉ muốn tạo một đối tượng mới để sử dụng trong tương lai.

const mapper = (obj, mapFn) => Object.keys(obj).reduce((result, key) => {
                result[key] = mapFn(obj)[key];
                return result;
            }, {});

var newImages = mapper(images, (value) => value);

Cách thức hoạt động của các chức năng này là như vậy:

mapFn lấy hàm để thêm vào sau (trong trường hợp này (value) => value) và chỉ cần trả về bất cứ thứ gì được lưu trữ ở đó làm giá trị cho khóa đó (hoặc nhân với hai nếu bạn thay đổi giá trị trả về như anh ta đã làm) trong mapFn ( obj) [khóa],

và sau đó xác định lại giá trị ban đầu được liên kết với khóa trong kết quả [key] = mapFn (obj) [key]

và trả về hoạt động được thực hiện trên kết quả (bộ tích lũy nằm trong dấu ngoặc được bắt đầu ở cuối hàm .reduce).

Tất cả điều này đang được thực hiện trên đối tượng đã chọn và VẪN CÓ THỂ yêu cầu ngầm định cho một mảng được trả về và chỉ hoạt động khi gán lại các giá trị theo như tôi có thể nói. Điều này đòi hỏi một số môn thể dục tinh thần nhưng làm giảm các dòng mã cần thiết như có thể thấy ở trên. Đầu ra giống hệt như có thể được nhìn thấy dưới đây:

{snow: "https://www.trbimg.com/img-5aa059f5/turbine/bs-   
md-weather-20180305", sunny: "http://www.cubaweather.org/images/weather-
photos/lmorning-east-Matanzas-city-Cuba-20170131-1080.jpg", rain: 
"https://i.pinimg.com/originals/23/d8
/ab/23d8ab1eebc72a123cebc80ce32b43d8.jpg"}

Hãy ghi nhớ điều này đã làm việc với NON-NUMBERS. Bạn có thể sao chép BẤT K object đối tượng nào bằng cách SIMPLY TRẢ LẠI GIÁ TRỊ trong hàm mapFN.


2

Hàm đầu tiên trả lời câu hỏi. Nó tạo ra một bản đồ.

Hàm thứ hai không tạo bản đồ. Thay vào đó, nó lặp qua các thuộc tính trong đối tượng hiện có bằng cách sử dụng hasOwnProperty(). Sự thay thế bản đồ này có thể là một giải pháp tốt hơn trong một số tình huống.

var myObject = { 'a': 1, 'b': 2, 'c': 3 }


//creates a map (answers question, but function below is 
//much better in some situations)
var newObject = {};
makeMap();    
function makeMap() {
    for (var k in myObject) {
        var value = myObject[k];
        newObject[k] = value * value;
    }
    console.log(newObject); //mapped array
}


//Doesn't create a map, just applies the function to
//a specific property using existing data
function getValue(key) {
  for (var k in myObject) {
    if (myObject.hasOwnProperty(key)) {
      var value = myObject[key]
      return value * value; //stops iteration
    }
  }
}
Input: <input id="input" value="" placeholder="a, b or c"><br>
Output:<input id="output"><br>
<button onclick="output.value=getValue(input.value)" >Get value</button>


2
Điều này không trả lời câu hỏi ban đầu - nó không ánh xạ các giá trị sang một đối tượng mới với hàm được cung cấp (nghĩa là đây không giống như Array.prototype.map).
Matt Browne

@MattBrowne Tôi đã thêm một phương thức thứ hai tạo ra cái được cho là bản đồ. Nó chậm, nhưng làm những gì OP yêu cầu. Phương thức đầu tiên là lý tưởng trong nhiều tình huống, đó là lý do tại sao tôi sử dụng các hàm vòng lặp và thuộc tính.
Victor Stoddard

1

Nếu bạn quan tâm đến mapping không chỉ các giá trị mà cả các khóa, tôi đã viết Object.map(valueMapper, keyMapper), nó hoạt động theo cách này:

var source = { a: 1, b: 2 };
function sum(x) { return x + x }

source.map(sum);            // returns { a: 2, b: 4 }
source.map(undefined, sum); // returns { aa: 1, bb: 2 }
source.map(sum, sum);       // returns { aa: 2, bb: 4 }

3
Tôi giả sử bởi vì về cơ bản bạn chỉ cung cấp một liên kết như một câu trả lời, được tán thành.
Chris Wright

Nếu có ích cho bất cứ ai : npm install @mattisg/object.map.
MattiSG

1

Tôi cũng cần một phiên bản cho phép sửa đổi các phím (dựa trên câu trả lời @Amberlamp và @yonatanmn);

var facts = [ // can be an object or array - see jsfiddle below
    {uuid:"asdfasdf",color:"red"},
    {uuid:"sdfgsdfg",color:"green"},
    {uuid:"dfghdfgh",color:"blue"}
];

var factObject = mapObject({}, facts, function(key, item) {
    return [item.uuid, {test:item.color, oldKey:key}];
});

function mapObject(empty, obj, mapFunc){
    return Object.keys(obj).reduce(function(newObj, key) {
        var kvPair = mapFunc(key, obj[key]);
        newObj[kvPair[0]] = kvPair[1];
        return newObj;
    }, empty);
}

factObject =

{
"asdfasdf": {"color":"red","oldKey":"0"},
"sdfgsdfg": {"color":"green","oldKey":"1"},
"dfghdfgh": {"color":"blue","oldKey":"2"}
}

Chỉnh sửa: thay đổi nhỏ để vượt qua trong đối tượng bắt đầu {}. Cho phép nó là [] (nếu các khóa là số nguyên)


1

Tôi đặc biệt muốn sử dụng cùng chức năng mà tôi đang sử dụng cho mảng cho một đối tượng và muốn giữ cho nó đơn giản. Điều này làm việc cho tôi:

var mapped = [item].map(myMapFunction).pop();

điều này không khác gìvar mapped = myMapFunction(item)
Cảm ơn bạn

Điều này rất đơn giản so với tất cả các giải pháp "tên lửa" khác mà tôi thấy ở đây. Cảm ơn đã chia sẻ :)
Yuri Teixeira

1

Để phản hồi chặt chẽ hơn với chính xác những gì OP yêu cầu, OP muốn có một đối tượng:

myObject = { 'a': 1, 'b': 2, 'c': 3 }

để có một phương pháp bản đồ myObject.map,

tương tự như Array.prototype.map sẽ được sử dụng như sau:

newObject = myObject.map (hàm (giá trị, nhãn) {
    giá trị trả về * giá trị;
});
// newObject hiện là {'a': 1, 'b': 4, 'c': 9}

Câu trả lời imho tốt nhất (được đo bằng thuật ngữ " gần với những gì được hỏi " + "không cần ES {5,6,7} không cần thiết") sẽ là:

myObject.map = function mapForObject(callback)
{
  var result = {};
  for(var property in this){
    if(this.hasOwnProperty(property) && property != "map"){
      result[property] = callback(this[property],property,this);
    }
  }
  return result;
}

Mã ở trên tránh cố ý sử dụng bất kỳ tính năng ngôn ngữ nào, chỉ có sẵn trong các phiên bản ECMAScript gần đây. Với đoạn mã trên, vấn đề có thể được giải quyết.

myObject = { 'a': 1, 'b': 2, 'c': 3 };

myObject.map = function mapForObject(callback)
{
  var result = {};
  for(var property in this){
    if(this.hasOwnProperty(property) && property != "map"){
      result[property] = callback(this[property],property,this);
    }
  }
  return result;
}

newObject = myObject.map(function (value, label) {
  return value * value;
});
console.log("newObject is now",newObject);
mã kiểm tra thay thế ở đây

Bên cạnh một số người cau mày, sẽ có khả năng chèn giải pháp vào chuỗi nguyên mẫu như thế này.

Object.prototype.map = function(callback)
{
  var result = {};
  for(var property in this){
    if(this.hasOwnProperty(property)){
      result[property] = callback(this[property],property,this);
    }
  }
  return result;
}

Một cái gì đó, khi được thực hiện với sự giám sát cẩn thận sẽ không có bất kỳ tác động xấu nào và không ảnh hưởng đến mapphương thức của các đối tượng khác (ví dụ như Array map).



1

Xác định một hàm mapEntries.

mapEntries có một hàm gọi lại được gọi trên mỗi mục trong đối tượng với giá trị tham số, khóa và đối tượng. Nó sẽ trả về một giá trị mới.

mapEntries sẽ trả về một đối tượng mới với các giá trị mới được trả về từ cuộc gọi lại.

Object.defineProperty(Object.prototype, 'mapEntries', {
  enumerable: false,
  value: function (mapEntriesCallback) {
    return Object.fromEntries(
      Object.entries(this).map(
        ([key, value]) => [key, mapEntriesCallback(value, key, this)]
      )
    )
  }
})


// Usage example:

var object = {a: 1, b: 2, c: 3}
var newObject = object.mapEntries(value => value * value)
console.log(newObject)
//> {a: 1, b: 4, c: 9}

Chỉnh sửa: Phiên bản trước không xác định rằng đây không phải là tài sản vô số


0

Hey đã viết một chức năng mapper có thể giúp đỡ.

    function propertyMapper(object, src){
         for (var property in object) {   
           for (var sourceProp in src) {
               if(property === sourceProp){
                 if(Object.prototype.toString.call( property ) === '[object Array]'){
                   propertyMapper(object[property], src[sourceProp]);
                   }else{
                   object[property] = src[sourceProp];
                }
              }
            }
         }
      }

1
Tôi đoán bạn có nghĩa là "Tôi" thay vì "Hey"
Carlo

0

Một cách khác là sử dụng hàm chuỗi json tùy chỉnh cũng có thể hoạt động trên các đối tượng sâu. Điều này có thể hữu ích nếu bạn có ý định đăng nó lên máy chủ dù là json

const obj = { 'a': 1, 'b': 2, x: {'c': 3 }}
const json = JSON.stringify(obj, (k, v) => typeof v === 'number' ? v * v : v)

console.log(json)
console.log('back to json:', JSON.parse(json))


0

Tôi chỉ xử lý các chuỗi để giảm miễn trừ:

Object.keys(params).map(k => typeof params[k] == "string" ? params[k] = params[k].trim() : null);

0

Đối tượng ánh xạ trong TypeScript

Tôi thích các ví dụ sử dụng Object.fromEntriesnhư ví dụ này , nhưng vẫn không dễ sử dụng. Các câu trả lời sử dụng Object.keysvà sau đó tìm kiếm keythực sự đang thực hiện nhiều tra cứu có thể không cần thiết.

Tôi ước có một Object.mapchức năng, nhưng chúng ta có thể tự tạo và gọi nó objectMapvới khả năng sửa đổi cả hai keyvalue:

Cách sử dụng (JavaScript):

const myObject = { 'a': 1, 'b': 2, 'c': 3 };

// keep the key and modify the value
let obj = objectMap(myObject, val => val * 2);
// obj = { a: 2, b: 4, c: 6 }


// modify both key and value
obj = objectMap(myObject,
    val => val * 2 + '',
    key => (key + key).toUpperCase());
// obj = { AA: '2', BB: '4', CC: '6' }

Mã (TypeScript):

interface Dictionary<T> {
    [key: string]: T;
}

function objectMap<TValue, TResult>(
    obj: Dictionary<TValue>,
    valSelector: (val: TValue, obj: Dictionary<TValue>) => TResult,
    keySelector?: (key: string, obj: Dictionary<TValue>) => string,
    ctx?: Dictionary<TValue>
) {
    const ret = {} as Dictionary<TResult>;
    for (const key of Object.keys(obj)) {
        const retKey = keySelector
            ? keySelector.call(ctx || null, key, obj)
            : key;
        const retVal = valSelector.call(ctx || null, obj[key], obj);
        ret[retKey] = retVal;
    }
    return ret;
}

Nếu bạn không sử dụng TypeScript thì hãy sao chép mã ở trên trong Sân chơi TypeScript để lấy mã JavaScript.

Ngoài ra, lý do tôi đặt keySelectorsau valSelectortrong danh sách tham số, là vì nó là tùy chọn.

* Một số tín dụng đi đến câu trả lời của alexander-mills .


0
const mapObject = (targetObject, callbackFn) => {
    if (!targetObject) return targetObject;
    if (Array.isArray(targetObject)){
        return targetObject.map((v)=>mapObject(v, callbackFn))
    }
    return Object.entries(targetObject).reduce((acc,[key, value]) => {
        const res = callbackFn(key, value);
        if (!Array.isArray(res) && typeof res ==='object'){
            return {...acc, [key]: mapObject(res, callbackFn)}
        }
        if (Array.isArray(res)){
            return {...acc, [key]: res.map((v)=>mapObject(v, callbackFn))}
        }
        return {...acc, [key]: res};
    },{})
};
const mapped = mapObject(a,(key,value)=> {
    if (!Array.isArray(value) && key === 'a') return ;
    if (!Array.isArray(value) && key === 'e') return [];
    if (!Array.isArray(value) && key === 'g') return value * value;
    return value;
});
console.log(JSON.stringify(mapped)); 
// {"b":2,"c":[{"d":2,"e":[],"f":[{"g":4}]}]}

Hàm này đi theo cách đệ quy thông qua đối tượng và mảng của các đối tượng. Các thuộc tính có thể bị xóa nếu trả về không xác định

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.