ईएस 6/2015 में अशक्त-सुरक्षित संपत्ति पहुंच (और सशर्त असाइनमेंट)


149

वहाँ एक है null-सुरक्षित संपत्ति पहुँच ES6 (ES2015 / JavaScript.next / सद्भाव) की तरह में (शून्य प्रचार / अस्तित्व) ऑपरेटर ?.में CoffeeScript उदाहरण के लिए? या यह ES7 के लिए योजनाबद्ध है?

var aThing = getSomething()
...
aThing = possiblyNull?.thing

यह मोटे तौर पर की तरह होगा:

if (possiblyNull != null) aThing = possiblyNull.thing

आदर्श रूप से समाधान असाइन नहीं करना चाहिए (यहां तक ​​कि अगर है undefined)aThingpossiblyNullnull


3
@naomik अशक्त जाँच इस तरह की बहुत उपयोगी हो सकता है के लिए अगर बयान है जहाँ आप एक गहरा नेस्टेड संपत्ति के लिए जाँच कर रहे हैं जैसे, if( obj?.nested?.property?.value )बजायif( obj && obj.nested && obj.nested.property && obj.nested.property.value )
शॉन वॉल्श

@ सीनवल्श यदि आपकी वस्तुएं हैं जो कि गहरी नेस्टेड हैं, या यदि आपके कार्य आपकी वस्तुओं में गहराई से खुदाई कर रहे हैं, तो संभवतः आपके ऐप के साथ कई अन्य समस्याएं भी हैं।
धन्यवाद

1
से तुलना var appConfig = loadConfig(config, process.env); connect(appConfig.database);करें connect(config)। आप के लिए एक बहुत सरल वस्तु पारित कर सकते हैं connectपूरे गुजर के बजाय configवस्तु, आप उपयोग कर सकते हैं conf.username, conf.passwordबजाय की तरह कुछ के प्रयास के config[process.env]?.database?.username, config[process.env]?.database?.password। संदर्भ: लॉ ऑफ डेमेटर
धन्यवाद

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

4
@naomik जब तक भाषा घोंसले की वस्तुओं का समर्थन करती है, तब भी यह एक उपयोगी विशेषता है - चाहे आप या मैं ऐप की वास्तुकला के बारे में सोचें। एक तरफ के रूप में, इस तरह के जटिल वस्तु रेखांकन ओआरएम में बहुत आम हैं जो एक जटिल डेटा मॉडल को मॉडलिंग कर रहे हैं।
सीन वॉल्श

जवाबों:


98

अद्यतन (2020-01-31): लगता है लोग अभी भी इसे पा रहे हैं, यहाँ वर्तमान कहानी है:

अद्यतन (2017-08-01): यदि आप एक आधिकारिक प्लगइन का उपयोग करना चाहते हैं, तो आप नए परिवर्तन के साथ बैबेल 7 के अल्फा निर्माण की कोशिश कर सकते हैं। आपकी माइलेज भिन्न हो सकती है

https://www.npmjs.com/package/babel-plugin-transform-optional-chaining

मूल :

एक विशेषता जो कि वर्तमान में चरण 1 में पूरा करती है: वैकल्पिक चेनिंग।

https://github.com/tc39/proposal-optional-chaining

यदि आप आज इसका उपयोग करना चाहते हैं, तो एक बाबेल प्लगइन है जो इसे पूरा करता है।

https://github.com/davidyaha/ecmascript-optionals-proposal


क्या मैं सही ढंग से समझता हूं कि इसमें सशर्त असाइनमेंट शामिल नहीं है? किसी भी मामले में street = user.address?.streetसेट होगा street?
16: ᆼ

1
वास्तव में दुर्भाग्य से मुझे लगता है कि तुम सही हो। Street मुझे लगता है कि सौंपा जाएगा undefinedलेकिन कम से कम यह अपरिभाषित पर संपत्तियों का उपयोग करने की कोशिश पर फेंक नहीं होगा।
बेसिकडे

2
यह भी दिखता है कि आप बाएं हाथ पर ऑपरेटर कर सकते हैं, और यदि यह अपरिभाषित कुछ भी निकालता है, तो दाहिने हाथ का मूल्यांकन नहीं किया जाता है। बाबेल प्लगइन थोड़ा भिन्न हो सकता है, इसने अभी तक खुद का परीक्षण नहीं किया है।
बेसिकडे

1
बाईं ओर के सशर्त असाइनमेंट के बारे में =, ऐसा लगता है कि वर्तमान में आधिकारिक कल्पना में समर्थित नहीं है। github.com/tc39/proposal-optional-chaining#not-supported
बेसिक दिन

1
मई 2020 तक, ऐसा लगता है कि वर्तमान ब्राउज़र और टाइपस्क्रिप्ट ने इसे लागू कर दिया है!
जोश मरहल

65

यह उतना अच्छा नहीं है। ऑपरेटर, लेकिन एक जैसा परिणाम प्राप्त करने के लिए आप कर सकते हैं:

user && user.address && user.address.postcode

के बाद से nullऔर undefinedदोनों falsy मूल्यों ( इस संदर्भ देखें ), के बाद संपत्ति &&ऑपरेटर केवल पहुँचा जा सकता है मिसाल यह शून्य या अनिर्धारित नहीं है।

वैकल्पिक रूप से, आप इस तरह से एक फ़ंक्शन लिख सकते हैं:

function _try(func, fallbackValue) {
    try {
        var value = func();
        return (value === null || value === undefined) ? fallbackValue : value;
    } catch (e) {
        return fallbackValue;
    }
}

उपयोग:

_try(() => user.address.postcode) // return postcode or undefined 

या, एक गिरावट मूल्य के साथ:

_try(() => user.address.postcode, "none") // return postcode or a custom string

शायद मुझे इस प्रश्न को स्पष्ट करना चाहिए, मुख्य बात मैं सशर्त असाइनमेंट था
ᆺ at

बस एक कोरोलरी कि; प्रतिलोम को सुरक्षित रूप से खोजने के लिए, आप !(user && user.address && user.address.postcode) :)
rob2d

foo && foo.bar && foo.bar.quux ...एक बड़े कोडबेस में यह बदसूरत है और बहुत अधिक जटिलता जोड़ता है जिससे आप बचना बेहतर होगा।
स्काईलार सेवलैंड

1
यह सबसे साफ समाधान है जो मैंने इंटरनेट पर पाया है। मैं इसे टाइपस्क्रिप्ट के साथ उपयोग करता हूं:_get<T>(func: () => T, fallbackValue?: T) :T
टॉमविंग

3
यदि user.address.postcodeअपरिभाषित है, के बजाय _try(() => user.address.postcode, "")वापस आ जाएगी । तो कोड एक अपवाद बढ़ाएगा। undefined""_try(() => user.address.postcode, "").length
अलेक्जेंडर चेन

33

नहीं। आप जावास्क्रिप्ट का उपयोग कर सकते हैं # पाने के लिए या जावास्क्रिप्ट में ऐसा कुछ।


4
क्या इसे ES7 में जोड़ने के प्रस्ताव हैं?
ᆼ ᆺ ᆼ

1
कोई सामना नहीं हुआ।
जिराफा

3
@PeterVarga: कई। बहुत ज्यादा चर्चा। व्याकरण इस सुविधा के लिए एक आसान बात नहीं है
बर्गी

1
lodash.getउस स्थिति में थोड़ा अलग है यह सशर्त असाइनमेंट नहीं कर सकता है।
17 :30 ᆼ

17

सुरक्षित संपत्ति के उपयोग के लिए वेनिला विकल्प

(((a.b || {}).c || {}).d || {}).e

सबसे संक्षिप्त सशर्त असाइनमेंट शायद यही होगा

try { b = a.b.c.d.e } catch(e) {}

तो आप इस तंत्र का उपयोग करते हुए प्रश्न में असाइनमेंट कैसे लिखेंगे? यदि आपको possiblyNullपरिभाषित नहीं है / नहीं है तो क्या आपको अभी भी असाइन नहीं करने के लिए सशर्त की आवश्यकता है null?
9: ᆼ

ज़रूर, आपको अभी भी जांचने की ज़रूरत है कि क्या आप एक असाइनमेंट होना चाहते हैं या नहीं। यदि आप '=' ऑपरेटर का उपयोग करते हैं, तो कुछ अनिवार्य रूप से सौंपा जाएगा, यह एक डेटा, एक अपरिभाषित या अशक्त होना चाहिए। तो ऊपर सिर्फ एक सुरक्षित संपत्ति का उपयोग है। क्या सशर्त असाइनमेंट ऑपरेटर किसी भी भाषा में भी मौजूद है?
यार्गर

बेशक, उदाहरण के लिए CoffeeScript , यह भी है||=
। ᆼ '

+1 यहां तक ​​कि मेरा पहला विचार था (((a.b || {}).c || {}).d || {}).e। लेकिन अधिक सटीक यह होगा((((a || {}).b || {}).c || {}).d || {}).e
इस्माईल

6

नहीं, ES6 में कोई शून्य प्रसार संचालक नहीं है। आपको ज्ञात पैटर्न में से एक के साथ जाना होगा ।

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

({thing: aThing} = possiblyNull);

ES7 में इस तरह के ऑपरेटर को जोड़ने के लिए कई चर्चाएं (जैसे यह ) हैं, लेकिन वास्तव में किसी ने भी नहीं लिया।


यह आशाजनक लग रहा था, लेकिन कम से कम बाबेल इसके साथ क्या करता है, यह सिर्फ किसी से अलग नहीं हैaThing = possiblyNull.thing
ᆼ at

1
@PeterVarga: उफ़, आप सही हैं, विनाशकारी काम करता है जब संपत्ति मौजूद नहीं है, लेकिन जब ऑब्जेक्ट नहीं है null। आपको डिफ़ॉल्ट मान की आपूर्ति करनी होगी, इस पैटर्न की तरह लेकिन बहुत अधिक भ्रमित सिंटैक्स के साथ।
बेर्गी

4

यहां सूची में जाने से , वर्तमान में एक्मास्क्रिप्ट में सुरक्षित ट्रैवर्सल जोड़ने का कोई प्रस्ताव नहीं है। इसलिए न केवल ऐसा करने का कोई अच्छा तरीका नहीं है, बल्कि यह भविष्य के लिए जोड़ा नहीं जा सकता है।


1
// Typescript
static nullsafe<T, R>(instance: T, func: (T) => R): R {
    return func(instance)
}

// Javascript
function nullsafe(instance, func) {
    return func(instance);
};

// use like this
const instance = getSomething();
let thing = nullsafe(instance, t => t.thing0.thing1.thingx);

1

ऑप्शनल चेनिंग ?.और न्यूलल कोलेसिंग??

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

?? एक डिफ़ॉल्ट मान सेट करने के लिए इस्तेमाल किया जा सकता है अगर अपरिभाषित या अशक्त।

aThing = possiblyNull ?? aThing
aThing = a?.b?.c ?? possiblyNullFallback ?? aThing

यदि कोई संपत्ति मौजूद है, ?.तो अगले चेक के लिए आगे बढ़ता है, या वैध मूल्य लौटाता है। कोई भी विफलता तुरंत शॉर्ट-सर्किट और वापस आ जाएगी undefined

const example = {a: ["first", {b:3}, false]}

example?.a  // ["first", {b:3}, false]
example?.b  // undefined

example?.a?.[0]     // "first"
example?.a?.[1]?.a  // undefined
example?.a?.[1]?.b  // 3

domElement?.parentElement?.children?.[3]?.nextElementSibling

null?.()                // undefined
validFunction?.()       // result
(() => {return 1})?.()  // 1

एक डिफ़ॉल्ट परिभाषित मूल्य सुनिश्चित करने के लिए, आप उपयोग कर सकते हैं ??। यदि आपको पहले सत्य मूल्य की आवश्यकता है, तो आप उपयोग कर सकते हैं ||

example?.c ?? "c"  // "c"
example?.c || "c"  // "c"

example?.a?.[2] ?? 2  // false
example?.a?.[2] || 2  // 2

यदि आप किसी मामले की जांच नहीं करते हैं, तो बाईं ओर की संपत्ति मौजूद होनी चाहिए। यदि नहीं, तो यह एक अपवाद फेंक देगा।

example?.First         // undefined
example?.First.Second  // Uncaught TypeError: Cannot read property 'Second' of undefined

?.ब्राउज़र समर्थन - 78%, जुलाई 2020

??ब्राउज़र समर्थन - 78%

मोज़िला प्रलेखन

-

तार्किक nullish असाइनमेंट, 2020+ समाधान

नए ऑपरेटर वर्तमान में ब्राउज़रों में जोड़े जा रहे हैं ??=, ||=और &&=। वे वह नहीं करते हैं जो आप खोज रहे हैं, लेकिन आपके कोड के उद्देश्य के आधार पर एक ही परिणाम हो सकता है।

नोट: ये अभी तक सार्वजनिक ब्राउज़र संस्करणों में आम नहीं हैं , लेकिन बैबेल को अच्छी तरह से ट्रांसपाइल करना चाहिए। उपलब्धता परिवर्तन के रूप में अद्यतन करेगा।

??=यदि पहले से परिभाषित है, तो बाईं ओर अपरिभाषित या अशक्त, शॉर्ट-सर्किटिंग की जाँच करता है। यदि नहीं, तो बाईं ओर को दाईं ओर मान असाइन किया गया है। ||=और &&=समान हैं, लेकिन ऑपरेटरों ||और &&ऑपरेटरों के आधार पर ।

मूल उदाहरण

let a          // undefined
let b = null
let c = false

a ??= true  // true
b ??= true  // true
c ??= true  // false

ऑब्जेक्ट / एरे उदाहरण

let x = ["foo"]
let y = { foo: "fizz" }

x[0] ??= "bar"  // "foo"
x[1] ??= "bar"  // "bar"

y.foo ??= "buzz"  // "fizz"
y.bar ??= "buzz"  // "buzz"

x  // Array [ "foo", "bar" ]
y  // Object { foo: "fizz", bar: "buzz" }

ब्राउज़र समर्थन जुलाई 2020 - .03%

मोज़िला प्रलेखन


1
सवाल सशर्त असाइनमेंट के बारे में भी है
ᆼ at

साथ कुछ उदाहरण जोड़ा ?.और ??, और एक विस्तृत आगामी समाधान है कि अपनी स्थिति के लिए काम कर सकते हैं। सबसे अच्छा वर्तमान समाधान शायद बस करना हैaThing = possiblyNull?.thing ?? aThing
जिबोल्ट

0

एक सुरक्षित डीप मेथड तरीका अंडरस्कोर।जेएस के लिए एक प्राकृतिक फिट की तरह लगता है, लेकिन वहां यह मुद्दा स्ट्रिंग प्रोग्रामिंग से बच रहा है। स्ट्रिंग प्रोग्रामिंग से बचने के लिए @ फेलिप का उत्तर संशोधित करना (या कम से कम किनारे के मामलों को कॉलर पर वापस लाना):

function safeGet(obj, props) {
   return (props.length==1) ? obj[keys[0]] :safeGet(obj[props[0]], props.slice(1))
}

उदाहरण:

var test = { 
  a: { 
    b: 'b property value',
    c: { }
  } 
}
safeGet(test, ['a', 'b']) 
safeGet(test, "a.b".split('.'))  

रिक को पैराफेयर करने के लिए: यह सिर्फ अतिरिक्त चरणों के साथ स्ट्रिंग प्रोग्रामिंग की तरह लगता है।
टॉस्कविले

1
लॉश अब लागू हो जाओ / सेट _.get(obj, array_or_dotstring)
प्रोटोटाइप

1
लेकिन निष्पक्ष होना भी जावास्क्रिप्ट डॉट और स्ट्रिंग एक्सेसर नोटेशन मूल रूप से स्ट्रिंग प्रोग्रामिंग है, obj.a.b.cबनामobj['a']['b']['c']
प्रोटोटाइप

1
कहां से keysआ रहा है?
लेवी रॉबर्ट्स

-2

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

.&, tryऔर && में उनकी ताकत और संभावित नुकसान हैं। उन विकल्पों में से एक महान रन यहां: http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/

TLDR; रूबीवादियों का निष्कर्ष यह है कि digदोनों आँखों पर आसान है और एक मजबूत गारंटी है कि एक मूल्य या nullसौंपा जाएगा।

यहाँ टाइपस्क्रिप्ट में एक सरल ime कार्यान्वयन है:

export function dig(target: any, ...keys: Array<string>): any {
  let digged = target
  for (const key of keys) {
    if (typeof digged === 'undefined') {
      return undefined // can also return null or a default value
    }
    if (typeof key === 'function') {
      digged = key(digged)
    } else {
      digged = digged[key]
    }
  }
  return digged
}

यह घोंसले के शिकार की किसी भी गहराई और कार्यों को संभालता है।

a = dig(b, 'c', 'd', 'e');
foo = () => ({});
bar = dig(a, foo, 'b', 'c')

tryके रूप में पिछले जवाब में दिखाया गया है दृष्टिकोण, समान रूप से जे एस में पढ़ने के लिए अच्छा है। इसे लूपिंग की भी आवश्यकता नहीं है, जो इस कार्यान्वयन का एक दोष है।


मैं इस जवाब को एक मजेदार / पूर्ण / वैकल्पिक समाधान b / c के रूप में यहाँ प्रस्तुत करता हूं जिस तरह से रूबी यह वाक्यात्मक चीनी के साथ करता है। समुदाय के लिए इसे बाहर रखना - एक बार और वोट करें और मैं खुशी से इस पोस्ट को हटा दूंगा। चीयर्स!
द यूटरसाइड

ECMAScript2019 को देखने के लिए वास्तव में अच्छा है रूबी की तरह "वैकल्पिक चेनिंग" के लिए एक महान प्रस्ताव है: github.com/tc39/proposal-optional-chaining यह आज बैबल प्लगिन के माध्यम से उपलब्ध है, और यह एक ऑब्जेक्ट पर कॉल करने के तरीकों पर भी काम करता है: babeljs.io / डॉक्स / एन / बैबल-प्लगइन-प्रस्ताव-वैकल्पिक-चेनिंग
यूटरसाइड

-5

मुझे लगा कि इस सवाल के लिए 2018 के लिए एक रिफ्रेश की आवश्यकता है। यह बिना किसी लाइब्रेरियों के उपयोग किए बिना अच्छी तरह से किया जा सकता है Object.defineProperty()और इसका उपयोग इस प्रकार किया जा सकता है:

myVariable.safeGet('propA.propB.propC');

मैं इस पर विचार सुरक्षित (और जे एस-नैतिक) की वजह से writeableऔर enumerableअब के लिए उपलब्ध परिभाषाओं definePropertyकी विधि Object, के रूप में MDN में दर्ज

नीचे फ़ंक्शन परिभाषा:

Object.defineProperty(Object.prototype, 'safeGet', { 
    enumerable: false,
    writable: false,
    value: function(p) {
        return p.split('.').reduce((acc, k) => {
            if (acc && k in acc) return acc[k];
            return undefined;
        }, this);
    }
});

मैंने इसे प्रदर्शित करने के लिए कंसोल आउटपुट के साथ jsBin को एक साथ रखा है । ध्यान दें कि jsBin संस्करण में मैंने खाली मानों के लिए एक कस्टम अपवाद भी जोड़ा है। यह वैकल्पिक है, और इसलिए मैंने इसे न्यूनतम परिभाषा से ऊपर छोड़ दिया है।

सुधारों का स्वागत किया जाता है


2
इसके साथ ही आप कर रहे हैं वास्तव में तार में लेखन कोड। यह वास्तव में एक बुरा विचार है। यह आपके कोड को रिफैक्टर के लिए असंभव बनाता है और आईडीई के अनुकूल नहीं।
टॉस्कविले
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.