it-swarm-eu.dev

Kartenfunktion für Objekte (anstelle von Arrays)

Ich habe ein Objekt:

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

Ich suche nach einer systemeigenen Methode, die Array.prototype.map ähnelt und wie folgt verwendet wird:

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

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

Hat JavaScript eine solche map Funktion für Objekte? (Ich möchte dies für Node.JS, daher interessieren mich keine browserübergreifenden Probleme.)

833
Randomblue

Es gibt kein natives map für das Object -Objekt, aber wie wäre es damit:

_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 }_

Mit _for ... in_ können Sie jedoch problemlos über ein Objekt iterieren:

_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 }_

Update

Viele Leute erwähnen, dass die vorherigen Methoden kein neues Objekt zurückgeben, sondern das Objekt selbst bearbeiten. Aus diesem Grund wollte ich eine andere Lösung hinzufügen, die ein neues Objekt zurückgibt und das ursprüngliche Objekt so belässt, wie es ist:

_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': 1, 'b': 4, 'c': 6 }

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

Array.prototype.reduce reduziert ein Array auf einen einzelnen Wert, indem der vorherige Wert etwas mit dem aktuellen Wert zusammengeführt wird. Die Kette wird durch ein leeres Objekt _{}_ initialisiert. Bei jeder Iteration wird ein neuer Schlüssel von myObject mit seinem Quadrat als Wert hinzugefügt.

1232
Amberlamps

Wie wäre es mit einem Einzeiler mit sofortiger Variablenzuweisung in JS ( ES6/ES2015 )?

Verwendung der Syntax Spread-Operator und Name des berechneten Schlüssels :

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

jsbin

Eine andere Version mit redu:

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

jsbin

Erstes Beispiel als Funktion:

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

Wenn Sie ein verschachteltes Objekt rekursiv in einem functional -Stil zuordnen möchten, können Sie dies folgendermaßen tun:

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

Oder unbedingt so:

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

Seit ES7/ES2016 können Sie Object.entries() anstelle von Object.keys() verwenden, z. so was:

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

ES2019 könnte Object.fromEntries() einführen, was dies noch weiter vereinfacht:

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


Geerbte Eigenschaften und die Prototypenkette:

In einigen seltenen Situationen müssen Sie möglicherweise ein klassenähnliches Objekt zuordnen, das die Eigenschaften eines geerbten Objekts in seiner Prototyp-Kette enthält. In solchen Fällen funktioniert Object.keys() nicht, da Object.keys()inherited -Eigenschaften nicht auflistet. Wenn Sie geerbte Eigenschaften zuordnen müssen, sollten Sie for (key in myObj) {...} verwenden.

Hier ist ein Beispiel für ein Objekt, das die Eigenschaften eines anderen Objekts erbt und wie Object.keys() in einem solchen Szenario nicht funktioniert.

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

Bitte tun Sie mir jedoch einen Gefallen und vermeiden Sie Vererbung. :-)

239
Rotareti

Keine nativen Methoden, aber lodash # mapValues macht den Job brillant

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

Es ist ziemlich einfach, einen zu schreiben:

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;
}

mit Beispielcode:

> 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 }

Hinweis: In dieser Version können Sie auch (optional) den Kontext this für den Rückruf festlegen, genau wie bei der Methode Array.

EDIT - wurde geändert, um die Verwendung von Object.prototype zu entfernen, um sicherzustellen, dass es nicht mit einer vorhandenen Eigenschaft mit dem Namen map für das Objekt kollidiert.

56
Alnitak

Sie können Object.keys und dann forEach über das zurückgegebene Array von Schlüsseln verwenden:

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

Oder modularer:

_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; });
_

Beachten Sie, dass _Object.keys_ ein Array zurückgibt, das nur die eigenen aufzählbaren Eigenschaften des Objekts enthält. Daher verhält es sich wie eine _for..in_-Schleife mit einer hasOwnProperty -Prüfung.

25
Mattias Buelens

Dies ist gerade bs, und jeder in der JS-Community weiß es. Es gibt sollte diese Funktionalität:

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}

hier ist die naive Implementierung:

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;
};

es ist super nervig, das die ganze zeit selber umsetzen zu müssen;)

Wenn Sie etwas Feineres wünschen, das die Object-Klasse nicht beeinträchtigt, versuchen Sie Folgendes:

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;
});

es ist jedoch sicher, diese Zuordnungsfunktion zu Object hinzuzufügen. Fügen Sie sie einfach nicht zu Object.prototype hinzu.

Object.map = ... // fairly safe
Object.prototype.map ... // not ok
16
Alexander Mills

Ich bin hierher gekommen, um ein Objekt für die Zuordnung zu einem Array zu finden und zu beantworten, und habe diese Seite als Ergebnis erhalten. Falls Sie hierher gekommen sind, um nach der gleichen Antwort wie ich zu suchen, können Sie hier ein Array zuordnen und Einwände dagegen erheben.

Sie können map verwenden, um ein neues Array wie folgt aus dem Objekt zurückzugeben:

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

Die akzeptierte Antwort hat zwei Nachteile:

  • Es missbraucht Array.prototype.reduce, weil Reduzieren bedeutet, die Struktur eines zusammengesetzten Typs zu ändern, was in diesem Fall nicht der Fall ist.
  • Es ist nicht besonders wiederverwendbar

Ein funktionaler Ansatz für ES6/ES2015

Bitte beachten Sie, dass alle Funktionen in Curry-Form definiert sind.

// 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));
  • In Zeile A wird o neu zugewiesen. Da Javascript Referenzwerte übergibt durch Teilen , wird eine flache Kopie von o generiert. Wir sind jetzt in der Lage, o innerhalb von omap zu mutieren, ohne o im übergeordneten Bereich zu mutieren.
  • In Zeile B wird der Rückgabewert von map ignoriert, da map eine Mutation von o ausführt. Da dieser Nebeneffekt innerhalb von omap bleibt und im übergeordneten Bereich nicht sichtbar ist, ist er absolut akzeptabel.

Dies ist nicht die schnellste, sondern eine deklarative und wiederverwendbare Lösung. Dies ist dieselbe Implementierung wie eine einzeilige, prägnante, aber weniger lesbare:

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

Anhang - Warum können Objekte standardmäßig nicht iteriert werden?

ES2015 hat den Iterator und die iterierbaren Protokolle angegeben. Objekte sind jedoch immer noch nicht iterierbar und daher nicht abbildbar. Der Grund ist die Vermischung von Daten- und Programmebene .

12
user6445533

JavaScript hat gerade die neue Methode Object.fromEntries erhalten.

Beispiel

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)

Erläuterung

Der obige Code konvertiert das Objekt in ein verschachteltes Array ([[<key>,<value>], ...]), über das Sie eine Zuordnung vornehmen können. Object.fromEntries konvertiert das Array zurück in ein Objekt.

Das Tolle an diesem Muster ist, dass Sie jetzt Objektschlüssel beim Mappen leicht berücksichtigen können.

Dokumentation

Browser-Unterstützung

Object.fromEntries wird derzeit nur von diesen Browsern/Engines unterstützt, es sind jedoch Polyfills verfügbar (z. B. @ babel/polyfill ).

8
HaNdTriX

Minimale Version (es6):

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

Für maximale Leistung.

Wenn sich Ihr Objekt nicht oft ändert, aber häufig wiederholt werden muss, schlage ich vor, eine native Map als Cache zu verwenden.

// 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 funktioniert bereits in Chrome, Edge, Firefox und Beta Opera, ist also eine zukunftssichere Funktion. Es ist von ES7, also polyfill es https://github.com/es-shims/Object.entries für IE, wo es nicht funktioniert.

7
Pawel

sie können die map -Methode und forEach für Arrays verwenden. Wenn Sie sie jedoch für Object verwenden möchten, können Sie sie mit der folgenden Drehung verwenden:

Mit 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}

sing 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}

Oder Sie können auch andere Schleifen wie die $.each -Methode verwenden, wie im folgenden Beispiel gezeigt:

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

BEARBEITEN: Der kanonische Weg mit neueren JavaScript-Funktionen ist -

const identity = x =>
  x

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

Wobei o ein Objekt ist und f Ihre Zuordnungsfunktion ist. Oder wir könnten sagen, dass bei einer gegebenen Funktion von a -> b und einem Objekt mit Werten vom Typ a ein Objekt mit Werten vom Typ b erzeugt wird. Als Pseudotyp Signatur -

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

Die ursprüngliche Antwort wurde geschrieben, um einen mächtigen Kombinator zu demonstrieren, mapReduce, der es uns ermöglicht, unsere Transformation auf eine andere Weise zu betrachten

  1. m, die Zuordnungsfunktion - gibt Ihnen die Möglichkeit, das eingehende Element zu transformieren, bevor ...
  2. r, die reduzierende Funktion - diese Funktion kombiniert den Akkumulator mit dem Ergebnis des abgebildeten Elements

Intuitiv erstellt mapReduce einen neuen Reduzierer, den wir direkt in Array.prototype.reduce einstecken können. Aber was noch wichtiger ist, wir können unsere Implementierung des Objektfunktors omap einfach implementieren, indem wir das Objektmonoid Object.assign und {} verwenden.

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 }

Beachten Sie, dass der einzige Teil des Programms, den wir tatsächlich schreiben mussten, die Mapping-Implementierung selbst ist.

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

Welche besagt, dass bei einem bekannten Objekt o und einem bestimmten Schlüssel k ein Objekt erstellt wird und dessen berechnete Eigenschaft k das Ergebnis des Aufrufs von f für den Wert des Schlüssels ist, o[k].

Wir erhalten einen Einblick in das Sequenzierungspotential von mapReduce, wenn wir oreduce zuerst abstrahieren.

// 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
    )

Alles funktioniert gleich, aber omap kann jetzt auf einer höheren Ebene definiert werden. Natürlich macht der neue Object.entries dies albern, aber die Übung ist für den Lernenden immer noch wichtig.

Sie werden hier nicht das volle Potenzial von mapReduce sehen, aber ich teile diese Antwort, weil es interessant ist zu sehen, an wie vielen Stellen es angewendet werden kann. Wenn Sie daran interessiert sind, wie es abgeleitet wird und wie es auf andere Weise nützlich sein könnte, lesen Sie bitte diese Antwort .

4
user633183

Der map function existiert nicht auf dem Object.prototype, aber Sie können ihn so emulieren

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;
});
3
whitneyit

Ich bin darauf als erstes Element in einer Google-Suche gestoßen, um zu lernen, wie man das macht, und dachte, ich würde dies anderen Leuten mitteilen, die kürzlich die Lösung gefunden haben, die das unveränderliche npm-Paket verwendet.

Ich denke, es ist interessant zu teilen, weil unveränderlich die EXACT-Situation des OP in ihrer eigenen Dokumentation verwendet - das Folgende ist nicht mein eigener Code, sondern stammt aus der aktuellen unveränderlichen js-Dokumentation:

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 } 

Nicht, dass Seq andere Eigenschaften hat ("Seq beschreibt eine verzögerte Operation, die es ihnen ermöglicht, die Verwendung aller Sammlungsmethoden höherer Ordnung (wie Map und Filter) effizient zu verketten, indem keine Zwischensammlungen erstellt werden") und einige andere unveränderliche js-Daten Strukturen könnten die Arbeit auch sehr effizient erledigen.

Jeder, der diese Methode verwendet, muss natürlich npm install immutable und möchte möglicherweise die folgenden Dokumente lesen:

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

2
alex.h

Basierend auf der Antwort von @Amberlamps, hier ist eine Utility-Funktion (als Kommentar sah sie hässlich aus)

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

und die Verwendung ist:

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
yonatanmn
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 }
2
Dmitry Ragozin

Sie können eine einfache for-in-Schleife durch geordnete Paare verwenden. Ich habe hasOwnProperty() verwendet, weil Sie drei Eigenschaften (mit Werten) für Ihr Objekt erstellt haben. Die erste Methode erstellt keine Karte. Stattdessen wird die Funktion einfach auf ein einzelnes Element angewendet, wodurch die Ausführung in vielen Situationen erheblich beschleunigt werden kann.

Die zweite Methode erstellt eine Karte auf ähnliche Weise wie die erste, ist jedoch wahrscheinlich langsamer als einige andere Antworten.

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

//Doesn't create a map, just applies the function to a specific element
function getValue(key) {
  for (var k in myObject) {
    if (myObject.hasOwnProperty(key)) {
      var value = myObject[key]
      return value * value; //stops iteration
    }
  }
}

//creates a map (answers question, but above function is 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
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>
1
Victor Stoddard

Konvertieren Sie zunächst Ihre HTMLCollection mit Object.entries (collection). Dann ist es iterabel, dass Sie jetzt die .map-Methode verwenden können.

Object.entries(collection).map(...)

referenz https://medium.com/@js_tut/calling-javascript-code-on-multiple-div-elements-without-the-id-attribute-97ff6a50f31

1
Jimubao

Wenn Sie daran interessiert sind, nicht nur Werte, sondern auch Schlüssel mit mapping zu versehen, habe ich Object.map(valueMapper, keyMapper) geschrieben, das verhält sich folgendermaßen:

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 }
1
MattiSG

Ich brauchte eine Version, mit der auch die Schlüssel geändert werden konnten (basierend auf @Amberlamps und @yonatanmn Antworten).

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"}
}

Bearbeiten: leichte Änderung, um das Startobjekt {} zu übergeben. Lässt es zu [] (wenn die Schlüssel ganze Zahlen sind)

1
Symmetric

Object Mapper in TypeScript

Ich mag die Beispiele, die Object.fromEntries verwenden, wie dieses , aber sie sind nicht sehr einfach zu verwenden. Die Antworten, die Object.keys verwenden und dann key nachschlagen, führen tatsächlich mehrere Suchen durch, die möglicherweise nicht erforderlich sind.

Ich wünschte, es gäbe eine Object.map -Funktion, aber wir können unsere eigene erstellen und sie objectMap nennen, mit der Möglichkeit, sowohl key als auch value zu ändern:

Verwendung (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' }

Code (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;
}

Wenn Sie TypeScript nicht verwenden, kopieren Sie den obigen Code in TypeScript Playground , um den JavaScript-Code zu erhalten.

Der Grund, warum ich keySelector nach valSelector in die Parameterliste eingefügt habe, ist, dass dies optional ist.

* Ein Guthaben geht an Alexander-Mills ' Antwort .

1
orad

Definieren Sie eine Funktion mapEntries.

mapEntries übernimmt eine Callback-Funktion, die für jeden Eintrag im Objekt mit den Parametern Wert, Schlüssel und Objekt aufgerufen wird. Es sollte einen neuen Wert zurückgeben.

mapEntries sollte ein neues Objekt mit den vom Rückruf zurückgegebenen neuen Werten zurückgeben.

Object.prototype.mapEntries = function(mapEntriesCB) {
    return Object.fromEntries(Object.entries(this).map(
        ([key, value]) => [key, mapEntriesCB(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}
0
Arye Eidelman

Ich wollte genau die gleiche Funktion verwenden, die ich für Arrays für ein einzelnes Objekt verwendet habe, und wollte es einfach halten. Das hat bei mir funktioniert:

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

Hey hat eine kleine Mapper-Funktion geschrieben, die helfen könnte.

    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];
                }
              }
            }
         }
      }
0
Zak

Ich behandle nur Zeichenfolgen, um Ausnahmen zu reduzieren:

Object.keys(params).map(k => typeof params[k] == "string" ? params[k] = params[k].trim() : null);
0
Idan
settings = {
  message_notification: {
    value: true,
    is_active: true,
    slug: 'message_notification',
    title: 'Message Notification'
  },
  support_notification: {
    value: true,
    is_active: true,
    slug: 'support_notification',
    title: 'Support Notification'
  },
};

let keys = Object.keys(settings);
keys.map(key=> settings[key].value = false )
console.log(settings)
0
Akın Köker

ES6:

Object.prototype.map = function(mapFunc) {
    return Object.keys(this).map((key, index) => mapFunc(key, this[key], index));
}

ES2015:

Object.prototype.map = function (mapFunc) {
    var _this = this;

    return Object.keys(this).map(function (key, index) {
        return mapFunc(key, _this[key], index);
    });
};

test im Knoten:

> a = {foo: "bar"}
{ foo: 'bar' }
> a.map((k,v,i) => v)
[ 'bar' ]
0
Malix Ren

Meine Antwort basiert größtenteils auf der höchstbewerteten Antwort hier und hoffentlich versteht jeder (habe die gleiche Erklärung auch auf meinem GitHub). Deshalb funktioniert seine Implementierung mit map:

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

Der Zweck der Funktion besteht darin, ein Objekt zu übernehmen und den ursprünglichen Inhalt des Objekts mit einer Methode zu ändern, die allen Objekten (Objekten und Arrays gleichermaßen) zur Verfügung steht, ohne ein Array zurückzugeben. Fast alles in JS ist ein Objekt, und aus diesem Grund können Elemente, die sich weiter unten in der Vererbungspipeline befinden, potenziell die technisch verfügbaren Elemente verwenden (und umgekehrt).

Der Grund, warum dies funktioniert, ist, dass die .map-Funktionen ein Array zurückgeben, für das Sie eine explizite oder implizite RETURN-Anweisung für ein Array angeben müssen, anstatt einfach ein vorhandenes Objekt zu ändern. Sie täuschen das Programm im Grunde genommen vor, dass das Objekt ein Array ist, indem Sie Object.keys verwenden, mit denen Sie die Zuordnungsfunktion verwenden können, die auf die Werte wirkt, denen die einzelnen Schlüssel zugeordnet sind (ich habe tatsächlich versehentlich Arrays zurückgegeben, sie jedoch behoben). Solange es keine Rückkehr im normalen Sinne gibt, wird kein Array erstellt, bei dem das ursprüngliche Objekt noch intakt und wie programmiert modifiziert ist.

Dieses spezielle Programm nimmt ein Objekt namens images, nimmt die Werte seiner Schlüssel und hängt URL-Tags zur Verwendung in einer anderen Funktion an. Original ist das:

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' };

... und modifiziert ist dies:

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') 
};

Die ursprüngliche Struktur des Objekts bleibt erhalten und ermöglicht den normalen Zugriff auf das Eigentum, solange keine Rückgabe erfolgt. Lassen Sie es NICHT wie gewohnt ein Array zurückgeben und alles wird gut. Das Ziel ist es, die ursprünglichen Werte (Bilder [Schlüssel]) dem zuzuordnen, was gewünscht wird und nichts anderes. Soweit ich weiß, MUSS eine Neuzuordnung von Bildern [Schlüssel] und keine implizite oder explizite Aufforderung zur Rückgabe eines Arrays erfolgen, um die Ausgabe von Arrays zu verhindern (die variable Zuweisung führt dies aus und lief für mich fehlerhaft vor und zurück).

BEARBEITEN:

Gehen Sie auf seine andere Methode zur Erstellung neuer Objekte ein, um das Ändern des ursprünglichen Objekts zu vermeiden (und eine Neuzuweisung scheint dennoch erforderlich zu sein, um zu verhindern, dass versehentlich ein Array als Ausgabe erstellt wird). Diese Funktionen verwenden die Pfeilsyntax und dienen dazu, ein neues Objekt für die zukünftige Verwendung zu erstellen.

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

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

Die Funktionsweise dieser Funktionen ist wie folgt:

mapFn übernimmt die später hinzuzufügende Funktion (in diesem Fall (value) => value) und gibt einfach das, was dort gespeichert ist, als Wert für diesen Schlüssel zurück (oder multipliziert mit zwei, wenn Sie den Rückgabewert wie er geändert haben) in mapFn ( obj) [key],

und definiert dann den ursprünglichen Wert, der dem Schlüssel in result [key] = mapFn (obj) [key] zugeordnet ist, neu.

und gibt die am Ergebnis ausgeführte Operation zurück (der Akkumulator, der sich in den Klammern befindet, die am Ende der .reduce-Funktion eingeleitet wurden).

All dies wird für das ausgewählte Objekt ausgeführt, und es KANN NOCH KEINE implizite Anforderung für ein zurückgegebenes Array geben. Dies funktioniert nur, wenn Werte neu zugewiesen werden, soweit ich das beurteilen kann. Dies erfordert einige mentale Gymnastik, reduziert aber die Codezeilen, wie oben zu sehen ist. Die Ausgabe ist genau die gleiche wie unten zu sehen:

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

Denken Sie daran, dass dies mit NON-NUMBERS funktioniert hat. Sie können jedes Objekt duplizieren, indem Sie den Wert einfach in der mapFN-Funktion zurückgeben.

0
Andrew Ramshaw