Programing

null 또는 정의되지 않은 값이있는 JavaScript 문자열 연결 동작

lottogame 2021. 1. 7. 07:32
반응형

null 또는 정의되지 않은 값이있는 JavaScript 문자열 연결 동작


아시다시피 JavaScript '' + null = "null"'' + undefined = "undefined"(대부분의 브라우저에서 테스트 할 수있는 Firefox, Chrome 및 IE). 나는이 기이함의 기원 (Brendan Eich의 머리에 도대체 무엇 이었는가?!)과 ECMA의 향후 버전에서 변경하려는 목표가 있는지 알고 싶습니다. 'sthg' + (var || '')Strings를 변수와 연결하고 Underscore 또는 기타 와 같은 타사 프레임 워크를 사용하여 젤리 네일을 두드리는 데 망치를 사용하는 것은 실제로 매우 실망 스럽습니다 .

편집하다:

StackOverflow에서 요구하는 기준을 충족하고 내 질문을 명확히하기 위해 세 가지 질문이 있습니다.

  • JS를 변환 null하거나 undefined문자열 값으로 String연결 하는 이상 함의 역사는 무엇입니까 ?
  • 향후 ECMAScript 버전에서이 동작이 변경 될 가능성이 있습니까?
  • 연결하는 예쁜 방법은 무엇입니까 String가능성 null또는 undefined이 문제 (일부 점점 떨어지는없이 객체 "undefined"의를 "null"문자열의 중간에)는? 가장 주관적인 기준이 예쁘다는 것은 짧고 깨끗하며 효과적이라는 뜻입니다. '' + (obj ? obj : '')정말 예쁘지 않다고 말할 필요 는 없습니다…

이 문제 [...]에 빠지지 않고 잠재적 인 null 또는 정의되지 않은 개체와 String을 연결하는 가장 예쁜 방법은 무엇입니까?

여러 가지 방법이 있으며 부분적으로 직접 언급했습니다. 간단히 말해서, 제가 생각할 수 있는 유일한 깨끗한 방법은 함수입니다.

const Strings = {};
Strings.orEmpty = function( entity ) {
    return entity || "";
};

// usage
const message = "This is a " + Strings.orEmpty( test );

물론 필요에 맞게 실제 구현을 변경할 수 있으며 변경해야합니다. 그리고 이것이 이미이 방법이 더 우수하다고 생각하는 이유입니다. 캡슐화를 도입했습니다.

실제로 캡슐화가없는 경우 "가장 예쁜"방법이 무엇인지 물어 보면됩니다. 이 질문 은 더 이상 구현을 변경할 수없는 상황에 처하게 될 것이라는 것을 이미 알고 있으므로 즉시 완벽하기를 원하기 때문입니다. 하지만 그게 문제입니다. 요구 사항,보기 및 환경이 변경됩니다. 그들은 진화합니다. 그렇다면 한 줄, 아마도 한두 개의 테스트를 적용하는 것만으로도 구현을 변경할 수있는 것은 어떨까요?

실제 논리를 구현하는 방법에 실제로 대답하지 않기 때문에 이것을 부정 행위라고 부를 수 있습니다. 하지만 그게 내 요점입니다. 그것은 중요하지 않습니다. 글쎄, 아마도 조금. 그러나 실제로 변경하는 것이 얼마나 간단하기 때문에 걱정할 필요가 없습니다. 인라인 방식이 아니기 때문에이 방식으로 구현하든 더 정교한 방식으로 구현하든 상관없이 훨씬 더 예쁘게 보입니다.

코드 전체에서 ||인라인 을 계속 반복하면 두 가지 문제가 발생합니다.

  • 중복 된 코드입니다.
  • 그리고 코드를 복제하기 때문에 향후 유지 관리 및 변경이 어려워집니다.

그리고 이것은 고품질 소프트웨어 개발과 관련하여 일반적으로 안티 패턴으로 알려진 두 가지 사항입니다.

어떤 사람들은 이것이 너무 많은 오버 헤드라고 말할 것입니다. 그들은 성능에 대해 이야기 할 것입니다. 말도 안돼. 우선 이것은 오버 헤드를 거의 추가하지 않습니다. 이것이 당신이 걱정하는 것이라면 잘못된 언어를 선택한 것입니다. jQuery조차도 함수를 사용합니다. 사람들은 마이크로 최적화를 극복해야합니다.

다른 하나는 "컴파일러"= 미니 파이어 코드를 사용할 수 있다는 것입니다. 이 영역의 좋은 도구는 컴파일 단계에서 인라인 할 문을 감지하려고합니다. 이런 식으로 코드를 깨끗하고 유지 관리 할 수있게 유지하면서 여전히 코드를 믿거 나 이것이 중요한 환경이있는 경우 마지막 성능 저하를 얻을 수 있습니다.

마지막으로 브라우저에 대한 믿음이 있습니다. 그들은 코드를 최적화 할 것이고 요즘에는 꽤 잘하고 있습니다.


Array.prototype.join무시 undefined하고 null다음을 사용할 수 있습니다 .

['a', 'b', void 0, null, 6].join(''); // 'ab6'

사양 에 따르면 :

요소undefined또는 null경우 다음 은 빈 문자열이됩니다. 그렇지 않으면 다음 이 ToString ( element )이되도록합니다.


을 고려하면,

  • JS를 변환 null하거나 undefined문자열 값으로 String연결 하는 이상 함의 역사는 무엇입니까 ?

    실제로 어떤 경우에는 현재 동작이 의미가 있습니다.

    function showSum(a,b) {
        alert(a + ' + ' + b + ' = ' + (+a + +b));
    }

    예를 들어 위의 함수가 인수없이 호출되는 undefined + undefined = NaN경우 + = NaN.

    일반적으로 문자열에 일부 변수를 삽입하려면 표시 undefined하거나 null의미가 있다고 생각합니다 . 아마도 Eich도 그렇게 생각했을 것입니다.

    물론 문자열을 결합 할 때와 같이 무시하는 것이 더 좋은 경우가 있습니다. 그러나 이러한 경우에는 Array.prototype.join.

  • 향후 ECMAScript 버전에서이 동작이 변경 될 가능성이 있습니까?

    대부분 그렇지 않습니다.

    이미 존재하므로 Array.prototype.join문자열 연결의 동작을 수정하면 단점 만 발생하지만 장점은 없습니다. 또한 오래된 코드를 깨뜨릴 수 있으므로 이전 버전과 호환되지 않습니다.

  • 잠재력을 가진 문자열을 연결하는 예쁜 방법은 무엇입니까 null또는 undefined?

    Array.prototype.join가장 간단한 것 같습니다. 그것이 가장 예쁜지 아닌지 여부는 의견 기반 일 수 있습니다.


ECMA 사양

사양 측면에서 이러한 방식으로 작동하는 이유를 구체화하기 위해이 작동은 버전 1 부터 존재했습니다 . 거기와 5.1의 정의는 의미 적으로 동일합니다. 5.1 정의를 보여 드리겠습니다.

섹션 11.6.1 : 더하기 연산자 (+)

더하기 연산자는 문자열 연결 또는 숫자 더하기를 수행합니다.

생산 AdditiveExpression : AdditiveExpression + MultiplicativeExpression 은 다음과 같이 평가됩니다.

  1. lref를 AdditiveExpression을 평가 한 결과라고 합시다 .
  2. 하자 LVAL BE GetValue ( lref ).
  3. rref를 MultiplicativeExpression을 평가 한 결과라고 합시다 .
  4. Let rval be GetValue(rref).
  5. Let lprim be ToPrimitive(lval).
  6. Let rprim be ToPrimitive(rval).
  7. If Type(lprim) is String or Type(rprim) is String, then
    a. Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)
  8. Return the result of applying the addition operation to ToNumber(lprim) and ToNumber(rprim). See the Note below 11.6.3.

So, if either value ends up being a String, then ToString is used on both arguments (line 7) and those are concatenated (line 7a). ToPrimitive returns all non-object values unchanged, so null and undefined are untouched:

Section 9.1 ToPrimitive

The abstract operation ToPrimitive takes an input argument and an optional argument PreferredType. The abstract operation ToPrimitive converts its input argument to a non-Object type ... Conversion occurs according to Table 10:

For all non-Object types, including both Null and Undefined, [t]he result equals the input argument (no conversion). So ToPrimitive does nothing here.

Finally, Section 9.8 ToString

The abstract operation ToString converts its argument to a value of type String according to Table 13:

Table 13 gives "undefined" for the Undefined type and "null" for the Null type.

Will it change? Is it even an "oddity"?

As others have pointed out, this is very unlikely to change as it would break backward compatibility (and bring no real benefit), even more so given that this behavior is the same since the 1997 version of the spec. I would also not really consider it an oddity.

If you were to change this behavior, would you change the definition of ToString for null and undefined or would you special-case the addition operator for these values? ToString is used many, many places throughout the spec and "null" seems like an uncontroversial choice for representing null. Just to give a couple of examples, in Java "" + null is the string "null" and in Python str(None) is the string "None".

Workaround

Others have given good workarounds, but I would add that I doubt you want to use entity || "" as your strategy since it resolves true to "true" but false to "". The array join in this answer has the more expected behavior, or you could change the implementation of this answer to check entity == null (both null == null and undefined == null are true).


Is there any chance for a change in this behavior in future ECMAScript versions?

I would say the chances are very slim. And there are several reasons:

We already know what ES5 and ES6 look like

The future ES versions are already done or in draft. Neither one, afaik, changes this behavior. And the thing to keep in mind here is that it will take years for these standards to be established in browsers in the sense that you can write applications with these standards without relying on proxy tools that compile it to actual Javascript.

Just try to estimate the duration. Not even ES5 is fully supported by the majority of browsers out there and it will probably take another few years. ES6 is not even fully specified yet. Out of the blue, we are looking at at least another five years.

Browsers do their own things

Browsers are known to make their own decisions on certain topics. You don't know whether all browsers will fully support this feature in exactly the same way. Of course you would know once it is part of the standard, but as of now, even if it was announced to become part of ES7, it would only be speculation at best.

And browsers may make their own decision here especially because:

This change is breaking

One of the biggest things about standards is that they usually try to be backwards compatible. This is especially true for the web where the same code has to run on all kinds of envrionments.

If the standard introduces a new feature and it's not supported in old browsers, that's one thing. Tell your client to update their browser to use the site. But if you update your browser and suddenly half the internet breaks for you, that's a bug uhm-no.

Sure, this particular change is unlikely to break a lot of scripts. But that's usually a poor arguments because a standard is universal and has to take every chance into account. Just consider

"use strict";

as the instruction to switch to strict mode. It goes to show huw much effort a standard puts into trying to make everything compatible, because they could've made strict mode the default (and even only mode). But with this clever instruction, you allow old code to run without a change and still can take advantage of the new, stricter mode.

Another example for backwards compatibility: the === operator. == is fundamentally flawed (though some people disagree) and it could've just changed its meaning. Instead, === was introduced, allowing old code to still run without breaking; at the same time allowing new programs to be written using a more strict check.

And for a standard to break compatibility, there has to be a very good reason. Which brings us to

There is just no good reason

Yes, it bugs you. That's understandable. But ultimately, it is nothing that can't be solved very easily. Use ||, write a function – whatever. You can make it work at almost no cost. So what is really the benefit for investing all the time and effort into analyzing this change which we know is breaking anyway? I just don't see the point.

Javascript has several weak points in its design. And it has increasingly become a bigger issue as the language became more and more important and powerful. But while there are very good reasons to change a lot of its design, other things just arent't meant to be changed.


Disclaimer: This answer is partly opinion-based.


To add null and '' they need to meet a minimum common type criterium which in this case is a string type.

null is converted to "null" for this reason and as they are string the two are concatenated.

The same happens with numbers:

4 + '' = '4'

as there is a string in there which can't be converted to any number, so the 4 will be converted to string instead.

ReferenceURL : https://stackoverflow.com/questions/20572016/javascript-string-concatenation-behavior-with-null-or-undefined-values

반응형