Zugriff auf JavaScript-Eigenschaft ohne Berücksichtigung der Groß- und Kleinschreibung?

78

Angenommen, ich habe ein Objekt:

var obj = {
  foo:"bar",
  fizz:"buzz"
};

Ich muss dynamisch auf eine Eigenschaft dieses Objekts zugreifen, wie folgt:

var objSetter = function(prop,val){
  obj[prop] = val;
}

Dort gibt es keine Probleme, außer dass propdie Groß- und Kleinschreibung nicht berücksichtigt werden muss, wenn der Eigenschaftsname beispielsweise Fooanstelle von an die Funktion übergeben wird foo.

Wie kann ich also ohne Rücksicht auf die Groß- und Kleinschreibung namentlich auf die Eigenschaft eines Objekts verweisen? Ich möchte nach Möglichkeit vermeiden, das gesamte Objekt zu wiederholen.

Matt Cashatt
quelle
7
Das kannst du nicht. Die Sprache unterscheidet zwischen Groß- und Kleinschreibung. Denken Sie überobj = {foo: true, Foo: false}
user123444555621
Behalten Sie Ihre tatsächlichen Eigenschaftsnamen immer in Kleinbuchstaben (oder Großbuchstaben) bei und konvertieren Sie sie dann bei der Abfrage.
Pointy
Wenn Sie "foo" anstelle von "Foo" erwarten, können Sie propvor der Verwendung in "niedriger " konvertieren .
Claudio Redi
1
Ein Blick auf JavaScript-Proxy-Objekte, die implementiert werden sollen, ist effektiv ein Mittel zum Ändern eines Platzhalter-Getter: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Zach Smith
Mach das nicht. Stellen Sie keine Mechanismen mehr bereit, um eine schlampige Entwicklung zu ermöglichen. Bei den Tasten wird zwischen Groß- und Kleinschreibung unterschieden. Wenn Sie jemand anderem erlauben, einen Schlüssel mit einer anderen Groß- und Kleinschreibung zu verwenden, erlauben Sie ihm, beschissenen Code zu erstellen, der schwer zu pflegen ist, ganz zu schweigen von langsamer, da Sie speziellen Code ausführen müssen, damit die Schlüssel übereinstimmen, wenn sie nicht sollten.
Intervalia

Antworten:

27

Vergleichen Sie alle Eigenschaften von obj mit prop.

var objSetter = function(prop,val){
  prop = (prop + "").toLowerCase();
  for(var p in obj){
     if(obj.hasOwnProperty(p) && prop == (p+ "").toLowerCase()){
           obj[p] = val;
           break;
      }
   }
}
Anoop
quelle
2
Vielen Dank. Dies wird sicherlich funktionieren, aber ich hoffe, dass ich nicht über ganze Objekte iterieren kann. Ich werde meinen Beitrag bearbeiten, um das klarer zu machen. Danke noch einmal.
Matt Cashatt
Danke Shusl, es sieht so aus, als wäre eine Iteration meine einzige Option. Kannst du mir bitte auch sagen, wofür das + ""ist? Ist dies nur für die Zeichenfolgenkonvertierung?
Matt Cashatt
1
Stellen Sie sicher, dass toLowerCase auf die Zeichenfolge angewendet wird. Z.B. (1 + "") konvertiert 1 in "1".
Anoop
16
Es ist nicht erforderlich, peine Zeichenfolge zu erzwingen . ECMA-262 gibt Objekteigenschaften als Zeichenfolgen an. Jeder Benutzeragent oder Host, der nicht konform war, hätte ernsthafte Probleme. Es besteht auch keine Notwendigkeit für break, sollten Sie verwenden return.
RobG
2
Ich habe dies an einem Objekt mit über 1 Million Schlüsseln versucht und es ist unerträglich langsam. Ein besserer Ansatz wäre die Verwendung eines Proxy-Objekts ( developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ). Oder fügen Sie dem Wörterbuch zunächst Schlüssel als Großbuchstaben hinzu, wenn Ihr Anwendungsfall dies zulässt
Zach Smith,
40

Versuche dies:

var myObject = { "mIxeDCaSEKeY": "value" };

var searchKey = 'mixedCaseKey';
myObject[Object.keys(myObject).find(key => key.toLowerCase() === searchKey.toLowerCase())];

Alternativ können Sie den searchKey bereits in Kleinbuchstaben angeben.

Wenn Sie es als Funktion wollen:

/**
  * @param {Object} object
  * @param {string} key
  * @return {any} value
 */
function getParameterCaseInsensitive(object, key) {
  return object[Object.keys(object)
    .find(k => k.toLowerCase() === key.toLowerCase())
  ];
}

Wenn das Objekt nicht gefunden werden kann, wird es wie gewohnt undefiniert zurückgegeben.

Wenn Sie ältere Browser unterstützen müssen, können Sie filterstattdessen Folgendes verwenden:

function getParameterCaseInsensitive(object, key) {
  return object[Object.keys(object).filter(function(k) {
    return k.toLowerCase() === key.toLowerCase();
  })[0]];
}

Ich empfehle die Verwendung der Polyfills für Object.keys () und Array.filter (), wenn Sie noch ältere Unterstützung benötigen.

ShortFuse
quelle
Ich war neugierig, woher der Stil der Dokumentationskommentare stammt. Dann fand ich jsdoc.app/about-getting-started.html
Michael Freidgeim
1
TypeScript liest auch JSDocs nativ und führt eine Typprüfung durch. Es ist direkt in VSCode integriert, was das Leben einfacher macht.
ShortFuse
10

Aus diesem Grund bevorzuge ich die Verwendung des Prototyps gegenüber einer eigenständigen Funktion, um die Benutzerfreundlichkeit und Ausdruckskraft zu verbessern. Ich mag es einfach nicht, Objekte in Funktionen zu leiten, wenn ich nicht muss.

Während die akzeptierte Antwort funktioniert, wollte ich eine umfassendere Lösung zum Abrufen und Einstellen, die sich so ähnlich wie die native Punktnotation oder Klammernotation wie möglich verhält.

Vor diesem Hintergrund habe ich einige Prototypfunktionen zum Festlegen / Abrufen einer Objekteigenschaft ohne Rücksicht auf die Groß- und Kleinschreibung erstellt. Sie müssen daran denken, beim Hinzufügen zum Objektprototyp SEHR verantwortlich zu sein. Besonders bei Verwendung von JQuery und anderen Bibliotheken. Object.defineProperty () mit der Aufzählung false wurde speziell verwendet, um Konflikte mit JQuery zu vermeiden. Ich habe mich auch nicht darum gekümmert, die Funktionen so zu benennen, dass sie nicht zwischen Groß- und Kleinschreibung unterscheiden, aber Sie könnten es auf jeden Fall. Ich mag kürzere Namen.

Hier ist der Getter:

Object.defineProperty(Object.prototype, "getProp", {
    value: function (prop) {
        var key,self = this;
        for (key in self) {
            if (key.toLowerCase() == prop.toLowerCase()) {
                return self[key];
            }
        }
    },
    //this keeps jquery happy
    enumerable: false
});

Hier ist der Setter:

Object.defineProperty(Object.prototype, "setProp", {
    value: function (prop, val) {
        var key,self = this;
        var found = false;
        if (Object.keys(self).length > 0) {
            for (key in self) {
                if (key.toLowerCase() == prop.toLowerCase()) {
                    //set existing property
                    found = true;                        
                    self[key] = val;
                    break;
                }
            }
        }

        if (!found) {
            //if the property was not found, create it
            self[prop] = val;
        }  

        return val;
    },
    //this keeps jquery happy
    enumerable: false
});

Nachdem wir diese Funktionen erstellt haben, ist unser Code sehr sauber und präzise und funktioniert einfach.

Groß- und Kleinschreibung wird nicht berücksichtigt:

var obj = {foo: 'bar', camelCase: 'humpy'}

obj.getProp("FOO");          //returns 'bar'
obj.getProp("fOO");          //returns 'bar'
obj.getProp("CAMELCASE");    //returns 'humpy' 
obj.getProp("CamelCase");    //returns 'humpy'

Groß- und Kleinschreibung wird nicht berücksichtigt:

var obj = {foo: 'bar', camelCase: 'humpy'}

obj.setProp('CAmelCasE', 'super humpy');     //sets prop 'camelCase' to 'super humpy'
obj.setProp('newProp', 'newval');      //creates prop 'newProp' and sets val to 'newval'  
obj.setProp('NewProp', 'anotherval');  //sets prop 'newProp' to 'anotherval'
Matt Goodwin
quelle
1
Natürlich wird dies schrecklich scheitern, wenn jemand es tutobj.setProp("GETPROP")
Bergi
6

Noch eine Variation der bereits vorgestellten, die die Iteration in die Underscore / Lodash- findKeyFunktion drückt :

var _ = require('underscore');
var getProp = function (obj, name) {
    var realName = _.findKey(obj, function (value, key) {
        return key.toLowerCase() === name.toLowerCase();
    });
    return obj[realName];
};

Zum Beispiel:

var obj = { aa: 1, bB: 2, Cc: 3, DD: 4 };
getProp(obj, 'aa'); // 1
getProp(obj, 'AA'); // 1
getProp(obj, 'bb'); // 2
getProp(obj, 'BB'); // 2
getProp(obj, 'cc'); // 3
getProp(obj, 'CC'); // 3
getProp(obj, 'dd'); // 4
getProp(obj, 'DD'); // 4
getProp(obj, 'EE'); // undefined
Rusty Shackleford
quelle
Wie underscoreimplementiert die Bibliothek dies? Dh ich suche nach einem Weg, der keine lineare Suche der Schlüssel eines Objekts beinhaltet
Zach Smith
2
@ZachSmith Es ist O (n); siehe hier .
Rusty Shackleford
3

Sie könnten dies tun, um "zu normalisieren" prop

 var normalizedProp = prop.toLowerCase();
 obj[normalizedProp] = val;
Claudio Redi
quelle
1
Vielen Dank. Ich sehe, wie in propKleinbuchstaben umgewandelt wird, aber was ist, wenn ich nicht garantieren kann, dass der tatsächliche Eigenschaftsname nur in Kleinbuchstaben geschrieben wird? Vielleicht fehlt mir etwas?
Matt Cashatt
1
@MatthewPatrickCashatt Sie vermissen nichts: Es gibt nichts zu verpassen - weil es nichts in der Sprache gibt, um hier zu helfen :)
3
Grund für die Abwertung: Dies beantwortet die Frage nicht, da wie bei der Antwort von @ RobG davon ausgegangen wird, dass die Eigenschaft in Kleinbuchstaben geschrieben ist.
Matt Goodwin
1

Es ist keine Iteration erforderlich. Da es sich propmöglicherweise nicht um eine Zeichenfolge handelt, sollte sie gegebenenfalls zuerst zu einer Zeichenfolge gezwungen werden, da Objekte dies nativ tun. Eine einfache Getter-Funktion ist:

function objGetter(prop) {
  return obj[String(prop).toLowerCase()];
}

Wenn es erforderlich ist, den Zugriff auf eigene Immobilien zu beschränken:

function objGetter(prop) {
  prop = String(prop).toLowerCase();

  if (obj.hasOwnProperty(prop)) {
    return obj.prop;
  }
}

und ein Setter:

function objSetter(prop, val) {
  obj[String(prop).toLowerCase()] = val;
}
RobG
quelle
2
Dies setzt voraus, dass alle Eigenschaften des Quellobjekts in Kleinbuchstaben geschrieben sind.
Chris Haines
Stimmen Sie mit @Hainesy überein, dies setzt einen Fall voraus, der im Widerspruch zu dem steht, worum es bei der Frage ging.
Matt Goodwin
@ MattGoodwin - Sie haben anscheinend den Setter verpasst, der die Eigenschaft mit einem Kleinbuchstaben erstellt.
RobG
@RobG Mein Problem mit dieser Antwort ist, dass Ihre Lösung bei einem Objekt mit unbestimmten Eigenschaftsnamen den Wert nur abrufen würde, wenn die Eigenschaften selbst ursprünglich mit Ihren Methoden erstellt wurden oder die Eigenschaften zufällig in Kleinbuchstaben geschrieben wurden. Ich glaube, der Fragesteller hat nach einer Möglichkeit gefragt, auf Objekteigenschaften zuzugreifen, wenn der Fall dieser Eigenschaften nicht im Voraus bekannt ist.
Matt Goodwin
@ MattGoodwin, lesen Sie die Frage des Autors noch einmal. Er impliziert nicht, dass er keine Kontrolle über das Objekt hat. Die Frage ist spezifisch für den Fall, propdass dies an die Funktion objSetter () übergeben wird. Tatsächlich impliziert die Einbeziehung der Funktion objSetter () durch die Fragesteller in erster Linie stark, dass der Autor die Kontrolle über die Erstellung des Objekts hat. Eine Antwort, die besagt, dass die Eigenschaftsnamen auf Kleinbuchstaben normiert werden müssen und dabei Unterstützung bieten, ist eine vernünftige Antwort. Wenn der Autor darüber hinaus mehr benötigt, kann der Autor dies in einem Kommentar oder durch Bearbeiten der Frage klarstellen.
Bobpaul
1

Warum sollten wir es so kompliziert machen, wenn wir einfach alles in Kleinbuchstaben schreiben können:

    var your_object = { 
"chickago" : 'hi' ,
 "detroit" : 'word', 
 "atlanta" : 'get r dun',     
GetName: function (status) {
        return this[status].name;
    } };

um es zu nennen: your_object.GetName(your_var.toLowerCase());

KaiOsmon
quelle
5
Dies setzt voraus, dass Sie die Kontrolle über die Objekterstellung haben und dass die Schlüssel im Objekt in Kleinbuchstaben geschrieben sind
velop
1

Es scheint mir ein guter Kandidat für Proxy mit Traps zu sein, um Zeichenfolgenschlüssel entweder in Groß- oder Kleinbuchstaben umzuwandeln und sich wie ein normales Objekt zu verhalten. Dies funktioniert entweder mit Notation: Punkten oder Klammern

Hier ist der Code:

'use strict';

function noCasePropObj(obj)
{
	var handler =
	{
		get: function(target, key)
			{
				//console.log("key: " + key.toString());
				if (typeof key == "string")
				{
					var uKey = key.toUpperCase();

					if ((key != uKey) && (key in target))
						return target[key];
					return target[uKey];
				}
				return target[key];
			},
		set: function(target, key, value)
			{
				if (typeof key == "string")
				{
					var uKey = key.toUpperCase();

					if ((key != uKey) && (key in target))
						target[key] = value;
					target[uKey] = value;
				}
				else
					target[key] = value;
			},
		deleteProperty: function(target, key)
			{
				if (typeof key == "string")
				{
					var uKey = key.toUpperCase();

					if ((key != uKey) && (key in target))
						delete target[key];
					if (uKey in target)
						delete target[uKey];
				}
				else
					delete target[key];
			},
	};
	function checkAtomic(value)
	{
		if (typeof value == "object")
			return new noCasePropObj(value); // recursive call only for Objects
		return value;
	}

	var newObj;

	if (typeof obj == "object")
	{
		newObj = new Proxy({}, handler);
        // traverse the Original object converting string keys to upper case
		for (var key in obj)
		{
			if (typeof key == "string")
			{
				var objKey = key.toUpperCase();

				if (!(key in newObj))
					newObj[objKey] = checkAtomic(obj[key]);
			}
		}
	}
	else if (Array.isArray(obj))
	{
        // in an array of objects convert to upper case string keys within each row
		newObj = new Array();
		for (var i = 0; i < obj.length; i++)
			newObj[i] = checkAtomic(obj[i]);
	}
	return newObj; // object with upper cased keys
}

// Use Sample:
var b = {Name: "Enrique", last: "Alamo", AdDrEsS: {Street: "1233 Main Street", CITY: "Somewhere", zip: 33333}};
console.log("Original: " + JSON.stringify(b));  // Original: {"Name":"Enrique","last":"Alamo","AdDrEsS":{"Street":"1233 Main Street","CITY":"Somewhere","zip":33333}}
var t = noCasePropObj(b);
console.log(JSON.stringify(t)); // {"NAME":"Enrique","LAST":"Alamo","ADDRESS":{"STREET":"1233 Main Street","CITY":"Somewhere","ZIP":33333}}
console.log('.NaMe:' + t.NaMe); // .NaMe:Enrique
console.log('["naME"]:' + t["naME"]); // ["naME"]:Enrique
console.log('.ADDreSS["CitY"]:' + t.ADDreSS["CitY"]); // .ADDreSS["CitY"]:Somewhere
console.log('check:' + JSON.stringify(Object.getOwnPropertyNames(t))); // check:["NAME","LAST","ADDRESS"]
console.log('check2:' + JSON.stringify(Object.getOwnPropertyNames(t['AddresS']))); // check2:["STREET","CITY","ZIP"]

Enrique Alamo
quelle
1
const getPropertyNoCase = (obj, prop) => obj[Object.keys(obj).find(key => key.toLowerCase() === prop.toLowerCase() )];

oder

const getPropertyNoCase = (obj, prop) => {
    const lowerProp = prop.toLowerCase(obj[Object.keys(obj).find(key => key.toLowerCase() === prop.toLowerCase() )];
}
Yaron Pdut
quelle
0

Hier ist ein sehr einfacher Code, um dies zu tun. Angenommen, Daten sind das Array von Objekten wie

data=[{"A":"bc","B":"nn"}]

var data=data.reduce(function(prev, curr) {
    var cc = curr; // current value
    var K = Object.keys(cc); // get all keys
    var n = {};
    for (var i = 0; i < K.length; i++) {
        var key = K[i];//get hte key

        n[key.toLowerCase()] = cc[key] // convert to lowercase and assign 
    }
    prev.push(n) // push to array
    return prev;
}, [])

Ausgabe wird sein

data=[{"a":"bc","b":"nn"}]
prajnavantha
quelle
0

Möglicherweise müssen Sie nur zwischen Groß- und Kleinschreibung unterscheiden (normalerweise teuer aufgrund von Objektiteration), wenn eine Übereinstimmung zwischen Groß- und Kleinschreibung (billig und schnell) fehlschlägt.

Angenommen, Sie haben:

var your_object = { "Chicago" : 'hi' , "deTroiT" : 'word' , "atlanta" : 'get r dun' } ;

Und Sie haben aus irgendeinem Grund den Wert Detroit:

if( your_object.hasOwnProperty( the_value ) ) 
  { 
    // do what you need to do here
  } 
else  
  { // since the case-sensitive match did not succeed, 
    //   ... Now try a the more-expensive case-insensitive matching

    for( let lvs_prop in your_object ) 
      { if( the_value.toLowerCase()  == lvs_prop.toLowerCase() ) 
          { 

            // do what you need to do here

            break ;
          } ;
      } 
  } ;
dsdsdsdsd
quelle
0

Ein anderer einfacher Weg:

function getVal(obj, prop){
var val;
  prop = (prop + "").toLowerCase();
  for(var p in obj){
     if(obj.hasOwnProperty(p) && prop == (p+ "").toLowerCase()){
           val = obj[p]
           break;
      }
   }
   return val;
}

Verwenden Sie es so:

var obj = {
  foo:"bar",
  fizz:"buzz"
};
    getVal(obj,"FoO") -> returns "bar"
GorvGoyl
quelle
0

Diese Antwort erfordert ES6.

const x = {'X-Total-Count':10};
console.log(x[Object.keys(x).reduce(key=>{return key.match(/x-total-count/i)})]);

nilloc
quelle
0

Hier ist eine nette rekursive Funktion, mit der Sie ein Javascript-Objekt ohne Berücksichtigung der Groß- und Kleinschreibung durchlaufen können:

let testObject = {'a': {'B': {'cC': [1,2,3]}}}
let testSeq = ['a','b','cc']

function keySequence(o, kseq) {
  if(kseq.length==0){ return o; }
  let validKeys = Object.keys(o).filter(k=>k.toLowerCase()==kseq[0].toLowerCase());
  if(validKeys.length==0) { return `Incorrect Key: ${kseq[0]}` }
  return keySequence(o[validKeys[0]], kseq.slice(1))
}

keySequence(testObject, testSeq); //returns [1,2,3]
cbartondock
quelle