ES6 / 2015의 안전하지 않은 속성 액세스 및 조건부 할당


149

거기 nullES6 (ES2015 / JavaScript.next / 하모니) 등의 -safe 속성 액세스 (null의 전파 / 유) 연산자 ?.커피 스크립트 예는? 아니면 ES7을 계획하고 있습니까?

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

이것은 대략 다음과 같습니다.

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

이상적 솔루션 (심지어 할당해서는 안됩니다 undefined)로 aThing하면 possiblyNullISnull


3
@naomik 널 (null) 검사의이 종류는 매우 유용 할 수 있습니다에 대한 당신이 예를 들면, 중첩 속성에 대해 확인하고 if 문 if( obj?.nested?.property?.value )대신에if( obj && obj.nested && obj.nested.property && obj.nested.property.value )
숀 월시

@SeanWalsh 객체가 깊게 중첩되어 있거나 함수가 객체에 깊이 파고 있으면 앱에 몇 가지 다른 문제가있을 수 있습니다.
감사합니다

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하는 경우 (위의 예에서 수행 할 수 있음) 속성의 존재에 대해 가정하고 앱의 수많은 영역에서 null 검사를 건너 뛸 수 있습니다.
감사합니다

4
@naomik 언어가 중첩 객체를 지원하는 한, 앱 자체의 아키텍처에 대해 생각하거나 상관없이 여전히 유용한 기능입니다. 또한 이와 같은 복잡한 개체 그래프는 복잡한 데이터 모델을 모델링하는 ORM에서 매우 일반적입니다.
Sean Walsh

답변:


98

업데이트 (2020-01-31) : 사람들이 여전히 이것을 찾는 것 같습니다. 현재 이야기는 다음과 같습니다.

업데이트 (2017-08-01) : 공식 플러그인을 사용하려면 새로운 변형으로 Babel 7의 알파 빌드를 시도 할 수 있습니다. 귀하의 마일리지가 다를 수 있습니다

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

실물 :

현재 1 단계에있는 기능 : 옵션 체인.

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

오늘 사용하고 싶다면 그것을 수행하는 Babel 플러그인이 있습니다.

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


조건부 할당이 포함되어 있지 않다는 것을 올바르게 이해하고 있습니까? 어떤 경우에도 street = user.address?.street설정 street하시겠습니까?
ᆼ ᆺ ᆼ

1
실제로 불행히도 나는 당신이 옳다고 생각합니다. Street 나는 할당 될 것 같아요undefined . 그러나 적어도 정의되지 않은 속성에 액세스하려고하면 포기하지 않습니다.
basicdays

2
또한 왼쪽에서 연산자를 사용할 수있는 것처럼 보이고 정의되지 않은 항목을 회피하면 오른쪽이 평가되지 않습니다. babel 플러그인은 약간 다를 수 있지만 아직 많이 테스트하지는 않았습니다.
basicdays

1
의 왼쪽에있는 조건부 할당과 관련하여 =현재 공식 사양에서 지원되지 않는 것 같습니다. github.com/tc39/proposal-optional-chaining#not-supported
기본 요일

1
2020 년 5 월 현재, 현재 브라우저처럼 보이고 Typescript가 이것을 구현했습니다!
Josh Diehl

65

?만큼 좋지 않습니다. 연산자이지만 비슷한 결과를 얻으려면 다음을 수행하십시오.

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

nullundefined둘 다 잘못된 값 이므로 ( 이 참조 참조 ) &&선행 연산자가 null이거나 정의되지 않은 경우에만 연산자 뒤의 속성에 액세스합니다.

또는 다음과 같은 함수를 작성할 수 있습니다.

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

아마도 그 질문을 분명히해야 할 것입니다. 제가 겪은 가장 중요한 것은 조건부 할당이었습니다
ᆼ ᆺ ᆼ

그것에 대한 단지 추론; 역을 안전하게 찾기 위해 다음을 사용할 수 있습니다 !(user && user.address && user.address.postcode) :)
rob2d

foo && foo.bar && foo.bar.quux ...큰 코드베이스에서는 이것이 추악하고 피해야 할 많은 복잡성을 추가합니다.
Skylar Saveland

1
이것은 인터넷에서 찾은 가장 깨끗한 솔루션입니다. 나는 이것을 typescript와 함께 사용한다 :_get<T>(func: () => T, fallbackValue?: T) :T
tomwassing

3
user.address.postcode가 정의되어 있지 않으면 대신에 _try(() => user.address.postcode, "")반환 undefined됩니다 "". 따라서 코드 _try(() => user.address.postcode, "").length에서 예외가 발생합니다.
Alexander Chen

33

아니요 . JavaScript에서 lodash # get 또는 이와 유사한 것을 사용할 수 있습니다 .


4
ES7에 추가 할 제안이 있습니까?
ᆼ ᆺ ᆼ

1
발생하지 않았습니다.
Girafa

3
@ PeterVarga : 많은. 너무 많은 토론. 문법은이 기능에서 쉬운 일이 아닙니다
Bergi

1
lodash.get조건부 할당을 수행 할 수 없다는 점에서 약간 다릅니다.
ᆼ ᆺ ᆼ

17

안전한 자산 접근을위한 바닐라 대안

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

가장 간결한 조건부 할당은 아마도

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

그렇다면이 메커니즘을 사용하여 질문에 과제를 어떻게 쓰시겠습니까? possiblyNull정의되지 않은 경우에도 할당하지 않으려면 조건이 필요 하지 null않습니까?
ᆼ ᆺ ᆼ

물론 과제를 수행 할 것인지 여전히 확인해야합니다. '='연산자를 사용하면 데이터, 정의되지 않았거나 null 인 것이 불가피하게 할당됩니다. 위의 내용은 안전한 자산 액세스입니다. 조건부 할당 연산자가 어떤 언어로도 존재합니까?
yagger

물론, 예를 들어 커피 스크립트 , 또한이||=
ᆼ ᆺ ᆼ

+1 나의 첫 생각조차도 (((a.b || {}).c || {}).d || {}).e. 그러나 더 정확할 것입니다((((a || {}).b || {}).c || {}).d || {}).e
IsmailS

6

아니요, ES6에는 null 전파 연산자가 없습니다. 알려진 패턴 중 하나를 사용해야합니다. 합니다.

하지만 다음과 같은 구조 조정을 사용할 수 있습니다.

({thing: aThing} = possiblyNull);

ES7에서 그러한 연산자를 추가하기위한 많은 토론 (예 : this ) 있지만 실제로 이륙 한 사람은 없습니다.


그러나 유망한 것처럼 보였지만 적어도 바벨이 그것으로 무엇을하는지와는 전혀 다르지 않습니다aThing = possiblyNull.thing
ᆼ ᆺ ᆼ

1
@PeterVarga : 그렇습니다. 속성이 존재하지 않을 때 객체가 아닌 경우에는 구조화가 작동합니다 null. 이 패턴 과 비슷 하지만 더 혼란스러운 구문 으로 기본값을 제공해야 합니다.
Bergi

4

여기 의 목록으로 이동하면 현재 Ecmascript에 안전한 순회를 추가 할 제안이 없습니다. 따라서이를 수행 할 수있는 좋은 방법은 없을뿐만 아니라 미래에도 추가되지는 않을 것입니다.


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

옵션 체인 ?. 및 Nullish Coalescing??

당신은 지금 직접 사용할 수 있습니다 ?.인라인을 하여 존재 여부를 안전하게 테스트 . 모든 최신 브라우저가이를 지원합니다.

?? undefined 또는 null 인 경우 기본값을 설정하는 데 사용할 수 있습니다.

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 년 7 월

??브라우저 지원 -78 %

모질라 문서

-

논리적 인 무효 할당, 2020+ 솔루션

신규 사업자는 현재 브라우저에 추가되고 ??=, ||=하고 &&=. 그들은 당신이 찾고있는 것을하지 않지만 코드의 목적에 따라 동일한 결과를 초래할 수 있습니다.

참고 : 공용 브라우저 버전에서는 아직 일반적이지 않지만 Babel은 잘 변환됩니다. 가용성이 변경되면 업데이트됩니다.

??=왼쪽이 정의되지 않았는지 또는 null인지 확인하고 이미 정의 된 경우 단락합니다. 그렇지 않으면 왼쪽에 오른쪽 값이 할당됩니다. ||=그리고 &&=온 유사하지만 기반 ||&&운영.

기본 예

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 년 7 월-.03 %

모질라 문서


1
질문은 또한 조건부 할당에 관한 것입니다
ᆼ ᆺ ᆼ

몇 가지 예에 추가 ?.하고 ??, 그리고 상황에 맞는 일을 할 수있는 상세한 곧 솔루션입니다. 현재 가장 좋은 솔루션은 아마도 할 것입니다aThing = possiblyNull?.thing ?? aThing
Gibolt

0

안전한 deep get 메소드는 underscore.js에 자연스럽게 맞는 것처럼 보이지만 문제는 문자열 프로그래밍을 피하는 것입니다. 문자열 프로그래밍을 피하기 위해 @Felipe의 답변을 수정하십시오 (또는 적어도 사례를 호출자에게 푸시합니다).

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('.'))  

Rick을 말하면, 이것은 추가 단계가있는 문자열 프로그래밍처럼 들립니다.
tocqueville

1
lodash는 이제 심오한 get / set을 구현합니다. _.get(obj, array_or_dotstring)
프로토 타입

1
그러나 공정 심지어 자바 스크립트 점 및 문자열 접근 표기 할 것은, 기본적으로 문자열 프로그램입니다 obj.a.b.cobj['a']['b']['c']
프로토 타입

1
어디에서 keys오나요?
Levi Roberts

-2

나는 이것이 JavaScript 질문이라는 것을 알고 있지만 Ruby는 요청 된 모든 방식으로 이것을 처리한다고 생각하므로 관련 참조 지점이라고 생각합니다.

.&, try및 &&에는 강점과 잠재적 인 함정이 있습니다. 이러한 옵션에 대한 자세한 설명은 다음과 같습니다. http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/

TLDR; Rubyists의 결론은 dig눈에 더 쉽고 이나 가치null 가 부여 될 것이라는 더 강한 보증입니다 .

TypeScript의 간단한 구현은 다음과 같습니다.

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접근법은 이전 답변에서 볼 수 있듯이 JS에서도 읽는 것이 좋습니다. 또한이 구현의 한 가지 단점 인 루핑이 필요하지 않습니다.


나는이 답변을 재미 있고 완전하며 대안적인 해결책으로 여기에 넣었다. 루비가 구문 설탕으로 이것을하는 방식을 좋아한다. 커뮤니티를 위해이 기능을 제공하기 만하면됩니다. 다시 한 번 투표하면이 게시물을 기꺼이 삭제할 것입니다. 건배!
theUtherSide

정말 ECMAScript2019 루비 같은 "옵션 체인"에 대한 좋은 제안을 가지고 볼 수 냉각 : github.com/tc39/proposal-optional-chaining 그것은 바벨 플러그인을 통해 오늘을 사용할 수, 그리고 너무 객체의 메소드를 호출하기위한 작동합니다 babeljs.io를 / docs / ko / babel-plugin-proposal-optional-chaining
theUtherSide

-5

이 질문은 2018 년에 약간의 새로 고침이 필요하다고 생각했습니다.이 라이브러리는 라이브러리를 사용하지 않고도 훌륭하게 수행 Object.defineProperty()할 수 있으며 다음과 같이 사용할 수 있습니다.

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

나는 MDN에 문서화 된 것처럼 의 방법에 사용할 수 있는 writeableenumerable정의 때문에이 안전하고 js-ethical이라고 생각합니다.definePropertyObject

아래 함수 정의 :

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
이를 통해 실제로 코드를 문자열로 작성합니다. 그렇게하는 것은 정말 나쁜 생각입니다. IDE 친화적이지 않은 코드 리팩토링이 불가능합니다.
tocqueville
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.