인터넷에서 온 이미지의 JavaScript 괴벽

12236 단어 javascript
최근에 나는 구글 사진에서 우연히 이 사진을 발견했다.

사진 속 사람은 Brendan Eich, Java Script의 창립자, 모질라 프로젝트의 공동 창시자이다.
설령 어떤 예가 언어 자체와 진정한 관계가 없다 하더라도 나는 그것이 매우 재미있고 간단명료하게 분해할 수 있다고 생각한다. 이것은 고전적인'엄격한 언어'(프로그래밍 배경만 있는 사람)에게는 큰 의미가 없다는 것을 감안하면.

붕괴


보어 섹션부터 시작합니다.

부동점 산술


> 9999999999999999
< 10000000000000000

> 0.5+0.1==0.6
< true

> 0.1+0.2==0.3
< false
이것은 결코 이상하지 않다. 이것은 이미 오래된 개념이다.물론 JavaScript의 특성과는 무관합니다.여기서 설명하기보다 this great'explainlikeimfive'사이트에 링크된 것만 남겨서 부동점 수학을 해석하는 데 사용합니다.

숫자 아니면 숫자.


> typeof NaN
< "number"
'난'은 도대체 뭐야?사실상 이것은 특정한 값의 표시로 수치 유형의 제한에 표시할 수 없다(실제로 유일한 JS 수치 원어는 float.NaN은 IEEE 754 부동 소수점 표준에 도입되었습니다.
그래서 이것은 단지 컴퓨터가 이 특정 환경에서 계산할 수 없는 숫자일 뿐이다.

유형 변환


JavaScript는 동적 형식 언어로 침묵 (은식) 형식의 강제에 익숙하지 않은 사람들에게 가장 얄미운'왜 이러니'디버깅 세션을 초래할 수 있다.
단순 섹션: 엄격함 ===
> true === 1
< false
엄격하게 두 값을 비교하다.비교를 진행하기 전에 두 값 모두 암시적으로 다른 값으로 변환되지 않습니다.값의 유형이 다르면 값이 같지 않다고 간주됩니다.부울 변수는 1이 아니라 숫자입니다.
다른 한편, 이것은 다음과 같다.
> true == 1
< true
이것은 암시적 유형 강제의 예이다.연산자를 다른 유형의 값에 적용하면 암시적 유형 강제가 발생합니다: 2+'2', 'true'+false, 35.5+new RegExp('de*v\.to') 또는 if (value) { 같은 특정 유형으로 예상되는 특정 컨텍스트에 값을 넣습니다.
JavaScript 형식 변환은 가장 간단한 부분이 아니기 때문에 저는 Alexey Samoshkin의 this great articlethis little MDN doc의 등식 비교에 관한 글을 더 읽을 것을 건의합니다.그리고 이것equality comparison cheatsheet이 도움이 될 것 같습니다.
어쨌든 우리 화면으로 돌아가자.
> [] + []
< ""
JS에는 두 가지 유형의 변수가 있습니다. 대상과 원어입니다. 원어는 boolean, number, string, boolean, undefined, null, symbolboolean 입니다.다른 모든 것은 함수와 그룹을 포함한 대상이다.
스텔스 변환을 호출하는 연산자를 포함하는 표현식을 실행하면 전체 표현식은 세 가지 기본 유형 중 하나로 변환됩니다.
  • 문자열
  • 번호
  • 원어 변환은 일부 규칙, 즉 pretty straightforward을 따른다.
    대상: true 상황에서 모든 비원어 값은 string 로 강제됩니다.numberPreferredType의 경우 다음 내부 작업ToPrimitive(input, PreferredType)을 실행 중이며 옵션numberstring 또는input.valueOf()이다.그러면 다음 알고리즘이 실행됩니다.
  • 입력이 기본이면 그대로 반환
  • 그렇지 않으면 입력이 객체로 간주됩니다.전화input.toString().결과가 기원이면 반환됩니다.
  • 그렇지 않으면 전화하십시오.결과가 기원이면 되돌려줍니다.
  • 그렇지 않으면 TypeError를 내보냅니다.
  • PreferredTypestring이면 2와 3을 교환합니다.
    위의 실제 JavaScript에서의 위조 실현을 보고 볼 수 있다. 게다가 볼 변환(처음에 앞에서 언급한 문장을 통해 이루어졌다courtesy of Alexey Samoshkin.
    function ToPrimitive(input, preferredType){
    
      switch (preferredType){
        case Boolean:
          return true;
          break;
        case Number:
          return toNumber(input);
          break;
        case String:
          return toString(input);
          break
        default:
          return toNumber(input);  
      }
    
      function isPrimitive(value){
        return value !== Object(value);
      }
    
      function toString(){
        if (isPrimitive(input.toString())) return input.toString();
        if (isPrimitive(input.valueOf())) return input.valueOf();
        throw new TypeError();
      }
    
      function toNumber(){
        if (isPrimitive(input.valueOf())) return input.valueOf();
        if (isPrimitive(input.toString())) return input.toString();
        throw new TypeError();
      }
    }
    
    따라서 당일 종료 시 원본[] + [] == ""은 다음과 같이 해석됩니다.
    ToPrimitive([]) + ToPrimitive([])
    
    두 그룹 모두 빈 문자열을 되돌려줍니다. 결과는 toString([]) 입니다.최종 결과는 두 개의 빈 문자열의 직렬입니다.
    이제 다음을 수행합니다.
    > [] + {}
    < "[object Object]"
    
    String({})로 인해[object Object], 결과는"""[object Object]"의 간단한 직렬이다.간단해.지금 이게 도대체 어떻게 된 일입니까?
    > {} + []
    < 0
    
    사실이 증명하듯이 JavaScript는 첫 번째{}를 코드 블록으로 설명합니다!해석 입력을 시작할 때부터 끝낼 때까지 { 을 블록의 시작으로 간주하고 닫습니다 }.따라서 우리의 위조 실현을 사용하면 앞의 예는 다음과 같이 평가될 것이다.
    ToPrimitive(+[])
    
    ..이것은 0입니다.+는 조작수를 숫자로 바꾸는 데 사용되는 일원 접두사 연산자이다.
    느슨함==과 바이너리+ 연산자는 항상 기본값preferredType을 터치하고 기본값은 숫자로 변환합니다(문자열을 반환한 날짜는 제외).이것은 true+true+true===3true==1를 설명한다.따라서 예상한 대로 true===1 되돌아오기 false 표현식 왼쪽에 연산자가 없기 때문에 === 은밀한 형식의 강제를 촉발하지 않습니다.[]==0과 마찬가지로 대체적으로 Number([]) == 0에 해당한다.
    모든 일은 재미있는 예를 가져다 줄 것이다. 예를 들어 우리가 여기에 있는 예:
    > (!+[]+[]+![]).length
    < 9
    
    그것을 분해하고,
  • (!+[]) + [] + (![])
  • !0+[]+가짜
  • 진+[]+가짜
  • 진+""+가짜
  • "진짜"
  • “truefalse”.길이 = = 9
    아주 간단해요.
    마지막으로 (가장 중요한 것은 솔직히 말하면):

    수학max()<수학.min()?


    > Math.max()
    < -Infinity
    > Math.min()
    < Infinity
    
    일부 파라미터가 필요한 함수가 의외의 결과를 되돌려주는 측면에서 볼 때, 이것은 비교적 작은 언어 결함으로 간주될 수 있다.
    그러나 사실 이 뒤에는 실제 수학 지식이 있다.
    이 가능하다, ~할 수 있다,...
    Math.max = function () {
      let temp = -Infinity;
      for ( let i = 0; i < arguments.length; i++ ) {
        let num = Number(arguments[i]);
        if ( num > temp ) {
          temp = num;
        }
      }
      return Number(temp);
    }
    
    현재, 매개 변수를 전달하지 않았을 때 되돌아오는 것은 의미가 있다.Math.max()-Infinityidentity element입니다.바이너리 작업의 표지 요소는 상기 작업을 두 요소에 적용한 후 다른 요소가 변하지 않는 요소이다.
    그래서 0은 덧셈의 항등식이고 1은 곱셈의 항등식이다.-InfinityMath.max() 은 항상 x+0 입니다.x*1x 에서 -Infinity 은 항상 최대 수입니다.
    찰리 하비의 절대gorgeous article는 이 화제를 깊이 있게 탐구했다.
    한 마디로 하면 스텔스 유형의 강제는 매우 중요한 개념이므로 당신은 시종 명심해야 합니다.느슨한 평등을 피하다.당신이 무엇을 비교하고 있는지 생각해 보세요. 가능한 한 현식 변환을 사용하세요.위의 내용이 두렵다면 TypeScript로 전환하는 것을 고려하십시오.)
    더 많은 "wtf"자바스크립트를 보고 싶다면, wtfjs 라는 훌륭한 자원이 있고, x 매뉴얼로도 제공할 수 있다.

    좋은 웹페이지 즐겨찾기