बिना म्यूटेशन के ऑब्जेक्ट से वैल्यू निकालें


101

मूल वस्तु को म्यूट किए बिना किसी विशिष्ट कुंजी पर किसी वस्तु से मूल्य निकालने का एक अच्छा और छोटा तरीका क्या है?

मैं कुछ करना चाहूंगा जैसे:

let o = {firstname: 'Jane', lastname: 'Doe'};
let o2 = doSomething(o, 'lastname');
console.log(o.lastname); // 'Doe'
console.log(o2.lastname); // undefined

मुझे पता है कि इस तरह के कार्यों के लिए बहुत सारी अपरिवर्तनीय पुस्तकालय हैं, लेकिन मैं पुस्तकालय के बिना दूर जाना चाहूंगा। लेकिन ऐसा करने के लिए, एक आवश्यकता के लिए एक आसान और छोटा तरीका होना चाहिए जो कि पूरे कोड का उपयोग किया जा सकता है, एक उपयोगिता फ़ंक्शन के रूप में विधि को अलग किए बिना।

उदाहरण के लिए मैं निम्नलिखित कार्य करता हूं:

let o2 = {...o1, age: 31};

यह काफी छोटा है, याद रखने में आसान है और उपयोगिता फ़ंक्शन की आवश्यकता नहीं है।

क्या कोई मूल्य निकालने के लिए ऐसा है? ES6 बहुत स्वागत है।

आपका बहुत बहुत धन्यवाद!


"ऑब्जेक्ट को म्यूट किए बिना एक मान निकालें" कोई मतलब नहीं है। आप किसी चीज़ को हटा नहीं सकते और उसे उसी समय बरकरार रख सकते हैं। आप वास्तव में क्या कर रहे हैं एक आंशिक प्रतिलिपि बना रहा है।
JJJ

जवाबों:


224

अपडेट करें:

आप एक ऑब्जेक्ट से एक ट्रिकी विनाशकारी असाइनमेंट के साथ एक संपत्ति निकाल सकते हैं :

const doSomething = (obj, prop) => {
  let {[prop]: omit, ...res} = obj
  return res
}

हालाँकि, यदि आप जिस प्रॉपर्टी का नाम हटाना चाहते हैं वह स्थिर है, तो आप इसे साधारण वन-लाइनर के साथ हटा सकते हैं:

let {lastname, ...o2} = o

सबसे आसान तरीका यह है कि आप इसे बदलने से पहले अपनी वस्तु को क्लोन कर सकते हैं:

const doSomething = (obj, prop) => {
  let res = Object.assign({}, obj)
  delete res[prop]
  return res
}

वैकल्पिक रूप से आप उपयोगिता पुस्तकालय omitसे फ़ंक्शन काlodash उपयोग कर सकते हैं :

let o2 = _.omit(o, 'lastname')

यह लॉश पैकेज के एक भाग के रूप में, या एक स्टैंडअलोन लॉश.ओमिट पैकेज के रूप में उपलब्ध है।


3
क्या यह वास्तव में सबसे सरल उपाय है? उदाहरण के लिए, आप a2 = a1.filter(el => el.id !== id)किसी सरणी के भीतर एक विशिष्ट आईडी द्वारा एक तत्व को छोड़ना कर सकते हैं । क्या किसी वस्तु के लिए ऐसा नहीं है?
अमन

1
मैं @amann से सहमत हूं। या तो वहाँ है एक बेहतर समाधान, या ES6 वास्तव में एक अधिक कार्यात्मक रास्ते में जे एस प्रयोग करने योग्य बनाने के बारे में कुछ याद किया। उदाहरण के लिए। रूबी नेkeep_if
अगस्तिन रिडिंगर को

1
@AugustinRiedinger वास्तव में, एक तरीका है। मेरा अपडेट देखें।
लियोनिद बेस्चस्टानी

1
अद्यतन विनाशकारी समाधान महान है। हालांकि मेरा दिमाग इससे थोड़ा उड़ा है। const {[prop], ...rest} = objकाम क्यों नहीं करेगा ? आपको निकाली गई संपत्ति को एक नए चर ( omitइस मामले में) को क्यों सौंपना है ?
ब्रानवेब

1
@ एंटोनी 4 आप अपने no-unused-varsनियम में "लोप" या "लोप" जोड़ सकते हैं , यह सिर्फ रेगेक्स है।
एड्रिनमेक

33

ES7 ऑब्जेक्ट विनाशकारी के साथ:

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

1
क्या होगा अगर aएक चर में संग्रहीत किया जाता है const x = 'a'?
FFF

कुछ भी नहीं बदलता है। एक ही सरणी के पहले तत्व को संदर्भित करता है। यह इस तरह से हो सकता है: const { a,b, ...noA } = myObject; console.log(noA); // => {c: 3 }
सेन

1
यह सबसे सुंदर, सरल समाधान है
जो

1
क्या ऐसा करने का कोई तरीका है अगर चाबियाँ नंबर हैं?
मार्क स्लॉथ ईस्टमैन

25

एक लाइन समाधान

const removeKey = (key, {[key]: _, ...rest}) => rest;

4

जैसा कि ऊपर की टिप्पणियों में सुझाया गया है यदि आप इसे अपने द्वारा objectउपयोग किए जाने वाले एक से अधिक आइटम को निकालने के लिए विस्तारित करना चाहते हैं filter। तथाreduce

जैसे

    const o = {
      "firstname": "Jane",
      "lastname": "Doe",
      "middlename": "Kate",
      "age": 23,
      "_id": "599ad9f8ebe5183011f70835",
      "index": 0,
      "guid": "1dbb6a4e-f82d-4e32-bb4c-15ed783c70ca",
      "isActive": true,
      "balance": "$1,510.89",
      "picture": "http://placehold.it/32x32",
      "eyeColor": "green",
      "registered": "2014-08-17T09:21:18 -10:00",
      "tags": [
        "consequat",
        "ut",
        "qui",
        "nulla",
        "do",
        "sunt",
        "anim"
      ]
    };

    const removeItems = ['balance', 'picture', 'tags']
    console.log(formatObj(o, removeItems))

    function formatObj(obj, removeItems) {
      return {
        ...Object.keys(obj)
          .filter(item => !isInArray(item, removeItems))
          .reduce((newObj, item) => {
            return {
              ...newObj, [item]: obj[item]
            }
          }, {})
      }
    }

    function isInArray(value, array) {
      return array.indexOf(value) > -1;
    }


1
आप फ़िल्टर स्थिति को कम में क्यों लागू नहीं करते हैं, ताकि आप अपने आप को एक लूप बचा सकें?
इवो ​​सबव

टिप के लिए धन्यवाद @IvoSabev मेरे कोड में कुछ फ़ंक्शन हैं जहां मैं फ़िल्टर करता हूं फिर कम करता हूं लेकिन लूप को बचाने के लिए आपके सुझाव को आगे बढ़ाने पर विचार करेगा।
ak85

4

प्रदर्शन में कुछ मसाला लाने के लिए। इस थ्रेड बॉलो की जाँच करें

https://github.com/googleapis/google-api-nodejs-client/issues/375

डिलीट ऑपरेटर के उपयोग से V8 छिपे हुए क्लास पैटर्न के लिए प्रदर्शन नकारात्मक प्रभाव पड़ता है। सामान्य तौर पर यह अनुशंसित है कि इसका उपयोग न करें।

वैकल्पिक रूप से, अपने स्वयं के गुणों को हटाने के लिए, हम उन गुणों के बिना एक नई ऑब्जेक्ट कॉपी बना सकते हैं (उदाहरण के लिए लॉश का उपयोग करते हुए):

_.ओमिट (ओ, 'प्रोप', 'प्रोप 2')

या यहां तक ​​कि संपत्ति के मान को शून्य या अपरिभाषित करने के लिए परिभाषित करें (जो कि JSON पर क्रमिक रूप से नजरअंदाज कर दिया गया है):

o.prop = अपरिभाषित

आप विनाशकारी तरीके का भी उपयोग कर सकते हैं

const {remov1, remov2, ...new} = old;
old = new;

और अधिक व्यावहारिक छूट:

this._volumes[this._minCandle] = undefined;
{ 
     const {[this._minCandle]: remove, ...rest} = this._volumes;
     this._volumes = rest; 
}

जैसा कि आप देख सकते हैं आप [somePropsVarForDynamicName]: scopeVarNameगतिशील नामों के लिए वाक्यविन्यास का उपयोग कर सकते हैं । और आप सभी कोष्ठक (नए ब्लॉक) में रख सकते हैं, इसलिए बाकी कचरा इसके बाद एकत्र किया जाएगा।

यहाँ एक परीक्षण: यहाँ छवि विवरण दर्ज करें

कार्यकारी:

यहाँ छवि विवरण दर्ज करें

या हम कुछ फ़ंक्शन के साथ जा सकते हैं जैसे

function deleteProps(obj, props) {
    if (!Array.isArray(props)) props = [props];
    return Object.keys(obj).reduce((newObj, prop) => {
        if (!props.includes(prop)) {
            newObj[prop] = obj[prop];
        }
        return newObj;
    }, {});
}

टाइपस्क्रिप्ट के लिए

function deleteProps(obj: Object, props: string[]) {
    if (!Array.isArray(props)) props = [props];
    return Object.keys(obj).reduce((newObj, prop) => {
        if (!props.includes(prop)) {
            newObj[prop] = obj[prop];
        }
        return newObj;
    }, {});
}

उपयोग:

let a = {propH: 'hi', propB: 'bye', propO: 'ok'};

a = deleteProps(a, 'propB'); 

// or 

a = deleteProps(a, ['propB', 'propO']);

इस तरह एक नई वस्तु बनाई जाती है। और वस्तु की तेज संपत्ति रखी जाती है। जो महत्वपूर्ण या बात हो सकती है। यदि मैपिंग और ऑब्जेक्ट को कई बार एक्सेस किया जाएगा।

साथ ही undefinedसाथ जाना भी एक अच्छा तरीका हो सकता है। जब आप इसे बर्दाश्त कर सकते हैं। और कुंजियों के लिए आप मूल्य की जांच भी कर सकते हैं। उदाहरण के लिए सभी सक्रिय कुंजी प्राप्त करने के लिए आप कुछ ऐसा करते हैं:

const allActiveKeys = Object.keys(myObj).filter(k => myObj[k] !== undefined);
//or
const allActiveKeys = Object.keys(myObj).filter(k => myObj[k]); // if any false evaluated value is to be stripped.

अनिर्धारित बड़ी सूची के लिए अनुकूल नहीं है। या कई सहारा के साथ समय के साथ विकास अंदर आने के लिए। जैसे-जैसे मेमोरी का उपयोग बढ़ता रहेगा और यह कभी साफ नहीं होगा। तो यह उपयोग पर निर्भर करता है। और बस एक नई वस्तु का निर्माण अच्छा तरीका लगता है।

तब में Premature optimization is the root of all evilकिक करेगा। इसलिए आपको व्यापार बंद के बारे में पता होना चाहिए। और क्या जरूरत है और क्या नहीं है।

लॉश के बारे में _.omit () के बारे में ध्यान दें

इसे संस्करण 5 से हटा दिया गया है। आप इसे रेपो में नहीं ढूंढ सकते। और यहां एक मुद्दा जो इसके बारे में बात करता है।

https://github.com/lodash/lodash/issues/2930

v8

आप इसे देख सकते हैं जो एक अच्छी रीडिंग है https://v8.dev/blog/fast-properties


1

यदि आप विनाश की कोशिश करते हैं, तो एक ESLint नियम मानक से स्वीकृत उत्तर के साथ मेरा मुद्दा:

    const { notNeeded, alsoNotNeeded, ...rest } = { ...ogObject };

2 नए चर, notNeededऔर alsoNotNeededआपके सेटअप के आधार पर एक चेतावनी या त्रुटि फेंक सकते हैं क्योंकि वे अब अप्रयुक्त हैं। तो अगर अप्रयुक्त हैं तो नए संस्करण क्यों बनाएं?

मुझे लगता है कि आपको deleteफ़ंक्शन का सही उपयोग करने की आवश्यकता है ।


4
no-unused-varsनियम वास्तव में एक विकल्प होता है ignoreRestSiblings: उपयोग के इस मामले को कवर करने के लिए अब eslint.org/docs/rules/no-unused-vars#ignorerestsiblings
AMANN

0

लॉश क्लोनडिप और डिलीट के साथ

(नोट: उथले क्लोन का उपयोग उथली वस्तुओं के लिए किया जा सकता है)

const obj = {a: 1, b: 2, c: 3}
const unwantedKey = 'a'

const _ = require('lodash')
const objCopy = _.cloneDeep(obj)
delete objCopy[unwantedKey]
// objCopy = {b: 2, c: 3}

0

अपने कोड के लिए मैं मानचित्र के वापसी मूल्य के लिए एक छोटा संस्करण चाहता था () लेकिन बहुस्तरीय / म्यूटली संचालन समाधान "बदसूरत" थे। मुख्य विशेषता पुरानी है void(0)जो हल करती है undefined

let o2 = {...o, age: 31, lastname: void(0)};

संपत्ति वस्तु में रहती है:

console.log(o2) // {firstname: "Jane", lastname: undefined, age: 31}

लेकिन संचारित ढांचा मेरे लिए इसे मारता है (बीसी स्ट्रिंग):

console.log(JSON.stringify(o2)) // {"firstname":"Jane","age":31}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.