किसी ऑब्जेक्ट को अपरिवर्तनीय रूप से निकालें


145

मैं Redux का उपयोग कर रहा हूं। मेरे reducer में मैं इस तरह से एक वस्तु से एक संपत्ति को दूर करने की कोशिश कर रहा हूँ:

const state = {
    a: '1',
    b: '2',
    c: {
       x: '42',
       y: '43'
    },
}

और मैं मूल स्थिति को बदलने के लिए बिना इस तरह से कुछ करना चाहता हूं:

const newState = {
    a: '1',
    b: '2',
    c: {
       x: '42',
    },
}

मैंने कोशिश की:

let newState = Object.assign({}, state);
delete newState.c.y

लेकिन कुछ कारणों से, यह दोनों राज्यों से संपत्ति को हटा देता है।

मुझे ऐसा करने में मदद कर सकता है?


3
ध्यान दें कि Object.assignकेवल एक बनाता है उथले नकल की stateहै और इसलिए state.cऔर newState.cएक ही साझा वस्तु को इंगित करेंगे। आपने yसाझा ऑब्जेक्ट से संपत्ति को हटाने की कोशिश की, cन कि नई वस्तु से newState
अक्सेली पालेन

जवाबों:


224

विनाशकारी असाइनमेंट सिंटैक्स का उपयोग करने के बारे में कैसे ?

const original = {
  foo: 'bar',
  stack: 'overflow',
};

// If the name of the property to remove is constant
const { stack, ...withoutFirst } = original;
console.log(withoutFirst); // Will be { "foo": "bar" }

// If the name of the property to remove is from a variable
const key = 'stack'
const { [key]: value, ...withoutSecond } = original;
console.log(withoutSecond); // Will be { "foo": "bar" }

// To do a deep removal with property names from variables
const deep = {
  foo: 'bar',
  c: {
   x: 1,
   y: 2
  }
};

const parentKey = 'c';
const childKey = 'y';
// Remove the 'c' element from original
const { [parentKey]: parentValue, ...noChild } = deep;
// Remove the 'y' from the 'c' element
const { [childKey]: removedValue, ...childWithout } = parentValue;
// Merge back together
const withoutThird = { ...noChild, [parentKey]: childWithout };
console.log(withoutThird); // Will be { "foo": "bar", "c": { "x": 1 } }


3
अद्भुत, अतिरिक्त पुस्तकालय के बिना, es6 और पर्याप्त सरल का उपयोग करें।
sbk201 12

सबसे सुंदर समाधान
long.luc

12
अच्छा! इसके साथ जाने के लिए यहां es6 हेल्पर फंक्शन है const deleteProperty = ({[key]: _, ...newObj}, key) => newObj;। उपयोग: deleteProperty({a:1, b:2}, "a");देता है{b:2}
mikebridge

सुपर चालाक, मैं इस एक के लिए देर से कर रहा हूँ, लेकिन मेरे नए पसंदीदा में से एक
गेविन

1
ध्यान दें कि गहरी हटाने का उदाहरण दुर्घटनाग्रस्त होगा यदि deep['c']खाली है, तो सामान्य स्थिति में, आप कुंजी की उपस्थिति के लिए एक चेक जोड़ना चाह सकते हैं।
लॉरेंट एस

46

मुझे ईएस 5 सरणी विधियां पसंद हैं filter, mapऔर reduceउपयोगी हैं क्योंकि वे हमेशा नए सरणियों या वस्तुओं को वापस करते हैं। इस मामले में मैं Object.keysऑब्जेक्ट पर पुनरावृति करने के लिए, और Array#reduceइसे किसी ऑब्जेक्ट में वापस करने के लिए उपयोग करूंगा ।

return Object.assign({}, state, {
    c: Object.keys(state.c).reduce((result, key) => {
        if (key !== 'y') {
            result[key] = state.c[key];
        }
        return result;
    }, {})
});

IMO को स्पष्ट करने के लिए मेरे थोड़े से बदलाव से चिढ़कर ... आपको कई गुणों को छोड़ना होगा। const omit = ['Prop1', 'prop2'] ... if (omit.indexOf (key) === -1) परिणाम [key] = state.c [key] वापसी परिणाम; ...
josh-sachs

3
myObjectmyKeyObject.keys(myObject).reduce((acc, cur) => cur === myKey ? acc : {...acc, [cur]: myObject[cur]}, {})
ईएस 6 को

38

आप लॉकेट लाइब्रेरी _.omit(object, [paths])से उपयोग कर सकते हैं

पथ को उदाहरण के लिए घोंसला बनाया जा सकता है: _.omit(object, ['key1.key2.key3'])


3
दुर्भाग्य से, _.omitगहरी संपत्तियों को नष्ट नहीं कर सकता (ओपी क्या पूछ रहा था)। नहीं है omit-deep-lodashइस उद्देश्य के लिए मॉड्यूल।
15

2
@AlexM क्या कह रहा था बंद जा रहा है। मुझे यह उपयोगी लगा, और यह अधिक उपयुक्त हो सकता है, हमारे लिए _.cloneDeep(obj)लॉश से। यह ऑब्जेक्ट को आसानी से कॉपी करता है और फिर आप delete obj.[key]कुंजी को हटाने के लिए बस js का उपयोग कर सकते हैं ।
एलेक्स जे

W / @AlexJ से सहमत हों, क्लोनडिप पूरी तरह से काम करता है और आप इसके साथ फैल सिंटैक्स का भी उपयोग कर सकते हैं: ..._। Redux के लिए क्लोनडिप (राज्य)
सीन चेस

32

बस ES6 ऑब्जेक्ट विनाशकारी सुविधा का उपयोग करें

const state = {
    c: {
       x: '42',
       y: '43'
    },
}

const { c: { y, ...c } } = state // generates a new 'c' without 'y'

console.log({...state, c }) // put the new c on a new state


8
const {y, ...c} = state.ccबाएं हाथ की तरफ दो होने की तुलना में थोड़ा स्पष्ट हो सकता है ।
dosentmatter

10
खबरदार: यह पूर्णांकों द्वारा बंद किए गए ऑब्जेक्ट के लिए काम नहीं करता है
daviestar

3
नीचे दिए गए उत्तर से, यदि आपको हटाए जाने वाले चर नाम को संदर्भित करने की आवश्यकता है: const name = 'c'तो आप ऐसा कर सकते हैं const {[name]:deletedValue, ...newState} = stateफिर newStateअपने reducer में लौट सकते हैं । यह शीर्ष स्तर की प्रमुख विलोपन के लिए है
FFF

23

ऐसा इसलिए है क्योंकि आप state.cदूसरी वस्तु के मूल्य की नकल कर रहे हैं । और वह मान किसी अन्य जावास्क्रिप्ट ऑब्जेक्ट के लिए एक संकेतक है। तो, वे दोनों बिंदु एक ही वस्तु की ओर इशारा करते हैं।

इसे इस्तेमाल करे:

let newState = Object.assign({}, state);
console.log(newState == state); // false
console.log(newState.c == state.c); // true
newState.c = Object.assign({}, state.c);
console.log(newState.c == state.c); // now it is false
delete newState.c.y;

आप ऑब्जेक्ट की डीप-कॉपी भी कर सकते हैं। इस प्रश्न को देखें और आप पाएंगे कि आपके लिए सबसे अच्छा क्या है।


2
यह एक उत्कृष्ट उत्तर है! state.cएक संदर्भ है, और संदर्भ को ठीक-ठीक कॉपी किया जा रहा है। Redux एक सामान्यीकृत राज्य आकृति चाहता है, जिसका अर्थ है घोंसले के शिकार राज्य के संदर्भ के बजाय आईडी का उपयोग करना। Redux
Ziggy

17

इस बारे में कैसा है:

function removeByKey (myObj, deleteKey) {
  return Object.keys(myObj)
    .filter(key => key !== deleteKey)
    .reduce((result, current) => {
      result[current] = myObj[current];
      return result;
  }, {});
}

यह उस कुंजी को फ़िल्टर करता है जिसे हटा दिया जाना चाहिए फिर शेष कुंजियों और प्रारंभिक ऑब्जेक्ट से एक नई ऑब्जेक्ट बनाता है। यह विचार टायलर मैकगिनेंस के भयानक रिएक्टज प्रोग्राम से चुराया गया है।

JSBin



9

आप अपने मामले में, किसी विशेषता को परेशान करने के लिए अपरिवर्तनीय सहायक का उपयोग कर सकते हैं :

import update from 'immutability-helper';

const updatedState = update(state, {
  c: {
    $unset: ['y']
  }
});    

फिर हर सरणी ऑब्जेक्ट आइटम की सभी संपत्ति "y" को कैसे हटाएं?
ग्रीवेंट

@ 5 मुझे लगता है कि यह एक और सवाल है, लेकिन मैं आपको सुझाव दूंगा कि आप सरणी को मैप करें और यहां दिए गए किसी भी समाधान को लागू करें
जेवियर पी

8

2019 तक, Object.fromEntriesविधि का उपयोग करने के लिए एक और विकल्प है । यह स्टेज 4 पर पहुंच गया है।

const newC = Object.fromEntries(
    Object.entries(state.c).filter(([key]) => key != 'y')
)
const newState = {...state, c: newC}

इसके बारे में अच्छी बात यह है कि यह पूर्णांक कुंजियों को अच्छी तरह से संभालता है।



3

आपके पास जो समस्या है वह यह है कि आप अपनी प्रारंभिक स्थिति का गहन प्रतिरूपण नहीं कर रहे हैं। इसलिए आपके पास एक उथली प्रति है।

आप स्प्रेड ऑपरेटर का उपयोग कर सकते हैं

  const newState = { ...state, c: { ...state.c } };
  delete newState.c.y

या अपने समान कोड का पालन करना

let newState = Object.assign({}, state, { c: Object.assign({}, state.c) });
delete newState.c.y

1

मैं सामान्य रूप से उपयोग करता हूं

Object.assign({}, existingState, {propToRemove: undefined})

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

1 यदि आप उपयोग कर रहे हैं hasOwnProperty(), तो आपको अधिक जटिल समाधान का उपयोग करने की आवश्यकता होगी।


1

मैं इस पैटर्न का उपयोग करता हूं

const newState = Object.assign({}, state);
      delete newState.show;
      return newState;

लेकिन किताब में मैंने एक और पैटर्न देखा

return Object.assign({}, state, { name: undefined } )

दूसरा वाला, चाबी नहीं निकालता। यह सिर्फ इसे अपरिभाषित करता है।
शाम

1

उपयोगिता;))

const removeObjectField = (obj, field) => {

    // delete filter[selectName]; -> this mutates.
    const { [field]: remove, ...rest } = obj;

    return rest;
}

प्रक्रिया का प्रकार

const MY_Y_REMOVE = 'MY_Y_REMOVE';

एक्शन क्रिएटर

const myYRemoveAction = (c, y) => {

    const result = removeObjectField(c, y);

        return dispatch =>
            dispatch({
                type: MY_Y_REMOVE,
                payload: result
            })
    }

कम करने

export default (state ={}, action) => {
  switch (action.type) {
    case myActions.MY_Y_REMOVE || :
      return { ...state, c: action.payload };
    default:
      return state;
  }
};

0

जैसा कि पहले से ही कुछ उत्तरों में संकेत दिया गया था, यह इसलिए है क्योंकि आप एक नेस्टेड स्थिति को संशोधित करने का प्रयास कर रहे हैं। एक स्तर गहरा। एक विहित समाधान xराज्य स्तर पर एक reducer जोड़ने के लिए किया जाएगा :

const state = {
    a: '1',
    b: '2',
    c: {
       x: '42',
       y: '43'
    },
}

गहरा स्तर रिड्यूसर

let newDeepState = Object.assign({}, state.c);
delete newDeepState.y;

मूल स्तर reducer

let newState = Object.assign({}, state, {c: newDeepState});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.