├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── new-example.md ├── PULL_REQUEST_TEMPLATE │ ├── new_example.md │ └── translation.md ├── dependabot.yml └── workflows │ ├── release.yml │ └── validate.yml ├── .gitignore ├── .husky └── pre-commit ├── CONTRIBUTING.md ├── LICENSE ├── README-fr-fr.md ├── README-hi.md ├── README-it-it.md ├── README-kr.md ├── README-pl-pl.md ├── README-pt-br.md ├── README-si.md ├── README-zh-cn.md ├── README.md ├── package-lock.json ├── package.json └── wtfjs.js /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | 9 | [package.json] 10 | indent_style = space 11 | indent_size = 2 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: denysdovhan 2 | patreon: denysdovhan 3 | custom: [buymeacoffee.com/denysdovhan] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/new-example.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New Example 3 | about: A new example for wtfjs collection 4 | title: '' 5 | labels: new-example 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/new_example.md: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/translation.md: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "monthly" 8 | 9 | # Maintain dependencies for npm 10 | - package-ecosystem: "npm" 11 | directory: "/" 12 | schedule: 13 | interval: "monthly" 14 | open-pull-requests-limit: 10 15 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - master 6 | jobs: 7 | release: 8 | name: Prepare release 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 🛑 Cancel Previous Runs 12 | uses: styfle/cancel-workflow-action@0.9.1 13 | 14 | - name: ⬇️ Checkout Repo 15 | uses: actions/checkout@v3 16 | 17 | - name: ⬢ Setup Node.js 18 | uses: actions/setup-node@v3 19 | with: 20 | node-version: "*" 21 | cache: npm 22 | 23 | - name: 📦 Install Packages 24 | run: npm ci 25 | 26 | - name: 📝 Generate TOC 27 | run: npm run toc 28 | 29 | - name: 💅 Format files 30 | run: npm run format 31 | 32 | - name: 🚀 Release 33 | run: npx semantic-release 34 | env: 35 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 37 | -------------------------------------------------------------------------------- /.github/workflows/validate.yml: -------------------------------------------------------------------------------- 1 | name: Validate 2 | on: 3 | push: 4 | pull_request: 5 | 6 | jobs: 7 | validate: 8 | name: Validate 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 🛑 Cancel Previous Runs 12 | uses: styfle/cancel-workflow-action@0.9.1 13 | 14 | - name: ⬇️ Checkout Repo 15 | uses: actions/checkout@v3 16 | 17 | - name: ⬢ Setup Node.js 18 | uses: actions/setup-node@v3 19 | with: 20 | node-version: "*" 21 | cache: npm 22 | 23 | - name: 📦 Install Packages 24 | run: npm ci 25 | 26 | - name: 💅 Check formatting 27 | run: npm test 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | npm-debug.log 4 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | This guide will help you to contribute to this project smoothly. Please, read carefully to make your contribution process easier. 4 | 5 | Usually, this project has two types of contributions: _new examples_ and _translations_. 6 | 7 | ## New Examples 8 | 9 | **New examples will be accepted only if they have an explanation.** Preferably, the explanation should contain links to the specification, blog posts, forum publications. 10 | 11 | If you don't know why an example works the way it works, ask for help on [the discussion forum](https://github.com/denysdovhan/wtfjs/discussions). 12 | 13 | Issues without explanations will be closed. 14 | 15 | ## Translations 16 | 17 | **If you want a translation, please, make one.** Issues with translation requests will be closed in favor of PRs. 18 | 19 | Before sending a PR with translation, please check if there are any existing PRs with translation to your language. 20 | 21 | **You have to find someone who speaks your language natively to read, check and verify your translation.** That's how we are trying to prevent typos and mistakes. 22 | 23 | --- 24 | 25 | Thanks for understanding, have fun! 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2017 Denys Dovhan 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /README-kr.md: -------------------------------------------------------------------------------- 1 | # 아니 X발? 자바스크립트 이게 뭐야?? 2 | 3 | [![WTFPL 2.0][license-image]][license-url] 4 | [![NPM version][npm-image]][npm-url] 5 | 6 | > 재미있고 교묘한 JavaScript 예제 7 | 8 | JavaScript는 훌륭한 언어입니다. JavaScript는 구문이 단순하며 큰 생태계를 가지고 있습니다. 가장 중요한 점은 훌륭한 공동체를 가지고 있다는 것입니다. 9 | 10 | 동시에, 우리 모두는 JavaScript가 까다로운 부분을 가진 꽤 재미있는 언어라는 것을 알고 있습니다. 몇몇 특징은 우리의 일상적인 일을 순식간에 지옥으로 바꾸기도 하고, 우리를 크게 웃게 만들기도 합니다. 11 | 12 | WTFJS의 아이디어는 [Brian Leroux](https://twitter.com/brianleroux)에 속해있습니다. 이 목록들은 그의 이야기에서 꽤 영감을 받았습니다. [**“WTFJS”** at dotJS 2012](https://www.youtube.com/watch?v=et8xNAc2ic8): 13 | 14 | [![dotJS 2012 - Brian Leroux - WTFJS](https://img.youtube.com/vi/et8xNAc2ic8/0.jpg)](https://www.youtube.com/watch?v=et8xNAc2ic8) 15 | 16 | # NPM 패키지 메뉴스크립트 17 | 18 | 이 핸드북은 `npm`를 이용하여 설치할 수 있습니다. 그냥 실행합시다: 19 | 20 | ``` 21 | $ npm install -g wtfjs 22 | ``` 23 | 24 | 이제 당신은 커맨드 창에서 'wtfjs'를 실행할 수 있게 되었습니다. 당신이 선택한 '$PAGER'에서 'wtfjs'가 열릴 것 입니다. 아니면 계속 여기서 읽어도 됩니다. 25 | 26 | 출처는 여기에서 확인 할 수 있습니다. 27 | 28 | # 번역 29 | 30 | 현재, **wtfjs**는 아래와 같은 언어로 번역되었습니다: 31 | 32 | - [中文版](./README-zh-cn.md) 33 | - [हिंदी](./README-hi.md) 34 | - [Français](./README-fr-fr.md) 35 | - [Português do Brasil](./README-pt-br.md) 36 | - [Polski](./README-pl-pl.md) 37 | - [Italiano](./README-it-it.md) 38 | - [Russian](https://habr.com/ru/company/mailru/blog/335292/) (on Habr.com) 39 | - [한국어](./README-kr.md) 40 | 41 | [**다른 번역 **][tr-request] 42 | 43 | [tr-request]: https://github.com/denysdovhan/wtfjs/issues/new?title=Translation%20Request:%20%5BPlease%20enter%20language%20here%5D&body=I%20am%20able%20to%20translate%20this%20language%20%5Byes/no%5D 44 | 45 | 46 | 47 | 48 | # Table of Contents 49 | 50 | - [💪🏻 시작하기에 앞서](#-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0%EC%97%90-%EC%95%9E%EC%84%9C) 51 | - [✍🏻 표기법](#-%ED%91%9C%EA%B8%B0%EB%B2%95) 52 | - [👀 예제](#-%EC%98%88%EC%A0%9C) 53 | - [`[]`와 `![]은 같다`](#%EC%99%80-%EC%9D%80-%EA%B0%99%EB%8B%A4) 54 | - [`true`는 `![]`와 같지 않지만, `[]`와도 같지 않다](#true%EB%8A%94-%EC%99%80-%EA%B0%99%EC%A7%80-%EC%95%8A%EC%A7%80%EB%A7%8C-%EC%99%80%EB%8F%84-%EA%B0%99%EC%A7%80-%EC%95%8A%EB%8B%A4) 55 | - [true는 false](#true%EB%8A%94-false) 56 | - [baNaNa](#banana) 57 | - [`NaN`은 `NaN`이 아니다](#nan%EC%9D%80-nan%EC%9D%B4-%EC%95%84%EB%8B%88%EB%8B%A4) 58 | - [이것은 실패다](#%EC%9D%B4%EA%B2%83%EC%9D%80-%EC%8B%A4%ED%8C%A8%EB%8B%A4) 59 | - [`[]`은 truthy 이지만 `true`는 아니다](#%EC%9D%80-truthy-%EC%9D%B4%EC%A7%80%EB%A7%8C-true%EB%8A%94-%EC%95%84%EB%8B%88%EB%8B%A4) 60 | - [`null`은 falsy 이지만 `false`은 아니다](#null%EC%9D%80-falsy-%EC%9D%B4%EC%A7%80%EB%A7%8C-false%EC%9D%80-%EC%95%84%EB%8B%88%EB%8B%A4) 61 | - [`document.all`은 객체이지만 `undefined`이다](#documentall%EC%9D%80-%EA%B0%9D%EC%B2%B4%EC%9D%B4%EC%A7%80%EB%A7%8C-undefined%EC%9D%B4%EB%8B%A4) 62 | - [최소 값은 0 보다 크다](#%EC%B5%9C%EC%86%8C-%EA%B0%92%EC%9D%80-0-%EB%B3%B4%EB%8B%A4-%ED%81%AC%EB%8B%A4) 63 | - [함수는 함수가 아니다](#%ED%95%A8%EC%88%98%EB%8A%94-%ED%95%A8%EC%88%98%EA%B0%80-%EC%95%84%EB%8B%88%EB%8B%A4) 64 | - [배열 추가](#%EB%B0%B0%EC%97%B4-%EC%B6%94%EA%B0%80) 65 | - [배열의 후행 쉼표](#%EB%B0%B0%EC%97%B4%EC%9D%98-%ED%9B%84%ED%96%89-%EC%89%BC%ED%91%9C) 66 | - [배열 평등은 몬스터](#%EB%B0%B0%EC%97%B4-%ED%8F%89%EB%93%B1%EC%9D%80-%EB%AA%AC%EC%8A%A4%ED%84%B0) 67 | - [`undefined`과 `Number`](#undefined%EA%B3%BC-number) 68 | - [`parseInt`은 나쁜 놈이다](#parseint%EC%9D%80-%EB%82%98%EC%81%9C-%EB%86%88%EC%9D%B4%EB%8B%A4) 69 | - [`true`와 `false`를 이용한 수학](#true%EC%99%80-false%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%88%98%ED%95%99) 70 | - [HTML 주석은 JavaScript에서도 유효하다](#html-%EC%A3%BC%EC%84%9D%EC%9D%80-javascript%EC%97%90%EC%84%9C%EB%8F%84-%EC%9C%A0%ED%9A%A8%ED%95%98%EB%8B%A4) 71 | - [`NaN`은 숫자가 아니다](#nan%EC%9D%80-%EC%88%AB%EC%9E%90%EA%B0%80-%EC%95%84%EB%8B%88%EB%8B%A4) 72 | - [`[]`과 `null`은 객체이다](#%EA%B3%BC-null%EC%9D%80-%EA%B0%9D%EC%B2%B4%EC%9D%B4%EB%8B%A4) 73 | - [마법처럼 증가하는 숫자](#%EB%A7%88%EB%B2%95%EC%B2%98%EB%9F%BC-%EC%A6%9D%EA%B0%80%ED%95%98%EB%8A%94-%EC%88%AB%EC%9E%90) 74 | - [정확도 `0.1 + 0.2`](#%EC%A0%95%ED%99%95%EB%8F%84-01--02) 75 | - [패치 번호](#%ED%8C%A8%EC%B9%98-%EB%B2%88%ED%98%B8) 76 | - [세 숫자의 비교](#%EC%84%B8-%EC%88%AB%EC%9E%90%EC%9D%98-%EB%B9%84%EA%B5%90) 77 | - [재미있는 수학](#%EC%9E%AC%EB%AF%B8%EC%9E%88%EB%8A%94-%EC%88%98%ED%95%99) 78 | - [RegExps 추가](#regexps-%EC%B6%94%EA%B0%80) 79 | - [문자열은 `String`의 인스턴스가 아니다](#%EB%AC%B8%EC%9E%90%EC%97%B4%EC%9D%80-string%EC%9D%98-%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4%EA%B0%80-%EC%95%84%EB%8B%88%EB%8B%A4) 80 | - [backticks으로 함수 호출](#backticks%EC%9C%BC%EB%A1%9C-%ED%95%A8%EC%88%98-%ED%98%B8%EC%B6%9C) 81 | - [Call call call](#call-call-call) 82 | - [`constructor` 속성](#constructor-%EC%86%8D%EC%84%B1) 83 | - [객체 속성의 키로서의 객체](#%EA%B0%9D%EC%B2%B4-%EC%86%8D%EC%84%B1%EC%9D%98-%ED%82%A4%EB%A1%9C%EC%84%9C%EC%9D%98-%EA%B0%9D%EC%B2%B4) 84 | - [`__proto__`을 사용한 프로토 타입 접근](#__proto__%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%ED%94%84%EB%A1%9C%ED%86%A0-%ED%83%80%EC%9E%85-%EC%A0%91%EA%B7%BC) 85 | - [`` `${{Object}}` ``](#-object-) 86 | - [디폴트 값으로 구조 해제](#%EB%94%94%ED%8F%B4%ED%8A%B8-%EA%B0%92%EC%9C%BC%EB%A1%9C-%EA%B5%AC%EC%A1%B0-%ED%95%B4%EC%A0%9C) 87 | - [Dots와 spreading](#dots%EC%99%80-spreading) 88 | - [라벨](#%EB%9D%BC%EB%B2%A8) 89 | - [중첩된 라벨들](#%EC%A4%91%EC%B2%A9%EB%90%9C-%EB%9D%BC%EB%B2%A8%EB%93%A4) 90 | - [교활한 `try..catch`](#%EA%B5%90%ED%99%9C%ED%95%9C-trycatch) 91 | - [이것은 다중 상속인가?](#%EC%9D%B4%EA%B2%83%EC%9D%80-%EB%8B%A4%EC%A4%91-%EC%83%81%EC%86%8D%EC%9D%B8%EA%B0%80) 92 | - [스스로 생성되는 Generator](#%EC%8A%A4%EC%8A%A4%EB%A1%9C-%EC%83%9D%EC%84%B1%EB%90%98%EB%8A%94-generator) 93 | - [클래스의 클래스](#%ED%81%B4%EB%9E%98%EC%8A%A4%EC%9D%98-%ED%81%B4%EB%9E%98%EC%8A%A4) 94 | - [강제할 수 없는 객체](#%EA%B0%95%EC%A0%9C%ED%95%A0-%EC%88%98-%EC%97%86%EB%8A%94-%EA%B0%9D%EC%B2%B4) 95 | - [까다로운 화살표 함수](#%EA%B9%8C%EB%8B%A4%EB%A1%9C%EC%9A%B4-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98) 96 | - [화살표 함수는 생성자가 될 수 없다](#%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98%EB%8A%94-%EC%83%9D%EC%84%B1%EC%9E%90%EA%B0%80-%EB%90%A0-%EC%88%98-%EC%97%86%EB%8B%A4) 97 | - [`arguments`와 화살표 함수](#arguments%EC%99%80-%ED%99%94%EC%82%B4%ED%91%9C-%ED%95%A8%EC%88%98) 98 | - [까다로운 return](#%EA%B9%8C%EB%8B%A4%EB%A1%9C%EC%9A%B4-return) 99 | - [객체에 할당 연결](#%EA%B0%9D%EC%B2%B4%EC%97%90-%ED%95%A0%EB%8B%B9-%EC%97%B0%EA%B2%B0) 100 | - [배열을 사용한 객체 속성 접근 s](#%EB%B0%B0%EC%97%B4%EC%9D%84-%EC%82%AC%EC%9A%A9%ED%95%9C-%EA%B0%9D%EC%B2%B4-%EC%86%8D%EC%84%B1-%EC%A0%91%EA%B7%BC-s) 101 | - [Null 및 관계 연산자](#null-%EB%B0%8F-%EA%B4%80%EA%B3%84-%EC%97%B0%EC%82%B0%EC%9E%90) 102 | - [`Number.toFixed()` 다른 숫자 표시](#numbertofixed-%EB%8B%A4%EB%A5%B8-%EC%88%AB%EC%9E%90-%ED%91%9C%EC%8B%9C) 103 | - [`Math.max()` 이하 `Math.min()`](#mathmax-%EC%9D%B4%ED%95%98-mathmin) 104 | - [`null`과 `0` 비교](#null%EA%B3%BC-0-%EB%B9%84%EA%B5%90) 105 | - [동일한 변수 재선언](#%EB%8F%99%EC%9D%BC%ED%95%9C-%EB%B3%80%EC%88%98-%EC%9E%AC%EC%84%A0%EC%96%B8) 106 | - [디폴트 동작 Array.prototype.sort()](#%EB%94%94%ED%8F%B4%ED%8A%B8-%EB%8F%99%EC%9E%91-arrayprototypesort) 107 | - [resolve()은 Promise instance를 반환하지 않는다](#resolve%EC%9D%80-promise-instance%EB%A5%BC-%EB%B0%98%ED%99%98%ED%95%98%EC%A7%80-%EC%95%8A%EB%8A%94%EB%8B%A4) 108 | - [📚 기타 resources](#-%EA%B8%B0%ED%83%80-resources) 109 | - [🎓 License](#-license) 110 | 111 | 112 | 113 | 114 | # 💪🏻 시작하기에 앞서 115 | 116 | > — _[**“Just for Fun: 우연한 혁명가의 이야기”**](https://en.wikipedia.org/wiki/Just_for_Fun), Linus Torvalds_ 117 | 118 | 이 목록의 주요 목표는 가능한 JavaScript의 몇 가지의 엄청난 예제들을 모으고, 작동 방식을 설명하는 것 입니다. 이전에 우리가 몰랐던 것들을 배우는 것이 재미있기 때문입니다. 119 | 120 | 당신이 초보자라면, 이 노트를 사용하여 JavaScript에 대해 자세히 알아볼 수 있을 것입니다. 이 노트의 설명을 읽는 것에 더 많은 시간을 할애할 수 있기를 바랍니다. 121 | 122 | 당신이 전문 개발자라면, 우리가 사랑하는 JavaScript의 모든 기이한 점과 예상치 못한 것들에 대한 예시에 훌륭한 참조로 간주할 수 있습니다. 123 | 124 | 어쨌든, 이것을 읽읍시다. 당신은 아마 새로운 것들을 찾을 수 있을 것입니다. 125 | 126 | # ✍🏻 표기법 127 | 128 | **`// ->`** 식의 결과를 표시하는 데 사용됩니다. 예를 들면: 129 | 130 | ```js 131 | 1 + 1; // -> 2 132 | ``` 133 | 134 | **`// >`** `console.log` 또는 다른 출력의 결과를 의미합니다. 예를 들면: 135 | 136 | ```js 137 | console.log("hello, world!"); // > hello, world! 138 | ``` 139 | 140 | **`//`** 설명에 사용되는 주석입니다. 예를 들면: 141 | 142 | ```js 143 | // Assigning a function to foo constant 144 | const foo = function() {}; 145 | ``` 146 | 147 | # 👀 예제 148 | 149 | ## `[]`와 `![]은 같다` 150 | 151 | 배열은 배열이 아닙니다: 152 | 153 | ```js 154 | [] == ![]; // -> true 155 | ``` 156 | 157 | ### 💡 설명: 158 | 159 | 추상 항등 연산자는 양쪽을 숫자로 변환하여 비교하고, 서로 다른 이유로 양 쪽의 숫자는 `0`이 됩니다. 배열은 truthy 하므로, 오른쪽의 값은 `0`을 강요하는 truthy value의 반대 값 즉, `false`입니다. 그러나 왼쪽은 빈 배열은 먼저 boolean이 되지 않고 숫자로 강제 변환되고 빈 배열은 truthy 임에도 불구하고 `0`으로 강요됩니다. 160 | 161 | 이 표현식이 어떻게 단순화 되는지는 아래와 같습니다: 162 | 163 | ```js 164 | +[] == +![]; 165 | 0 == +false; 166 | 0 == 0; 167 | true; 168 | ``` 169 | 170 | 참조 [`[]`은 truthy 이지만 `true`은 아니다](#%EC%9D%80-truthy-%EC%9D%B4%EC%A7%80%EB%A7%8C-true%EB%8A%94-%EC%95%84%EB%8B%88%EB%8B%A4). 171 | 172 | - [**12.5.9** 논리 연산자 NOT (`!`)](https://www.ecma-international.org/ecma-262/#sec-logical-not-operator) 173 | - [**7.2.13** 추상 평등](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 174 | 175 | ## `true`는 `![]`와 같지 않지만, `[]`와도 같지 않다 176 | 177 | 배열은 `true`와 같지 않지만 배열이 아닌것도 `true`와 같지 않습니다; 178 | 배열은 `false`와 같지만 배열이 아닌것도 `false`와 같습니다: 179 | 180 | ```js 181 | true == []; // -> false 182 | true == ![]; // -> false 183 | 184 | false == []; // -> true 185 | false == ![]; // -> true 186 | ``` 187 | 188 | ### 💡 설명: 189 | 190 | ```js 191 | true == []; // -> false 192 | true == ![]; // -> false 193 | 194 | // According to the specification 195 | 196 | true == []; // -> false 197 | 198 | toNumber(true); // -> 1 199 | toNumber([]); // -> 0 200 | 201 | 1 == 0; // -> false 202 | 203 | true == ![]; // -> false 204 | 205 | ![]; // -> false 206 | 207 | true == false; // -> false 208 | ``` 209 | 210 | ```js 211 | false == []; // -> true 212 | false == ![]; // -> true 213 | 214 | // According to the specification 215 | 216 | false == []; // -> true 217 | 218 | toNumber(false); // -> 0 219 | toNumber([]); // -> 0 220 | 221 | 0 == 0; // -> true 222 | 223 | false == ![]; // -> true 224 | 225 | ![]; // -> false 226 | 227 | false == false; // -> true 228 | ``` 229 | 230 | - [**7.2.13** 추상 평등 비교](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 231 | 232 | ## true는 false 233 | 234 | ```js 235 | !!"false" == !!"true"; // -> true 236 | !!"false" === !!"true"; // -> true 237 | ``` 238 | 239 | ### 💡 설명: 240 | 241 | 다음 단계를 고려합시다: 242 | 243 | ```js 244 | // true is 'truthy' and represented by value 1 (number), 'true' in string form is NaN. 245 | true == "true"; // -> false 246 | false == "false"; // -> false 247 | 248 | // 'false' is not the empty string, so it's a truthy value 249 | !!"false"; // -> true 250 | !!"true"; // -> true 251 | ``` 252 | 253 | - [**7.2.13** 추상 평등 비교](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 254 | 255 | ## baNaNa 256 | 257 | ```js 258 | "b" + "a" + +"a" + "a"; // -> 'baNaNa' 259 | ``` 260 | 261 | 이것은 JavaScript에서 구식 농담이지만 재해석 되었습니다. 원본은 다음과 같습니다: 262 | 263 | ```js 264 | "foo" + +"bar"; // -> 'fooNaN' 265 | ``` 266 | 267 | ### 💡 설명: 268 | 269 | 식은 `'foo' + (+'bar')`으로 평가되고 숫자가 아닌 `'bar'` 형태로 변환됩니다. 270 | 271 | - [**12.8.3** 덧셈 연산자 (`+`)](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus) 272 | - [12.5.6 단항 + 연산자](https://www.ecma-international.org/ecma-262/#sec-unary-plus-operator) 273 | 274 | ## `NaN`은 `NaN`이 아니다 275 | 276 | ```js 277 | NaN === NaN; // -> false 278 | ``` 279 | 280 | ### 💡 설명: 281 | 282 | 아래의 사항들로 동작의 논리를 엄격하게 정의합니다: 283 | 284 | > 1. 만약 `Type(x)`와 `Type(y)`가 다르면 **false**를 반환합니다. 285 | > 2. 만약 `Type(x)`이 숫자이고 286 | > 1. `x`가 **NaN**이면 **false**를 반환합니다. 287 | > 2. `y`가 **NaN**이면 **false**를 반환합니다. 288 | > 3. … … … 289 | > 290 | > — [**7.2.14** 염격한 평등 비교](https://www.ecma-international.org/ecma-262/#sec-strict-equality-comparison) 291 | 292 | IEEE에서 정의한 `NaN`: 293 | 294 | > 4 개의 상호 배타적인 관계 : 보다 작음, 같음, 보다 큼, 순서 없음. 마지막의 경우 하나 이상의 피연산자가 NaN일 때 발생합니다. 모든 NaN은 자신을 포함한 모든 것과 순서 없이 비교해야 합니다. 295 | > 296 | > — [“IEEE754 NaN 값에 false를 반환하는 것의 근거는 무엇입니까?”](https://stackoverflow.com/questions/1565164/1573715#1573715) StackOverflow에서 297 | 298 | ## 이것은 실패다 299 | 300 | 당신은 믿지 않을지도 모르지만 … 301 | 302 | ```js 303 | (![] + [])[+[]] + 304 | (![] + [])[+!+[]] + 305 | ([![]] + [][[]])[+!+[] + [+[]]] + 306 | (![] + [])[!+[] + !+[]]; 307 | // -> 'fail' 308 | ``` 309 | 310 | ### 💡 설명: 311 | 312 | 기호를 하나하나 나누면 아래와 같은 패턴이 자주 발생하는 것을 알 수 있습니다: 313 | 314 | ```js 315 | ![] + []; // -> 'false' 316 | ![]; // -> false 317 | ``` 318 | 319 | 그래서 `[]`를 `false`으로 바꾸는 시도를 해봅니다. 하지만 많은 내부 함수 호출(`binary + Operator` -> `ToPrimitive` -> `[[DefaultValue]]`)때문에 오른쪽 피 연산 문자열로 변환하게 됩니다: 320 | 321 | ```js 322 | ![] + [].toString(); // 'false' 323 | ``` 324 | 325 | 문자열을 배열로 생각하면 `[0]`을 통해 첫 번째 문자에 접근할 수 있습니다: 326 | 327 | ```js 328 | "false"[0]; // -> 'f' 329 | ``` 330 | 331 | 나머지는 분명하지만 `i`는 꽤 까다롭습니다. `fail` 속 `i`는 'falseundefined'라는 문자열을 생성하고 `['10']` 인덱스를 사용하여 요소를 잡습니다. 332 | 333 | ## `[]`은 truthy 이지만 `true`는 아니다 334 | 335 | 배열은 truthy 한 값이지만 `true`와 같지는 않다. 336 | 337 | ```js 338 | !![] // -> true 339 | [] == true // -> false 340 | ``` 341 | 342 | ### 💡 설명: 343 | 344 | 다음은 ECMA-262 명세된 것의 세션에 대한 링크입니다: 345 | 346 | - [**12.5.9** 논리 NOT 연산자 (`!`)](https://www.ecma-international.org/ecma-262/#sec-logical-not-operator) 347 | - [**7.2.13** 추상 평등 비교](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 348 | 349 | ## `null`은 falsy 이지만 `false`은 아니다 350 | 351 | `null`은 falsy 값이라는 사실에도 불구하고 `false`는 아닙니다. 352 | 353 | ```js 354 | !!null; // -> false 355 | null == false; // -> false 356 | ``` 357 | 358 | 동시에 `0` 또는 `''`와 같은 falsy 값은 `false`와 동일합니다. 359 | 360 | ```js 361 | 0 == false; // -> true 362 | "" == false; // -> true 363 | ``` 364 | 365 | ### 💡 설명: 366 | 367 | 설명은 이전 예제와 동일합니다. 다음은 해당 링크입니다: 368 | 369 | - [**7.2.13** 추상 평등 비교](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 370 | 371 | ## `document.all`은 객체이지만 `undefined`이다 372 | 373 | > ⚠️ 이 파트는 브라우저 API 의 일부이며 Node.js 환경에서는 작동하지 않습니다.⚠️ 374 | 375 | `document.all`은 배열과 같은 클래스이고 페이지의 DOM 노드에 대한 엑세스를 제공한다는 사실에도 불구하고 `typeof`함수의 `undefined`으로 반응합니다. 376 | 377 | ```js 378 | document.all instanceof Object; // -> true 379 | typeof document.all; // -> 'undefined' 380 | ``` 381 | 382 | 동시에 `document.all`은 `undefined`와 동일하지 않습니다. 383 | 384 | ```js 385 | document.all === undefined; // -> false 386 | document.all === null; // -> false 387 | ``` 388 | 389 | 하지만 동시에: 390 | 391 | ```js 392 | document.all == null; // -> true 393 | ``` 394 | 395 | ### 💡 설명: 396 | 397 | > 특히 이전 버전의 IE에서 `document.all`은 DOM 요소에 접근하는 방법을 사용했습니다. 이것은 표준이 된 적은 없지만 이전 JavaScript 코드에서 사용되었습니다. 새로운 APIs(`document.getElementById`와 같은)에서 표준이 진행되었을 때 이 API 호출은 쓸모 없게 되었고 표준 위원회는 이를 어떻게 처리할지 결정해야 했습니다. 광범위하게 사용되기 때문에 그들은 API를 유지하기로 결정했지만 JavaScript 명세된 것을 고의로 위반했습니다. 398 | > 이것이 `undefined`의 상황에서 [엄격한 평등 비교](https://www.ecma-international.org/ecma-262/#sec-strict-equality-comparison)을 사용했을 때 `false`를 응답하고 [추상 평등 비교](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison)을 사용할 때 `true`로 응답하는 이유는 명시적으로 허용하는 명세된 것의 의도적인 위반 때문입니다. 399 | > 400 | > — [“오래된 특징 - document.all”](https://html.spec.whatwg.org/multipage/obsolete.html#dom-document-all) WhatWG의 HTML 명세된 것 401 | > — [“Chapter 4 - ToBoolean - Falsy values”](https://github.com/getify/You-Dont-Know-JS/blob/0d79079b61dad953bbfde817a5893a49f7e889fb/types%20%26%20grammar/ch4.md#falsy-objects) YDKJS의 Types & Grammar 402 | 403 | ## 최소 값은 0 보다 크다 404 | 405 | `Number.MIN_VALUE`은 0 보다 큰 가장 작은 숫자입니다: 406 | 407 | ```js 408 | Number.MIN_VALUE > 0; // -> true 409 | ``` 410 | 411 | ### 💡 설명: 412 | 413 | > `Number.MIN_VALUE`은 `5e-324`입니다. 즉, 부동 소수점 정밀도 내에서 표현할 수 있는 가장 작은 양수입니다. 이 말은 0 에 도달할 수 있는 가장 가까운 값이라는 의미 입니다. 이것은 소수가 제공할 수 있는 최상의 값이라고 정의할 수 있습니다. 414 | > 415 | > 비록 엄격하게 실제로 숫자는 아니지만 전체적으로 가장 작은 값은 `Number.NEGATIVE_INFINITY`이라고 할 수 있습니다. 416 | > 417 | > — [“자바 스크립트에서 왜 `0`은 `Number.MIN_VALUE`보다 작습니까?”](https://stackoverflow.com/questions/26614728/why-is-0-less-than-number-min-value-in-javascript) StackOverflow에서 418 | 419 | - [**20.1.2.9** Number.MIN_VALUE](https://www.ecma-international.org/ecma-262/#sec-number.min_value) 420 | 421 | ## 함수는 함수가 아니다 422 | 423 | > ⚠️ V8 v5.5 또는 그 이하의 버전에서는 버그가 있을 수 있습니다.(Node.js <=7) ⚠️ 424 | 425 | 이것을 _undefined is not a function_ 모두가 알고 있지만 이건 어떨까요? 426 | 427 | ```js 428 | // Declare a class which extends null 429 | class Foo extends null {} 430 | // -> [Function: Foo] 431 | 432 | new Foo() instanceof null; 433 | // > TypeError: function is not a function 434 | // > at … … … 435 | ``` 436 | 437 | ### 💡 설명: 438 | 439 | 이것은 명세된 것의 일부가 아닙니다. 현재 수정된 버그 일 뿐이므로 향후 아무 문제 없을 것입니다. 440 | 441 | ## 배열 추가 442 | 443 | 두 개의 배열을 추가하려면 어떻게 해야 할까요? 444 | 445 | ```js 446 | [1, 2, 3] + [4, 5, 6]; // -> '1,2,34,5,6' 447 | ``` 448 | 449 | ### 💡 설명: 450 | 451 | 연결이 발생합니다.차근차근 다음을 봅시다: 452 | 453 | ```js 454 | [1, 2, 3] + 455 | [4, 5, 6][ 456 | // call toString() 457 | (1, 2, 3) 458 | ].toString() + 459 | [4, 5, 6].toString(); 460 | // concatenation 461 | "1,2,3" + "4,5,6"; 462 | // -> 463 | ("1,2,34,5,6"); 464 | ``` 465 | 466 | ## 배열의 후행 쉼표 467 | 468 | 4 개의 빈 배열을 만듭니다. 그럼에도 불구하고 후행 쉼표로 인해 세가지 , 요소가 있는 배열을 얻게 됩니다: 469 | 470 | ```js 471 | let a = [, , ,]; 472 | a.length; // -> 3 473 | a.toString(); // -> ',,' 474 | ``` 475 | 476 | ### 💡 설명: 477 | 478 | > **후행 쉼표** ("마지막 쉼표"라고도 함)는 JavaScript 에 새로운 요소, 매개 변수 또는 속성을 추가할 때 유용하게 사용할 수 있습니다. 만약 새 속성을 추가하려는 상황에서 이미 후행 쉼표를 사용하고 있는 경우 이전 마지막 줄을 수정하지 않고 새 줄을 추가할 수 있습니다. 이렇게 하면 버전 관리가 더 깔끔 해지고 코드 편집이 덜 번거로울 수 있습니다. 479 | > 480 | > — [후행 쉼표](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Trailing_commas) MDN에서 481 | 482 | ## 배열 평등은 몬스터 483 | 484 | 배열 평등은 아래에서 볼 수 있듯 JavaScript에서는 몬스터입니다: 485 | 486 | ```js 487 | [] == '' // -> true 488 | [] == 0 // -> true 489 | [''] == '' // -> true 490 | [0] == 0 // -> true 491 | [0] == '' // -> false 492 | [''] == 0 // -> true 493 | 494 | [null] == '' // true 495 | [null] == 0 // true 496 | [undefined] == '' // true 497 | [undefined] == 0 // true 498 | 499 | [[]] == 0 // true 500 | [[]] == '' // true 501 | 502 | [[[[[[]]]]]] == '' // true 503 | [[[[[[]]]]]] == 0 // true 504 | 505 | [[[[[[ null ]]]]]] == 0 // true 506 | [[[[[[ null ]]]]]] == '' // true 507 | 508 | [[[[[[ undefined ]]]]]] == 0 // true 509 | [[[[[[ undefined ]]]]]] == '' // true 510 | ``` 511 | 512 | ### 💡 설명: 513 | 514 | 아래의 예제를 주의 깊게 살펴 보아야 합니다! 이 동작은 [**7.2.13** 추상 동등 비교](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison)에 설명되어 있습니다. 515 | 516 | ## `undefined`과 `Number` 517 | 518 | `Number`생성자에 인수를 전달하지 않으면 `0` 값을 얻게 됩니다. 실제 인수가 없는 경우 `undefined`값이 형식 인수에 할당되기 때문에 인수가 없는 `Number`는 매개 변수 값으로 `undefined`를 사용합니다. 그러나 `undefined`를 통과하면 `NaN`을 얻을 수 있습니다. 519 | 520 | ```js 521 | Number(); // -> 0 522 | Number(undefined); // -> NaN 523 | ``` 524 | 525 | ### 💡 설명: 526 | 527 | 명세된 것에 따르면: 528 | 529 | 1. 함수의 호출로 인수가 전달되지 않은 경우 `n`은 `+0`이 됩니다. 530 | 2. 또는 let `n` be ? `ToNumber(value)`. 531 | 3. `undefined`의 경우 `ToNumber(undefined)`는 `NaN`으로 반환해야 합니다. 532 | 533 | 다음은 해당 부분입니다: 534 | 535 | - [**20.1.1** 숫자 생성자](https://www.ecma-international.org/ecma-262/#sec-number-constructor) 536 | - [**7.1.3** ToNumber(`argument`)](https://www.ecma-international.org/ecma-262/#sec-tonumber) 537 | 538 | ## `parseInt`은 나쁜 놈이다 539 | 540 | `parseInt`은 특이한 점으로 유명합니다: 541 | 542 | ```js 543 | parseInt("f*ck"); // -> NaN 544 | parseInt("f*ck", 16); // -> 15 545 | ``` 546 | 547 | **💡 설명:** 이는 `parseInt`알 수 없는 문자에 도달할 때까지 문자별로 계속 구문 분석을 하기 때문에 발생합니다. `'f*ck'`에서 `f`는 16 진수로 `15`입니다. 548 | 549 | `Infinity`정수로 파싱하는 것은… 550 | 551 | ```js 552 | // 553 | parseInt("Infinity", 10); // -> NaN 554 | // ... 555 | parseInt("Infinity", 18); // -> NaN... 556 | parseInt("Infinity", 19); // -> 18 557 | // ... 558 | parseInt("Infinity", 23); // -> 18... 559 | parseInt("Infinity", 24); // -> 151176378 560 | // ... 561 | parseInt("Infinity", 29); // -> 385849803 562 | parseInt("Infinity", 30); // -> 13693557269 563 | // ... 564 | parseInt("Infinity", 34); // -> 28872273981 565 | parseInt("Infinity", 35); // -> 1201203301724 566 | parseInt("Infinity", 36); // -> 1461559270678... 567 | parseInt("Infinity", 37); // -> NaN 568 | ``` 569 | 570 | `null`을 파싱하는 것에도 주의합시다: 571 | 572 | ```js 573 | parseInt(null, 24); // -> 23 574 | ``` 575 | 576 | **💡 설명:** 577 | 578 | > `null`을 문자열 `"null"`로 변환하려고 합니다. 0 부터 23 까지의 기수에 대해서 변환할 수 있는 숫자가 없으므로 NaN을 반환합니다. 24 에, `"n"`, 14 번째 문자가 숫자 체계에 추가됩니다. 31에, `"u"`, 21 번째 문자가 추가되고 전체 문자열을 디코딩 할 수 있게 되었습니다. 37에서 더 이상 생성할 수 있는 유효 숫자 집합이 없으며 `NaN`이 반환됩니다. 579 | > 580 | > — [“parseInt(null, 24) === 23… wait, what?”](https://stackoverflow.com/questions/6459758/parseintnull-24-23-wait-what) StackOverflow에서 581 | 582 | 8 진수에 대해서 잊지맙시다: 583 | 584 | ```js 585 | parseInt("06"); // 6 586 | parseInt("08"); // 8 if support ECMAScript 5 587 | parseInt("08"); // 0 if not support ECMAScript 5 588 | ``` 589 | 590 | **💡 설명:** 입력 문자열이 "0"으로 시작하는 경우, 기수는 8 (octal) 또는 10 (decimal)입니다. 정확히는 어떤 기수가 선택되는가는 구현에 따라 다릅니다. ECMAScript 5는 10 (decimal)진수를 사용하도록 지정하지만 모든 브라우저가 이것을 지원하지는 않습니다. 그러므로 `parseInt`을 사용할 때는 항상 기수를 지정합시다. 591 | 592 | `parseInt`항상 입력을 문자열로 변환: 593 | 594 | ```js 595 | parseInt({ toString: () => 2, valueOf: () => 1 }); // -> 2 596 | Number({ toString: () => 2, valueOf: () => 1 }); // -> 1 597 | ``` 598 | 599 | 부동 소수점값을 파싱하는 동안 주의하세요. 600 | 601 | ```js 602 | parseInt(0.000001); // -> 0 603 | parseInt(0.0000001); // -> 1 604 | parseInt(1 / 1999999); // -> 5 605 | ``` 606 | 607 | **💡 설명:** `ParseInt`은 문자열 인수를 취하고 지정된 기수의 정수를 반환합니다. 또한 `ParseInt`은 문자열 매개 변수에서 첫 번째가 아닌 숫자를 포함하여 모든 것을 제거합니다. `0.000001`은 문자열 "0.000001"`로 바뀌고`parseInt`은`0`으로 반환됩니다.`0.0000001`이 문자열로 변환되면`"1e-7"`로 되므로`parseInt`은`1`을 반환합니다.`1/1999999`은`5.00000250000125e-7`로 해석되고`parseInt`은`5`을 리턴합니다. 608 | 609 | ## `true`와 `false`를 이용한 수학 610 | 611 | 몇 가지 수학을 해봅시다: 612 | 613 | ```js 614 | true - 615 | true + 616 | // -> 2 617 | (true + true) * (true + true) - 618 | true; // -> 3 619 | ``` 620 | 621 | 흠… 🤔 622 | 623 | ### 💡 설명: 624 | 625 | `Number`생성자를 사용하여 값을 숫자로 강제 변환할 수 있습니다. `true`가 `1`로 강제되는 것은 분명합니다: 626 | 627 | ```js 628 | Number(true); // -> 1 629 | ``` 630 | 631 | 단항 더하기 연산자는 값을 숫자로 변환하려고 합니다. 이것은 정수와 소수의 문자열 표현일 뿐아니라 비문자열인 `true`, `false`와 `null`값도 변환할 수 있습니다. 특정 값을 파싱할 수 없는 경우 `NaN`으로 평가됩니다. 그것은 더 쉽게 `true`를 `1`로 강제할 수 있음을 의미합니다: 632 | 633 | ```js 634 | +true; // -> 1 635 | ``` 636 | 637 | 덧셈 또는 곱셈을 수행할 때 `ToNumber`메서드가 호출됩니다. 명세된 것에 따르면 아래의 메서드를 반환합니다: 638 | 639 | > 만약 `argument`이 **true**이면 **1**이 반환됩니다. 만약`argument`이 **false**이면 **+0**이 반환됩니다. 640 | 641 | 이 때문에 boolean 값을 일반 숫자로 추가하고 올바른 결과를 얻을 수 있습니다. 642 | 643 | 해당 부분: 644 | 645 | - [**12.5.6** 단항 `+` 연산자](https://www.ecma-international.org/ecma-262/#sec-unary-plus-operator) 646 | - [**12.8.3** 더하기 연산자(`+`)](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus) 647 | - [**7.1.3** ToNumber(`argument`)](https://www.ecma-international.org/ecma-262/#sec-tonumber) 648 | 649 | ## HTML 주석은 JavaScript에서도 유효하다 650 | 651 | 이것이 ` 1471 | ```js 1472 | (function() { 1473 | return 1474 | { 1475 | b: 10; 1476 | } 1477 | })(); // -> undefined 1478 | ``` 1479 | 1480 | 1481 | ### 💡 설명: 1482 | 1483 | `return`과 반환된 표현식은 같은 줄에 있어야 합니다: 1484 | 1485 | ```js 1486 | (function() { 1487 | return { 1488 | b: 10 1489 | }; 1490 | })(); // -> { b: 10 } 1491 | ``` 1492 | 1493 | 이는 대부분 줄 바꿈 뒤에 세미콜론을 자동으로 삽입하는 자동 세미콜론 삽입이라는 개념 때문입니다. 첫번째 예시에서 `return`문과 객체 리터럴 사이에 세미콜론이 삽입되어 있으므로 함수는 `undefined`를 반환하고 객체 리터럴은 평가되지 않습니다. 1494 | 1495 | - [**11.9.1** Rules of Automatic Semicolon Insertion](https://www.ecma-international.org/ecma-262/#sec-rules-of-automatic-semicolon-insertion) 1496 | - [**13.10** The `return` Statement](https://www.ecma-international.org/ecma-262/#sec-return-statement) 1497 | 1498 | ## 객체에 할당 연결 1499 | 1500 | ```js 1501 | var foo = { n: 1 }; 1502 | var bar = foo; 1503 | 1504 | foo.x = foo = { n: 2 }; 1505 | 1506 | foo.x; // -> undefined 1507 | foo; // -> {n: 2} 1508 | bar; // -> {n: 1, x: {n: 2}} 1509 | ``` 1510 | 1511 | 오른쪽에서 왼쪽으로, `{n: 2}`이 foo에 할당되고, 이 할당의 결과`{n: 2}`는 foo.x 에 할당되어 있고, bar는 foo를 할당하고 있기 때문에 bar는 `{n: 1, x: {n: 2}}`입니다. 그런데 bar.x가 아닌 반면에 foo.x는 왜 정의되지 않은 것일까요? 1512 | 1513 | ### 💡 설명: 1514 | 1515 | Foo와 bar는 같은 객체 `{n: 1}`를 참조하고 있고 lvalues는 할당되기 전에 결정됩니다. `foo = {n: 2}`은 새로운 객체를 생성하고 있으므로 foo는 새로운 객체를 참조하도록 업데이트됩니다. 트릭은 `foo.x = ...`의 foo 에 있습니다. lvalue 값은 사전에 확인되었고 여전히 이전 `foo = {n:1}` 객체를 참조하고 x 값을 추가하여 업데이트합니다. 체인 할당 후에도 bar는 여전히 이전의 foo 객체를 참조하지만 foo는 x가 존재하지 않는 새로운 `{n: 2}`객체를 참조합니다. 1516 | 1517 | 다음과 동일합니다: 1518 | 1519 | ```js 1520 | var foo = { n: 1 }; 1521 | var bar = foo; 1522 | 1523 | foo = { n: 2 }; // -> {n: 2} 1524 | bar.x = foo; // -> {n: 1, x: {n: 2}} 1525 | // bar.x point to the address of the new foo object 1526 | // it's not equivalent to: bar.x = {n: 2} 1527 | ``` 1528 | 1529 | ## 배열을 사용한 객체 속성 접근 s 1530 | 1531 | ```js 1532 | var obj = { property: 1 }; 1533 | var array = ["property"]; 1534 | 1535 | obj[array]; // -> 1 1536 | ``` 1537 | 1538 | 다차원 배열의 수도코드는 무엇입니까? 1539 | 1540 | ```js 1541 | var map = {}; 1542 | var x = 1; 1543 | var y = 2; 1544 | var z = 3; 1545 | 1546 | map[[x, y, z]] = true; 1547 | map[[x + 10, y, z]] = true; 1548 | 1549 | map["1,2,3"]; // -> true 1550 | map["11,2,3"]; // -> true 1551 | ``` 1552 | 1553 | ### 💡 설명: 1554 | 1555 | 대괄호 연산자 `[]`는 `toString`을 사용하여 전달된 식을 변환합니다. 단일 요소 배열을 문자열으로 변환하는 것은 포함된 요소를 문자열로 변환하는 것과 유사합니다: 1556 | 1557 | ```js 1558 | ["property"].toString(); // -> 'property' 1559 | ``` 1560 | 1561 | ## Null 및 관계 연산자 1562 | 1563 | ```js 1564 | null > 0; // false 1565 | null == 0; // false 1566 | 1567 | null >= 0; // true 1568 | ``` 1569 | 1570 | ### 💡 설명: 1571 | 1572 | 긴 얘기를 짧게 하자면, 만약 `null`이 `0` 보다 작으면 `false`이고 `null >= 0`은 `true`입니다. 여기에서 이에 대한 자세한 설명을 읽으십시오 [여기](https://blog.campvanilla.com/javascript-the-curious-case-of-null-0-7b131644e274). 1573 | 1574 | ## `Number.toFixed()` 다른 숫자 표시 1575 | 1576 | `Number.toFixed()`는 다른 브라우저에서 약간 이상하게 작동할 수 있습니다. 아래 예를 확인하세요: 1577 | 1578 | ```js 1579 | (0.7875).toFixed(3); 1580 | // Firefox: -> 0.787 1581 | // Chrome: -> 0.787 1582 | // IE11: -> 0.788 1583 | (0.7876).toFixed(3); 1584 | // Firefox: -> 0.788 1585 | // Chrome: -> 0.788 1586 | // IE11: -> 0.788 1587 | ``` 1588 | 1589 | ### 💡 설명: 1590 | 1591 | 본능적으로 IE11은 올바르고 Firefox/Chrome이 잘못되었다고 생각할 수 있지만 사실은 Firefox/Chrome이 더 직접적으로 숫자의 표준(IEEE-754 Floating Point)을 준수하고 있는 반면 IE11는 더 명확한 결과를 제공하기 위한 노력으로 그것들을 미세하게 거역하고 있습니다. 1592 | 1593 | 몇 가지 간단한 테스트를 통해 이 문제가 발생하는 이유를 확인할 수 있습니다: 1594 | 1595 | ```js 1596 | // Confirm the odd result of rounding a 5 down 1597 | (0.7875).toFixed(3); // -> 0.787 1598 | // It looks like it's just a 5 when you expand to the 1599 | // limits of 64-bit (double-precision) float accuracy 1600 | (0.7875).toFixed(14); // -> 0.78750000000000 1601 | // But what if you go beyond the limit? 1602 | (0.7875).toFixed(20); // -> 0.78749999999999997780 1603 | ``` 1604 | 1605 | 부동 소수점 번호는 내부적으로 10진수 리스트로 저장되는 것이 아니라 대게 toString과 유사한 호출에 의해 반올림되지만 실제로 내부적으로는 매우 복잡한 방법론을 통해 저장됩니다. 1606 | 1607 | 이 경우 끝에 있는 "5"는 실제로 진짜 5 보다 매우 작은 부분입니다.합리적인 길이로 반올림하면 5...으로 렌더링되지만 실제로는 내부적으로 5는 아닙니다. 1608 | 1609 | 그러나 IE11은 하드웨어 한계에서 문제를 줄이기 위해 값을 강제로 반올림하는 것처럼 보이기 때문에 toFixed(20)의 사례에서도 끝에 0만 추가한 값을 입력 보고 할 것입니다. 1610 | 1611 | `toFixed`에 대한 ECMA-262 정의의 `NOTE 2`를 참고하세요. 1612 | 1613 | - [**20.1.3.3** Number.prototype.toFixed (`fractionDigits`)](https://www.ecma-international.org/ecma-262//#sec-number.prototype.tofixed) 1614 | 1615 | ## `Math.max()` 이하 `Math.min()` 1616 | 1617 | ```js 1618 | Math.min(1, 4, 7, 2); // -> 1 1619 | Math.max(1, 4, 7, 2); // -> 7 1620 | Math.min(); // -> Infinity 1621 | Math.max(); // -> -Infinity 1622 | Math.min() > Math.max(); // -> true 1623 | ``` 1624 | 1625 | ### 💡 설명: 1626 | 1627 | - [Why is Math.max() less than Math.min()?](https://charlieharvey.org.uk/page/why_math_max_is_less_than_math_min) by Charlie Harvey 1628 | 1629 | ## `null`과 `0` 비교 1630 | 1631 | 다음 표현들은 모순을 의미한것 같습니다: 1632 | 1633 | ```js 1634 | null == 0; // -> false 1635 | null > 0; // -> false 1636 | null >= 0; // -> true 1637 | ``` 1638 | 1639 | 만약 `null >= 0`이 실제로 `true`이면 어떻게 `null`이 `0`과 같지도 않고 크지도 않을까요? (이는 보다 적은 경우에도 동일하게 작동합니다.) 1640 | 1641 | ### 💡 설명: 1642 | 1643 | 이 세가지 식이 평가되는 방식은 모두 다르며 예기치 않은 동작들을 생성합니다. 1644 | 1645 | 첫째, 추상 평등 비교 `null == 0`입니다. 일반적으로 이 연산자가 양쪽 값을 제대로 비교할 수없으면 둘 다 숫자로 변환한 후 숫자를 비교합니다. 그러면 다음 동작을 예상할 수 있습니다: 1646 | 1647 | ```js 1648 | // This is not what happens 1649 | (null == 0 + null) == +0; 1650 | 0 == 0; 1651 | true; 1652 | ``` 1653 | 1654 | 그러나 spec을 자세히 읽어보면 숫자 변환은 `null`이나 `undefined`의 한 면에서는 일어나지 않습니다. 그러므로 등호 한쪽에 `null`이 있으면 다른 한쪽에 `null` 또는 `undefined`가 있어야 `true`를 리턴합니다. 이 경우 그렇지 않기 때문에`false`을 리턴합니다. 1655 | 1656 | 다음은 관계 비교 `null > 0`입나다. 여기서 알고리즘은 추상 평등 연산자와 달리 `null`을 숫자로 변환합니다. 따라서 다음과 같은 동작이 발생합니다: 1657 | 1658 | ```js 1659 | null > 0 + null = +0; 1660 | 0 > 0; 1661 | false; 1662 | ``` 1663 | 1664 | 마지막으로 관계 비교 `null >= 0`입니다. 이 표현이 `null > 0 || null == 0`의 결과라고 주장할 수 있는데, 만약 그렇다면, 위의 결과는 이 역시 `false`라는 것을 의미할 것입니다. 그러나 사실 `>=`연산자는 매우 다른 방식으로 작동하는데, 이는 기본적으로 `<`연산자와 반대되는 방식입니다. 위보다 큰 연산자를 사용한 예도 연산자보다 작기 때문에 이 식은 실제로 다음과 같이 평가됩니다. 1665 | 1666 | ```js 1667 | null >= 0; 1668 | !(null < 0); 1669 | !(+null < +0); 1670 | !(0 < 0); 1671 | !false; 1672 | true; 1673 | ``` 1674 | 1675 | - [**7.2.12** Abstract Relational Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-relational-comparison) 1676 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 1677 | 1678 | ## 동일한 변수 재선언 1679 | 1680 | JavaScript에서는 변수를 다시 선언할 수 있습니다: 1681 | 1682 | ```js 1683 | a; 1684 | a; 1685 | // This is also valid 1686 | a, a; 1687 | ``` 1688 | 1689 | strict 모드에서도 작동합니다: 1690 | 1691 | ```js 1692 | var a, a, a; 1693 | var a; 1694 | var a; 1695 | ``` 1696 | 1697 | ### 💡 설명: 1698 | 1699 | 모든 정의가 하나의 정의로 병합됩니다. 1700 | 1701 | - [**13.3.2** Variable Statement](https://www.ecma-international.org/ecma-262/#sec-variable-statement) 1702 | 1703 | ## 디폴트 동작 Array.prototype.sort() 1704 | 1705 | 숫자 배열을 정렬해야 한다고 상상해보세요. 1706 | 1707 | ``` 1708 | [ 10, 1, 3 ].sort() // -> [ 1, 10, 3 ] 1709 | ``` 1710 | 1711 | ### 💡 설명: 1712 | 1713 | 기본 정렬 순서는 요소들을 문자열로 변환한 후 UTF-16 코드 단위 값의 시퀀스를 비교할 때 작성됩니다. 1714 | 1715 | - [**22.1.3.25** Array.prototype.sort ( comparefn )](https://www.ecma-international.org/ecma-262/#sec-array.prototype.sort) 1716 | 1717 | ### 힌트 1718 | 1719 | 문자열 이외의 정렬을 시도하면 `comparefn`을 통과시키세요. 1720 | 1721 | ``` 1722 | [ 10, 1, 3 ].sort((a, b) => a - b) // -> [ 1, 3, 10 ] 1723 | ``` 1724 | 1725 | ## resolve()은 Promise instance를 반환하지 않는다 1726 | 1727 | ```javascript 1728 | const theObject = { 1729 | a: 7 1730 | }; 1731 | const thePromise = new Promise((resolve, reject) => { 1732 | resolve(theObject); 1733 | }); // -> Promise instance object 1734 | 1735 | thePromise.then(value => { 1736 | console.log(value === theObject); // -> true 1737 | console.log(value); // -> { a: 7 } 1738 | }); 1739 | ``` 1740 | 1741 | `value`는 `thePromise` 정확하게 말하면 `theObject`에서 해결되는 것 입니다. 1742 | 1743 | `resolve`함수에 또 다른 `Promise`를 넣는 것은 어떨까요? 1744 | 1745 | ```javascript 1746 | const theObject = new Promise((resolve, reject) => { 1747 | resolve(7); 1748 | }); // -> Promise instance object 1749 | const thePromise = new Promise((resolve, reject) => { 1750 | resolve(theObject); 1751 | }); // -> Promise instance object 1752 | 1753 | thePromise.then(value => { 1754 | console.log(value === theObject); // -> false 1755 | console.log(value); // -> 7 1756 | }); 1757 | ``` 1758 | 1759 | ### 💡 설명: 1760 | 1761 | > 이 함수는 promise 같은 객체의 중첩된 레이어(예시: 무언가로 해결되는 promise으로 해결되는 promise)를 단일 레이어로 평탄화합니다. 1762 | 1763 | – [Promise.resolve() on MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve) 1764 | 1765 | 명세서는 [ECMAScript 25.6.1.3.2 Promise Resolve Functions](https://tc39.es/ecma262/#sec-promise-resolve-functions)입니다. 하지만 그것은 인간 친화적이지 않습니다. 1766 | 1767 | # 📚 기타 resources 1768 | 1769 | - [wtfjs.com](http://wtfjs.com/) — a collection of those very special irregularities, inconsistencies and just plain painfully unintuitive moments for the language of the web. 1770 | - [Wat](https://www.destroyallsoftware.com/talks/wat) — A lightning talk by Gary Bernhardt from CodeMash 2012 1771 | - [What the... JavaScript?](https://www.youtube.com/watch?v=2pL28CcEijU) — Kyle Simpsons talk for Forward 2 attempts to “pull out the crazy” from JavaScript. He wants to help you produce cleaner, more elegant, more readable code, then inspire people to contribute to the open source community. 1772 | 1773 | # 🎓 License 1774 | 1775 | [![CC 4.0][license-image]][license-url] 1776 | 1777 | © [Denys Dovhan](http://denysdovhan.com) 1778 | 1779 | [license-url]: http://www.wtfpl.net 1780 | [license-image]: https://img.shields.io/badge/License-WTFPL%202.0-lightgrey.svg?style=flat-square 1781 | [npm-url]: https://npmjs.org/package/wtfjs 1782 | [npm-image]: https://img.shields.io/npm/v/wtfjs.svg?style=flat-square 1783 | -------------------------------------------------------------------------------- /README-pl-pl.md: -------------------------------------------------------------------------------- 1 | # What the f\*ck JavaScript? 2 | 3 | [![WTFPL 2.0][license-image]][license-url] 4 | [![NPM version][npm-image]][npm-url] 5 | 6 | > Lista zabawnych i podchwytliwych przykładów JavaScript 7 | 8 | JavaScript to świetny język. Ma prostą składnię, duży ekosystem i, co najważniejsze, wspaniałą społeczność. 9 | 10 | Jednocześnie wszyscy wiemy, że JavaScript jest dość zabawnym językiem z podchwytliwymi częściami. Niektóre z nich mogą szybko zamienić naszą codzienną pracę w piekło, a niektóre mogą rozśmieszyć nas na głos. 11 | 12 | Oryginalny pomysł na WTFJS należy do [Brian Leroux](https://twitter.com/brianleroux). Ta lista jest bardzo zainspirowana jego przemową 13 | [**“WTFJS”** na dotJS 2012](https://www.youtube.com/watch?v=et8xNAc2ic8): 14 | 15 | [![dotJS 2012 - Brian Leroux - WTFJS](https://img.youtube.com/vi/et8xNAc2ic8/0.jpg)](https://www.youtube.com/watch?v=et8xNAc2ic8) 16 | 17 | # Node Packaged Manuscript 18 | 19 | Możesz zainstalować ten podręcznik za pomocą `npm`. Po prostu uruchom: 20 | 21 | ``` 22 | $ npm install -g wtfjs 23 | ``` 24 | 25 | Powinieneś być teraz w stanie uruchomić `wtfjs` w linii poleceń. Spowoduje to otwarcie instrukcji w wybranym `$PAGER`. W przeciwnym razie możesz kontynuować czytanie tutaj. 26 | 27 | Źródło jest dostępne tutaj: 28 | 29 | # Tłumaczenia 30 | 31 | Obecnie są następujące tłumaczenia **wtfjs**: 32 | 33 | - [中文版](./README-zh-cn.md) 34 | - [Français](./README-fr-fr.md) 35 | - [Polski](./README-pl-pl.md) 36 | 37 | [**Poproś o kolejne tłumaczenie**][tr-request] 38 | 39 | [tr-request]: https://github.com/denysdovhan/wtfjs/issues/new?title=Translation%20Request:%20%5BPlease%20enter%20language%20here%5D&body=I%20am%20able%20to%20translate%20this%20language%20%5Byes/no%5D 40 | 41 | 42 | 43 | 44 | # Table of Contents 45 | 46 | - [💪🏻 Motywacja](#-motywacja) 47 | - [✍🏻 Notacja](#-notacja) 48 | - [👀 Przykłady](#-przyk%C5%82ady) 49 | - [`[]` jest równe `![]`](#-jest-r%C3%B3wne-) 50 | - [`true` nie jest równe `![]`, ale też nie równe `[]`](#true-nie-jest-r%C3%B3wne--ale-te%C5%BC-nie-r%C3%B3wne-) 51 | - [prawda to fałsz](#prawda-to-fa%C5%82sz) 52 | - [baNaNa](#banana) 53 | - [`NaN` nie jest `NaN`](#nan-nie-jest-nan) 54 | - [To jest fail](#to-jest-fail) 55 | - [`[]` jest prawdziwe, ale nie `true`](#-jest-prawdziwe-ale-nie-true) 56 | - [`null` jest fałszywe, ale nie `false`](#null-jest-fa%C5%82szywe-ale-nie-false) 57 | - [`document.all` jest obiektem, ale jest undefined](#documentall-jest-obiektem-ale-jest-undefined) 58 | - [Minimalna wartość jest większa od zera](#minimalna-warto%C5%9B%C4%87-jest-wi%C4%99ksza-od-zera) 59 | - [funkcja nie jest funkcją](#funkcja-nie-jest-funkcj%C4%85) 60 | - [Dodawanie tablic](#dodawanie-tablic) 61 | - [Trailing commas in array](#trailing-commas-in-array) 62 | - [Równość tablic to potwór](#r%C3%B3wno%C5%9B%C4%87-tablic-to-potw%C3%B3r) 63 | - [`undefined` oraz `Number`](#undefined-oraz-number) 64 | - [`parseInt` jest złym gościem](#parseint-jest-z%C5%82ym-go%C5%9Bciem) 65 | - [Matematyka z `true` i `false`](#matematyka-z-true-i-false) 66 | - [Komentarze HTML są obowiązujące w JavaScript](#komentarze-html-s%C4%85-obowi%C4%85zuj%C4%85ce-w-javascript) 67 | - [`NaN` is ~~not~~ a number](#nan-is-not-a-number) 68 | - [`[]` i `null` są obiektami](#-i-null-s%C4%85-obiektami) 69 | - [Magicznie rosnące liczby](#magicznie-rosn%C4%85ce-liczby) 70 | - [Precyzja `0.1 + 0.2`](#precyzja-01--02) 71 | - [Patching numbers](#patching-numbers) 72 | - [Porównanie trzech liczb](#por%C3%B3wnanie-trzech-liczb) 73 | - [Zabawna matematyka](#zabawna-matematyka) 74 | - [Dodanie RegExps](#dodanie-regexps) 75 | - [Stringi nie są instancjami `String`](#stringi-nie-s%C4%85-instancjami-string) 76 | - [Wywoływanie funkcji za pomocą backticksa](#wywo%C5%82ywanie-funkcji-za-pomoc%C4%85-backticksa) 77 | - [Call call call](#call-call-call) 78 | - [Właściwość `constructor`](#w%C5%82a%C5%9Bciwo%C5%9B%C4%87-constructor) 79 | - [Obiekt jako klucz właściwości obiektu](#obiekt-jako-klucz-w%C5%82a%C5%9Bciwo%C5%9Bci-obiektu) 80 | - [Dostęp do prototypów za pomocą `__proto__`](#dost%C4%99p-do-prototyp%C3%B3w-za-pomoc%C4%85-__proto__) 81 | - [`` `${{Object}}` ``](#-object-) 82 | - [Destrukturyzacja z wartościami domyślnymi](#destrukturyzacja-z-warto%C5%9Bciami-domy%C5%9Blnymi) 83 | - [Dots and spreading](#dots-and-spreading) 84 | - [Etykiety](#etykiety) 85 | - [Zagnieżdżone etykiety](#zagnie%C5%BCd%C5%BCone-etykiety) 86 | - [Podstępny `try..catch`](#podst%C4%99pny-trycatch) 87 | - [Czy to wielokrotne dziedziczenie?](#czy-to-wielokrotne-dziedziczenie) 88 | - [A generator which yields itself](#a-generator-which-yields-itself) 89 | - [Klasa klasy](#klasa-klasy) 90 | - [Non-coercible objects](#non-coercible-objects) 91 | - [Podstępne funkcje strzałkowe](#podst%C4%99pne-funkcje-strza%C5%82kowe) 92 | - [Funkcje strzałkowe nie mogą być konstruktorami](#funkcje-strza%C5%82kowe-nie-mog%C4%85-by%C4%87-konstruktorami) 93 | - [`arguments` i funkcje strzałkowe](#arguments-i-funkcje-strza%C5%82kowe) 94 | - [Podstępny return](#podst%C4%99pny-return) 95 | - [Chaining assignments on object](#chaining-assignments-on-object) 96 | - [Dostęp do właściwości obiektu za pomocą tablic](#dost%C4%99p-do-w%C5%82a%C5%9Bciwo%C5%9Bci-obiektu-za-pomoc%C4%85-tablic) 97 | - [Null and Relational Operators](#null-and-relational-operators) 98 | - [`Number.toFixed()` display different numbers](#numbertofixed-display-different-numbers) 99 | - [`Math.max()` mniej niż `Math.min()`](#mathmax-mniej-ni%C5%BC-mathmin) 100 | - [Comparing `null` to `0`](#comparing-null-to-0) 101 | - [Redeklaracja tej samej zmiennej](#redeklaracja-tej-samej-zmiennej) 102 | - [Domyślne zachowanie Array.prototype.sort()](#domy%C5%9Blne-zachowanie-arrayprototypesort) 103 | - [📚 Inne materiały](#-inne-materia%C5%82y) 104 | - [🎓 Licencja](#-licencja) 105 | 106 | 107 | 108 | 109 | # 💪🏻 Motywacja 110 | 111 | > Dla zabawy 112 | > 113 | > — _[**“Just for Fun: The Story of an Accidental Revolutionary”**](https://en.wikipedia.org/wiki/Just_for_Fun), Linus Torvalds_ 114 | 115 | Głównym celem tej listy jest zebranie szalonych przykładów i wyjaśnienie, w jaki sposób działają, jeśli to możliwe. Tylko dlatego, że fajnie jest nauczyć się czegoś, czego wcześniej nie znaliśmy. 116 | 117 | Jeśli jesteś początkujący, możesz skorzystać z tych notatek, aby głębiej zagłębić się w JavaScript. Mam nadzieję, że te notatki zmotywują cię do spędzenia więcej czasu na czytaniu specyfikacji. 118 | 119 | Jeśli jesteś profesjonalnym programistą, możesz rozważyć te przykłady, jako świetne źródło informacji o wszystkich dziwactwach i nieoczekiwanych krawędziach naszego ukochanego JavaScript. 120 | 121 | W każdym razie po prostu przeczytaj to. Prawdopodobnie znajdziesz coś nowego. 122 | 123 | # ✍🏻 Notacja 124 | 125 | **`// ->`** służy do wyświetlenia wyniku wyrażenia. Na przykład: 126 | 127 | ```js 128 | 1 + 1; // -> 2 129 | ``` 130 | 131 | **`// >`** oznacza wynik `console.log` lub wyświetlenie innego wyniku. Na przykład: 132 | 133 | ```js 134 | console.log("hello, world!"); // > hello, world! 135 | ``` 136 | 137 | **`//`** jest tylko komentarzem używanym w celu wyjaśnienia. Przykład: 138 | 139 | ```js 140 | // Assigning a function to foo constant 141 | const foo = function() {}; 142 | ``` 143 | 144 | # 👀 Przykłady 145 | 146 | ## `[]` jest równe `![]` 147 | 148 | Tablica jest równa zanegowanej tablicy: 149 | 150 | ```js 151 | [] == ![]; // -> true 152 | ``` 153 | 154 | ### 💡 Wytłumaczenie: 155 | 156 | Abstrakcyjny operator równości przekształca obie strony na liczby, aby je porównać, a obie strony stają się liczbą `0` z różnych powodów. Tablice są prawdziwe, więc po prawej stronie przeciwieństwem prawdziwej wartości jest `false`, który jest następnie wymuszany na `0`. Po lewej jednak pusta tablica jest wymuszana na liczbę, nie będąc najpierw wartością logiczną, a puste tablice są wymuszane na `0`, mimo że są prawdziwe. 157 | 158 | Oto jak to wyrażenie upraszcza: 159 | 160 | ```js 161 | +[] == +![]; 162 | 0 == +false; 163 | 0 == 0; 164 | true; 165 | ``` 166 | 167 | Zobacz też [`[]` jest prawdziwe, ale nie `true`](##-jest-prawdziwe-ale-nie-true). 168 | 169 | - [**12.5.9** Logical NOT Operator (`!`)](https://www.ecma-international.org/ecma-262/#sec-logical-not-operator) 170 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 171 | 172 | ## `true` nie jest równe `![]`, ale też nie równe `[]` 173 | 174 | Tablica nie jest równa `true`, ale zanegowana tablica też nie jest równa `true`; 175 | Tablica jest równa `false`, zanegowana tablica również jest równa `false`: 176 | 177 | ```js 178 | true == []; // -> false 179 | true == ![]; // -> false 180 | 181 | false == []; // -> true 182 | false == ![]; // -> true 183 | ``` 184 | 185 | ### 💡 Wytłumaczenie: 186 | 187 | ```js 188 | true == []; // -> false 189 | true == ![]; // -> false 190 | 191 | // According to the specification 192 | 193 | true == []; // -> false 194 | 195 | toNumber(true); // -> 1 196 | toNumber([]); // -> 0 197 | 198 | 1 == 0; // -> false 199 | 200 | true == ![]; // -> false 201 | 202 | ![]; // -> false 203 | 204 | true == false; // -> false 205 | ``` 206 | 207 | ```js 208 | false == []; // -> true 209 | false == ![]; // -> true 210 | 211 | // According to the specification 212 | 213 | false == []; // -> true 214 | 215 | toNumber(false); // -> 0 216 | toNumber([]); // -> 0 217 | 218 | 0 == 0; // -> true 219 | 220 | false == ![]; // -> true 221 | 222 | ![]; // -> false 223 | 224 | false == false; // -> true 225 | ``` 226 | 227 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 228 | 229 | ## prawda to fałsz 230 | 231 | ```js 232 | !!"false" == !!"true"; // -> true 233 | !!"false" === !!"true"; // -> true 234 | ``` 235 | 236 | ### 💡 Wytłumaczenie: 237 | 238 | Rozważ to krok po kroku: 239 | 240 | ```js 241 | // true is 'truthy' and represented by value 1 (number), 'true' in string form is NaN. 242 | true == "true"; // -> false 243 | false == "false"; // -> false 244 | 245 | // 'false' is not the empty string, so it's a truthy value 246 | !!"false"; // -> true 247 | !!"true"; // -> true 248 | ``` 249 | 250 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 251 | 252 | ## baNaNa 253 | 254 | ```js 255 | "b" + "a" + +"a" + "a"; // -> 'baNaNa' 256 | ``` 257 | 258 | To stary żart w JavaScript, ale odnowiony. Oto oryginał: 259 | 260 | ```js 261 | "foo" + +"bar"; // -> 'fooNaN' 262 | ``` 263 | 264 | ### 💡 Wytłumaczenie: 265 | 266 | Wyrażenie jest oceniane jako `'foo' + (+'bar')`, które konwertuje `'bar'` nie na liczbę. 267 | 268 | - [**12.8.3** The Addition Operator (`+`)](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus) 269 | - [12.5.6 Unary + Operator](https://www.ecma-international.org/ecma-262/#sec-unary-plus-operator) 270 | 271 | ## `NaN` nie jest `NaN` 272 | 273 | ```js 274 | NaN === NaN; // -> false 275 | ``` 276 | 277 | ### 💡 Wytłumaczenie: 278 | 279 | Specyfikacja ściśle określa logikę tego zachowania: 280 | 281 | > 1. Jeśli `Type(x)` jest różny od `Type(y)`, zwraca **false**. 282 | > 2. Jeśli `Type(x)` jest Number, wtedy 283 | > 1. Jeśli `x` jest **NaN**, zwraca **false**. 284 | > 2. Jeśli `y` jest **NaN**, zwraca **false**. 285 | > 3. … … … 286 | > 287 | > — [**7.2.14** Strict Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-strict-equality-comparison) 288 | 289 | Zgodnie z definicją `NaN` z IEEE: 290 | 291 | > Możliwe są cztery wzajemnie wykluczające się relacje: mniejszy, równy, większy niż i nieuporządkowany. Ostatni przypadek powstaje, gdy co najmniej jednym operandem jest NaN. Każdy NaN porównuje się nieuporządkowany ze wszystkim, w tym samym sobą. 292 | > 293 | > — [“What is the rationale for all comparisons returning false for IEEE754 NaN values?”](https://stackoverflow.com/questions/1565164/1573715#1573715) at StackOverflow 294 | 295 | ## To jest fail 296 | 297 | Nie uwierzyłbyś, ale … 298 | 299 | ```js 300 | (![] + [])[+[]] + 301 | (![] + [])[+!+[]] + 302 | ([![]] + [][[]])[+!+[] + [+[]]] + 303 | (![] + [])[!+[] + !+[]]; 304 | // -> 'fail' 305 | ``` 306 | 307 | ### 💡 Wytłumaczenie: 308 | 309 | Po rozbiciu masy symboli na części zauważamy, że często występuje następujący wzór: 310 | 311 | ```js 312 | ![] + []; // -> 'false' 313 | ![]; // -> false 314 | ``` 315 | 316 | Więc próbujemy dodać `[]` do `false`. Ale z powodu wielu wywołań funkcji wewnętrznych (`binary + Operator` -> `ToPrimitive` -> `[[DefaultValue]]`) w końcu konwertujemy odpowiedni operand na ciąg: 317 | 318 | ```js 319 | ![] + [].toString(); // 'false' 320 | ``` 321 | 322 | Myśląc o łańcuchu jako tablicy, możemy uzyskać dostęp do jego pierwszego znaku za pośrednictwem `[0]`: 323 | 324 | ```js 325 | "false"[0]; // -> 'f' 326 | ``` 327 | 328 | Reszta jest oczywista, ale `i` jest podchwytliwe. `i` w `fail` jest pobierany przez generowanie ciągu `'falseundefined'` i łapanie elementu na indeks `['10']` 329 | 330 | ## `[]` jest prawdziwe, ale nie `true` 331 | 332 | Tablica jest prawdziwą wartością, jednak nie jest równa `true`. 333 | 334 | ```js 335 | !![] // -> true 336 | [] == true // -> false 337 | ``` 338 | 339 | ### 💡 Wytłumaczenie: 340 | 341 | Oto linki do odpowiednich sekcji specyfikacji ECMA-262: 342 | 343 | - [**12.5.9** Logical NOT Operator (`!`)](https://www.ecma-international.org/ecma-262/#sec-logical-not-operator) 344 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 345 | 346 | ## `null` jest fałszywe, ale nie `false` 347 | 348 | Pomimo faktu, że`null` jest wartością fałszywą, nie jest równa `false`. 349 | 350 | ```js 351 | !!null; // -> false 352 | null == false; // -> false 353 | ``` 354 | 355 | W tym samym czasie inne wartości fałszywe, takie jak `0` lub `''` są równe do `false`. 356 | 357 | ```js 358 | 0 == false; // -> true 359 | "" == false; // -> true 360 | ``` 361 | 362 | ### 💡 Wytłumaczenie: 363 | 364 | Wytłumaczenie jest takie samo jak w poprzednim przykładzie. Oto odpowiedni link: 365 | 366 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 367 | 368 | ## `document.all` jest obiektem, ale jest undefined 369 | 370 | > ⚠️ Jest to część interfejsu API przeglądarki i nie będzie działać w środowisku Node.js ⚠️ 371 | 372 | Pomimo faktu, że `document.all` jest obiektem tablicowym i daje dostęp do węzłów DOM na stronie, odpowiada na funkcję `typeof` jako `undefined`. 373 | 374 | ```js 375 | document.all instanceof Object; // -> true 376 | typeof document.all; // -> 'undefined' 377 | ``` 378 | 379 | W tym samym czasie, `document.all` nie jest równe `undefined`. 380 | 381 | ```js 382 | document.all === undefined; // -> false 383 | document.all === null; // -> false 384 | ``` 385 | 386 | Ale w tym samym czasie: 387 | 388 | ```js 389 | document.all == null; // -> true 390 | ``` 391 | 392 | ### 💡 Wytłumaczenie: 393 | 394 | > `document.all` kiedyś był sposobem na dostęp do elementów DOM, w szczególności w starszych wersjach IE. Chociaż nigdy nie był standardem, był szeroko stosowany w starszym kodzie JS. Kiedy standard rozwijał się z nowymi interfejsami API (takimi jak `document.getElementById`), to wywołanie interfejsu API stało się przestarzałe i komitet standardowy musiał zdecydować, co z nim zrobić. Ze względu na szerokie zastosowanie postanowili zachować interfejs API, ale wprowadzili umyślne naruszenie specyfikacji JavaScript. 395 | > Powód, dla którego reaguje na `false` podczas korzystania ze [Strict Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-strict-equality-comparison) z `undefined` gdy `true` podczas korzystania z [Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) wynika z umyślnego naruszenia specyfikacji, która wyraźnie na to pozwala. 396 | > 397 | > — [“Obsolete features - document.all”](https://html.spec.whatwg.org/multipage/obsolete.html#dom-document-all) na WhatWG - HTML spec 398 | > — [“Chapter 4 - ToBoolean - Falsy values”](https://github.com/getify/You-Dont-Know-JS/blob/0d79079b61dad953bbfde817a5893a49f7e889fb/types%20%26%20grammar/ch4.md#falsy-objects) na YDKJS - Types & Grammar 399 | 400 | ## Minimalna wartość jest większa od zera 401 | 402 | `Number.MIN_VALUE` jest najmniejszą liczbą, która jest większa od zera: 403 | 404 | ```js 405 | Number.MIN_VALUE > 0; // -> true 406 | ``` 407 | 408 | ### 💡 Wytłumaczenie: 409 | 410 | > `Number.MIN_VALUE` jest `5e-324`, np. najmniejsza liczba dodatnia, która może być reprezentowana z precyzją zmiennoprzecinkową, tj. jest tak blisko, jak można dojść do zera. Określa najlepszą rozdzielczość, jaką mogą zaoferować floaty. 411 | > 412 | > Teraz ogólna najmniejsza wartość to `Number.NEGATIVE_INFINITY` chociaż nie jest to tak naprawdę liczbowe w ścisłym tego słowa znaczeniu. 413 | > 414 | > — [“Why is `0` less than `Number.MIN_VALUE` in JavaScript?”](https://stackoverflow.com/questions/26614728/why-is-0-less-than-number-min-value-in-javascript) na StackOverflow 415 | 416 | - [**20.1.2.9** Number.MIN_VALUE](https://www.ecma-international.org/ecma-262/#sec-number.min_value) 417 | 418 | ## funkcja nie jest funkcją 419 | 420 | > ⚠️ Bug obecny w wersji V8 5.5 lub nowszej (Node.js <=7) ⚠️ 421 | 422 | Wszyscy wiecie o irytującym _niezdefiniowany nie jest funkcją_, ale co z tym? 423 | 424 | ```js 425 | // Declare a class which extends null 426 | class Foo extends null {} 427 | // -> [Function: Foo] 428 | 429 | new Foo() instanceof null; 430 | // > TypeError: function is not a function 431 | // > at … … … 432 | ``` 433 | 434 | ### 💡 Wytłumaczenie: 435 | 436 | To nie jest część specyfikacji. To tylko błąd, który został już naprawiony, więc nie powinno być z tym problemu w przyszłości. 437 | 438 | ## Dodawanie tablic 439 | 440 | Co jeśli spróbujesz dodać dwie tablice? 441 | 442 | ```js 443 | [1, 2, 3] + [4, 5, 6]; // -> '1,2,34,5,6' 444 | ``` 445 | 446 | ### 💡 Wytłumaczenie: 447 | 448 | Zachodzi konkatenacja. Krok po kroku wygląda to tak: 449 | 450 | ```js 451 | [1, 2, 3] + 452 | [4, 5, 6][ 453 | // call toString() 454 | (1, 2, 3) 455 | ].toString() + 456 | [4, 5, 6].toString(); 457 | // concatenation 458 | "1,2,3" + "4,5,6"; 459 | // -> 460 | ("1,2,34,5,6"); 461 | ``` 462 | 463 | ## Trailing commas in array 464 | 465 | Utworzyłeś tablicę z 4 pustymi elementami. Mimo wszystko otrzymasz tablicę z trzema elementami ze względu na końcowe przecinki: 466 | 467 | ```js 468 | let a = [, , ,]; 469 | a.length; // -> 3 470 | a.toString(); // -> ',,' 471 | ``` 472 | 473 | ### 💡 Wytłumaczenie: 474 | 475 | > **Trailing commas** (czasami nazywane "final commas") może być przydatne podczas dodawania nowych elementów, parametrów lub właściwości do kodu JavaScript. Jeśli chcesz dodać nową właściwość, możesz po prostu dodać nową linię bez modyfikowania poprzedniej poprzedniej linii, jeśli linia ta już używa przecinka końcowego. To sprawia, że różnice w kontroli wersji są czystsze, a edycja kodu może być mniej kłopotliwa. 476 | > 477 | > — [Trailing commas](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Trailing_commas) na MDN 478 | 479 | ## Równość tablic to potwór 480 | 481 | Równość tablic jest potworem w JS, jak widać poniżej: 482 | 483 | ```js 484 | [] == '' // -> true 485 | [] == 0 // -> true 486 | [''] == '' // -> true 487 | [0] == 0 // -> true 488 | [0] == '' // -> false 489 | [''] == 0 // -> true 490 | 491 | [null] == '' // true 492 | [null] == 0 // true 493 | [undefined] == '' // true 494 | [undefined] == 0 // true 495 | 496 | [[]] == 0 // true 497 | [[]] == '' // true 498 | 499 | [[[[[[]]]]]] == '' // true 500 | [[[[[[]]]]]] == 0 // true 501 | 502 | [[[[[[ null ]]]]]] == 0 // true 503 | [[[[[[ null ]]]]]] == '' // true 504 | 505 | [[[[[[ undefined ]]]]]] == 0 // true 506 | [[[[[[ undefined ]]]]]] == '' // true 507 | ``` 508 | 509 | ### 💡 Wytłumaczenie: 510 | 511 | Powinieneś uważnie obserwować powyższe przykłady! Zachowanie opisano w rozdziale [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) specyfikacji. 512 | 513 | ## `undefined` oraz `Number` 514 | 515 | Jeśli nie przekażemy żadnych argumentów do konstruktura `Number`, otrzymamy `0`. Wartość `undefined` jest przypisana do formalnych argumentów, gdy nie ma rzeczywistych argumentów, więc możesz się spodziewać, że `Number` bez argumentów dostanie `undefined` jako wartość jego parametru. Jednak kiedy przekażemy `undefined`, dostaniemy `NaN`. 516 | 517 | ```js 518 | Number(); // -> 0 519 | Number(undefined); // -> NaN 520 | ``` 521 | 522 | ### 💡 Wytłumaczenie: 523 | 524 | Zgodnie ze specyfikacją: 525 | 526 | 1. Jeśli do wywołania tej funkcji nie zostaną przekazane żadne argumenty, pozwól `n` być `+0`. 527 | 2. Inaczej, pozwól `n` być ? `ToNumber(value)`. 528 | 3. W przypadku `undefined`, `ToNumber(undefined)` powinno zwrócić `NaN`. 529 | 530 | Oto odpowiednia sekcja: 531 | 532 | - [**20.1.1** The Number Constructor](https://www.ecma-international.org/ecma-262/#sec-number-constructor) 533 | - [**7.1.3** ToNumber(`argument`)](https://www.ecma-international.org/ecma-262/#sec-tonumber) 534 | 535 | ## `parseInt` jest złym gościem 536 | 537 | `parseInt` słynie ze swoich dziwactw: 538 | 539 | ```js 540 | parseInt("f*ck"); // -> NaN 541 | parseInt("f*ck", 16); // -> 15 542 | ``` 543 | 544 | **💡 Wytłumaczenie:** Dzieje się tak, ponieważ `parseInt` będzie kontynuować analizowanie znak po znaku, dopóki nie trafi na postać, której nie zna. `f` w `'f*ck'` jest cyfrą szesnastkową `15`. 545 | 546 | Parsowanie `Infinity` do integer jest czymś… 547 | 548 | ```js 549 | // 550 | parseInt("Infinity", 10); // -> NaN 551 | // ... 552 | parseInt("Infinity", 18); // -> NaN... 553 | parseInt("Infinity", 19); // -> 18 554 | // ... 555 | parseInt("Infinity", 23); // -> 18... 556 | parseInt("Infinity", 24); // -> 151176378 557 | // ... 558 | parseInt("Infinity", 29); // -> 385849803 559 | parseInt("Infinity", 30); // -> 13693557269 560 | // ... 561 | parseInt("Infinity", 34); // -> 28872273981 562 | parseInt("Infinity", 35); // -> 1201203301724 563 | parseInt("Infinity", 36); // -> 1461559270678... 564 | parseInt("Infinity", 37); // -> NaN 565 | ``` 566 | 567 | Uważaj na parsowanie `null` także: 568 | 569 | ```js 570 | parseInt(null, 24); // -> 23 571 | ``` 572 | 573 | **💡 Wytłumaczenie:** 574 | 575 | > Konwertuje `null` na string `"null"` i próbuje to przekonwertować. W przypadku podstaw od 0 do 23 nie ma cyfr, które mógłby przekonwertować, więc zwraca NaN. Na 24, `"n"`, 14ta litera, jest dodawana do systemu liczbowego. Na 31, `"u"`, 21sza litera, jest dodawana, a cały ciąg można dekodować. Na 37 nie ma już żadnego poprawnego zestawu liczb, który można by wygenerować i `NaN` jest zwrócony. 576 | > 577 | > — [“parseInt(null, 24) === 23… wait, what?”](https://stackoverflow.com/questions/6459758/parseintnull-24-23-wait-what) na StackOverflow 578 | 579 | Nie zapomnij o ósemkach: 580 | 581 | ```js 582 | parseInt("06"); // 6 583 | parseInt("08"); // 8 if support ECMAScript 5 584 | parseInt("08"); // 0 if not support ECMAScript 5 585 | ``` 586 | 587 | **💡 Wytłumaczenie:** Jeśli ciąg wejściowy zaczyna się od "0", podstawa to osiem (ósemka) lub 10 (dziesiętnie). To, która podstawa jest wybrana, zależy od implementacji. ECMAScript 5 określa, że używana jest liczba 10 (dziesiętna), ale nie wszystkie przeglądarki obsługują to jeszcze. Z tego powodu zawsze określaj podstawę podczas używania `parseInt`. 588 | 589 | `parseInt` zawsze konwertuj dane wejściowe na ciąg: 590 | 591 | ```js 592 | parseInt({ toString: () => 2, valueOf: () => 1 }); // -> 2 593 | Number({ toString: () => 2, valueOf: () => 1 }); // -> 1 594 | ``` 595 | 596 | Zachowaj ostrożność podczas analizowania wartości zmiennoprzecinkowych 597 | 598 | ```js 599 | parseInt(0.000001); // -> 0 600 | parseInt(0.0000001); // -> 1 601 | parseInt(1 / 1999999); // -> 5 602 | ``` 603 | 604 | **💡 Wytłumaczenie:** `ParseInt` pobiera argument ciągu i zwraca liczbę całkowitą określonej podstawy. `ParseInt` usuwa również wszystko po pierwszej wartości cyfrowej i włącznie z nią w parametrze ciągu. `0.000001` jest konwertowany na ciąg znaków `"0.000001"` i `parseInt` zwraca `0`. Gdy `0.0000001` jest konwertowany na ciąg, który jest traktowany jako `"1e-7"` i stąd `parseInt` zwraca `1`. `1/1999999` jest interpretowane jako `5.00000250000125e-7` i `parseInt` zwraca `5`. 605 | 606 | ## Matematyka z `true` i `false` 607 | 608 | Zróbmy trochę matematyki: 609 | 610 | ```js 611 | true + 612 | true( 613 | // -> 2 614 | true + true 615 | ) * 616 | (true + true) - 617 | true; // -> 3 618 | ``` 619 | 620 | Hmmm… 🤔 621 | 622 | ### 💡 Wytłumaczenie: 623 | 624 | Możemy narzucić wartości do liczb za pomocą konstruktora `Number`. To całkiem oczywiste że `true` będzie zmienione na `1`: 625 | 626 | ```js 627 | Number(true); // -> 1 628 | ``` 629 | 630 | Jednoargumentowy operator plus próbuje przeliczyć swoją wartość na liczbę. Może konwertować reprezentacje ciągu liczb całkowitych i liczb zmiennoprzecinkowych, a także wartości nie łańcuchowe `true`, `false`, i `null`. Jeśli nie może przeanalizować określonej wartości, oceni to jako `NaN`. To oznacza, że możemy narzucić `true` na `1` łatwiej: 631 | 632 | ```js 633 | +true; // -> 1 634 | ``` 635 | 636 | Podczas dodawania lub mnożenia, metoda `ToNumber` jest przywoływana. Zgodnie ze specyfikacją ta metoda zwraca: 637 | 638 | > Jeśli `argument` jest **true**, zwraca **1**. Jeśli `argument` jest **false**, zwraca **+0**. 639 | 640 | Dlatego możemy dodawać wartości logiczne jako liczby regularne i uzyskiwać prawidłowe wyniki. 641 | 642 | Odpowiednie sekcje: 643 | 644 | - [**12.5.6** Unary `+` Operator](https://www.ecma-international.org/ecma-262/#sec-unary-plus-operator) 645 | - [**12.8.3** The Addition Operator (`+`)](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus) 646 | - [**7.1.3** ToNumber(`argument`)](https://www.ecma-international.org/ecma-262/#sec-tonumber) 647 | 648 | ## Komentarze HTML są obowiązujące w JavaScript 649 | 650 | Będziesz pod wrażeniem, ale ` 1471 | ```js 1472 | (function() { 1473 | return 1474 | { 1475 | b: 10; 1476 | } 1477 | })(); // -> undefined 1478 | ``` 1479 | 1480 | 1481 | ### 💡 Wytłumaczenie: 1482 | 1483 | `return` i zwrócone wyrażenie musi znajdować się w tym samym wierszu: 1484 | 1485 | ```js 1486 | (function() { 1487 | return { 1488 | b: 10 1489 | }; 1490 | })(); // -> { b: 10 } 1491 | ``` 1492 | 1493 | Wynika to z koncepcji o nazwie Automatyczne wstawianie średników, która automatycznie wstawia średniki po większości nowych linii. W pierwszym przykładzie między wyrażeniem `return` a literałem obiektu wstawiono średnik, więc funkcja zwraca `undefined`, a literał obiektu nigdy nie jest oceniany. 1494 | 1495 | - [**11.9.1** Rules of Automatic Semicolon Insertion](https://www.ecma-international.org/ecma-262/#sec-rules-of-automatic-semicolon-insertion) 1496 | - [**13.10** The `return` Statement](https://www.ecma-international.org/ecma-262/#sec-return-statement) 1497 | 1498 | ## Chaining assignments on object 1499 | 1500 | ```js 1501 | var foo = { n: 1 }; 1502 | var bar = foo; 1503 | 1504 | foo.x = foo = { n: 2 }; 1505 | 1506 | foo.x; // -> undefined 1507 | foo; // -> {n: 2} 1508 | bar; // -> {n: 1, x: {n: 2}} 1509 | ``` 1510 | 1511 | Z prawej do lewej, `{n: 2}` jest przypisany do foo, a wynik tego przypisania `{n: 2}` jest do foo.x, i dlatego bar jest `{n: 1, x: {n: 2}}` jako bar jest referencją do foo. Ale czemu foo.x jest undefined podczas gdy bar.x nie jest ? 1512 | 1513 | ### 💡 Wytłumaczenie: 1514 | 1515 | Foo and bar references the same object `{n: 1}`, and lvalues are resolved before assignations. `foo = {n: 2}` is creating a new object, and so foo is updated to reference that new object. The trick here is foo in `foo.x = ...` as a lvalue was resolved beforehand and still reference the old `foo = {n: 1}` object and update it by adding the x value. After that chain assignments, bar still reference the old foo object, but foo reference the new `{n: 2}` object, where x is not existing. 1516 | 1517 | Jest to równoważne z: 1518 | 1519 | ```js 1520 | var foo = { n: 1 }; 1521 | var bar = foo; 1522 | 1523 | foo = { n: 2 }; // -> {n: 2} 1524 | bar.x = foo; // -> {n: 1, x: {n: 2}} 1525 | // bar.x point to the address of the new foo object 1526 | // it's not equivalent to: bar.x = {n: 2} 1527 | ``` 1528 | 1529 | ## Dostęp do właściwości obiektu za pomocą tablic 1530 | 1531 | ```js 1532 | var obj = { property: 1 }; 1533 | var array = ["property"]; 1534 | 1535 | obj[array]; // -> 1 1536 | ``` 1537 | 1538 | Co z tablicami pseudo-wielowymiarowymi? 1539 | 1540 | ```js 1541 | var map = {}; 1542 | var x = 1; 1543 | var y = 2; 1544 | var z = 3; 1545 | 1546 | map[[x, y, z]] = true; 1547 | map[[x + 10, y, z]] = true; 1548 | 1549 | map["1,2,3"]; // -> true 1550 | map["11,2,3"]; // -> true 1551 | ``` 1552 | 1553 | ### 💡 Wytłumaczenie: 1554 | 1555 | Operator nawiasów klamrowych `[]` konwertuje przekazane wyrażenie za pomocą `toString`. Konwersja tablicy jednoelementowej na ciąg znaków jest zbliżona do konwersji zawartego elementu na ciąg znaków: 1556 | 1557 | ```js 1558 | ["property"].toString(); // -> 'property' 1559 | ``` 1560 | 1561 | ## Null and Relational Operators 1562 | 1563 | ```js 1564 | null > 0; // false 1565 | null == 0; // false 1566 | 1567 | null >= 0; // true 1568 | ``` 1569 | 1570 | ### 💡 Wytłumaczenie: 1571 | 1572 | Long story short, if `null` is less than `0` is `false`, then `null >= 0` is `true`. Read in-depth Wytłumaczenie for this [here](https://blog.campvanilla.com/javascript-the-curious-case-of-null-0-7b131644e274). 1573 | 1574 | ## `Number.toFixed()` display different numbers 1575 | 1576 | `Number.toFixed()` może zachowywać się trochę dziwnie w różnych przeglądarkach. Sprawdź ten przykład: 1577 | 1578 | ```js 1579 | (0.7875).toFixed(3); 1580 | // Firefox: -> 0.787 1581 | // Chrome: -> 0.787 1582 | // IE11: -> 0.788 1583 | (0.7876).toFixed(3); 1584 | // Firefox: -> 0.788 1585 | // Chrome: -> 0.788 1586 | // IE11: -> 0.788 1587 | ``` 1588 | 1589 | ### 💡 Wytłumaczenie: 1590 | 1591 | Podczas gdy twoim pierwszym instynktem może być to, że IE11 jest poprawny, a Firefox / Chrome są w błędzie, w rzeczywistości Firefox / Chrome bardziej bezpośrednio przestrzegają standardów liczbowych (zmiennoprzecinkowy IEEE-754), podczas gdy IE11 nieznacznie ich nie przestrzega (prawdopodobnie), aby dać wyraźniejsze wyniki. 1592 | 1593 | Możesz zobaczyć, dlaczego tak się dzieje po kilku szybkich testach: 1594 | 1595 | ```js 1596 | // Confirm the odd result of rounding a 5 down 1597 | (0.7875).toFixed(3); // -> 0.787 1598 | // It looks like it's just a 5 when you expand to the 1599 | // limits of 64-bit (double-precision) float accuracy 1600 | (0.7875).toFixed(14); // -> 0.78750000000000 1601 | // But what if you go beyond the limit? 1602 | (0.7875).toFixed(20); // -> 0.78749999999999997780 1603 | ``` 1604 | 1605 | Floating point numbers are not stored as a list of decimal digits internally, but through a more complicated methodology that produces tiny inaccuracies that are usually rounded away by toString and similar calls, but are actually present internally. 1606 | 1607 | In this case, that "5" on the end was actually an extremely tiny fraction below a true 5. Rounding it at any reasonable length will render it as a 5... but it is actually not a 5 internally. 1608 | 1609 | IE11, however, will report the value input with only zeros appended to the end even in the toFixed(20) case, as it seems to be forcibly rounding the value to reduce the troubles from hardware limits. 1610 | 1611 | See for reference `NOTE 2` on the ECMA-262 definition for `toFixed`. 1612 | 1613 | - [**20.1.3.3** Number.prototype.toFixed (`fractionDigits`)](https://www.ecma-international.org/ecma-262//#sec-number.prototype.tofixed) 1614 | 1615 | ## `Math.max()` mniej niż `Math.min()` 1616 | 1617 | ```js 1618 | Math.min(1, 4, 7, 2); // -> 1 1619 | Math.max(1, 4, 7, 2); // -> 7 1620 | Math.min(); // -> Infinity 1621 | Math.max(); // -> -Infinity 1622 | Math.min() > Math.max(); // -> true 1623 | ``` 1624 | 1625 | ### 💡 Wytłumaczenie: 1626 | 1627 | - [Why is Math.max() less than Math.min()?](https://charlieharvey.org.uk/page/why_math_max_is_less_than_math_min) od Charlie Harvey 1628 | 1629 | ## Comparing `null` to `0` 1630 | 1631 | Następujące wyrażenia wydają się wprowadzać w sprzeczność: 1632 | 1633 | ```js 1634 | null == 0; // -> false 1635 | null > 0; // -> false 1636 | null >= 0; // -> true 1637 | ``` 1638 | 1639 | Jak `null` nie może być ani równy ani większy od `0`, jeśli `null>=0' jest w rzeczywistości`true`? (Działa to również z mniej niż w ten sam sposób.) 1640 | 1641 | ### 💡 Wytłumaczenie: 1642 | 1643 | Sposób oceny tych trzech wyrażeń jest różny i jest odpowiedzialny za wywołanie tego nieoczekiwanego zachowania. 1644 | 1645 | Po pierwsze, abstrakcyjne porównanie równości `null == 0`. Zwykle, jeśli ten operator nie może poprawnie porównać wartości po obu stronach, konwertuje obie liczby na liczby i porównuje liczby. Następnie możesz spodziewać się następującego zachowania: 1646 | 1647 | ```js 1648 | // This is not what happens 1649 | (null == 0 + null) == +0; 1650 | 0 == 0; 1651 | true; 1652 | ``` 1653 | 1654 | Jednak, zgodnie z dokładnym odczytaniem specyfikacji, konwersja liczb tak naprawdę nie zachodzi po stronie, która jest `null` lub `undefined`. Dlatego jeśli po jednej stronie znaku równości występuje `null`, druga strona musi być `null` lub `undefined`, aby wyrażenie mogło zwrócić `true`. Ponieważ tak nie jest, zwracane jest `false`. 1655 | 1656 | Następnie relacyjne porównanie `null> 0`. Algorytm tutaj, w przeciwieństwie do abstrakcyjnego operatora równości, _przekonwertuje_ `null` na liczbę. Dlatego otrzymujemy takie zachowanie: 1657 | 1658 | ```js 1659 | null > 0 1660 | +null = +0 1661 | 0 > 0 1662 | false 1663 | ``` 1664 | 1665 | Wreszcie relacyjne porównanie `null >= 0`. Można argumentować, że to wyrażenie powinno być wynikiem `null> 0 || null == 0`; gdyby tak było, powyższe wyniki oznaczałyby, że byłoby to również `false`. Jednak operator `> =` w rzeczywistości działa w zupełnie inny sposób, co w zasadzie ma przeciwne działanie niż operator `<`. Ponieważ nasz przykład z operatorem większym niż powyżej odnosi się również do operatora mniejszego niż, oznacza to, że to wyrażenie jest w rzeczywistości oceniane tak: 1666 | 1667 | ```js 1668 | null >= 0; 1669 | !(null < 0); 1670 | !(+null < +0); 1671 | !(0 < 0); 1672 | !false; 1673 | true; 1674 | ``` 1675 | 1676 | - [**7.2.12** Abstract Relational Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-relational-comparison) 1677 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 1678 | 1679 | ## Redeklaracja tej samej zmiennej 1680 | 1681 | JS pozwala na ponowne zdefiniowanie zmiennych: 1682 | 1683 | ```js 1684 | a; 1685 | a; 1686 | // This is also valid 1687 | a, a; 1688 | ``` 1689 | 1690 | Działa również w trybie ścisłym: 1691 | 1692 | ```js 1693 | var a, a, a; 1694 | var a; 1695 | var a; 1696 | ``` 1697 | 1698 | ### 💡 Wytłumaczenie: 1699 | 1700 | Wszystkie definicje są scalone w jedną definicję. 1701 | 1702 | - [**13.3.2** Variable Statement](https://www.ecma-international.org/ecma-262/#sec-variable-statement) 1703 | 1704 | ## Domyślne zachowanie Array.prototype.sort() 1705 | 1706 | Wyobraź sobie, że musisz posortować tablicę liczb. 1707 | 1708 | ``` 1709 | [ 10, 1, 3 ].sort() // -> [ 1, 10, 3 ] 1710 | ``` 1711 | 1712 | ### 💡 Wytłumaczenie: 1713 | 1714 | Domyślna kolejność sortowania opiera się na konwersji elementów na ciągi, a następnie porównaniu ich sekwencji wartości jednostek kodu UTF-16. 1715 | 1716 | - [**22.1.3.25** Array.prototype.sort ( comparefn )](https://www.ecma-international.org/ecma-262/#sec-array.prototype.sort) 1717 | 1718 | ### Wskazówka 1719 | 1720 | Przekaż `comparefn` jeśli spróbujesz posortować cokolwiek poza ciągiem znaków. 1721 | 1722 | ``` 1723 | [ 10, 1, 3 ].sort((a, b) => a - b) // -> [ 1, 3, 10 ] 1724 | ``` 1725 | 1726 | # 📚 Inne materiały 1727 | 1728 | - [wtfjs.com](http://wtfjs.com/) — zbiór tych bardzo wyjątkowych nieprawidłowości, niespójności i po prostu bolesnie nieintuicyjnych momentów dla języka webowego. 1729 | - [Wat](https://www.destroyallsoftware.com/talks/wat) — Lightning talk od Gary Bernhardt z CodeMash 2012 1730 | - [What the... JavaScript?](https://www.youtube.com/watch?v=2pL28CcEijU) — Kyle Simpsons mówi dla Forward 2 o próbach "wyciągnięcia szaleństwa" z JavaScript. Chce pomóc ci w tworzeniu czystszego, bardziej eleganckiego, bardziej czytelnego kodu, a następnie zainspirować ludzi do współpracy w społeczności open source. 1731 | 1732 | # 🎓 Licencja 1733 | 1734 | [![CC 4.0][license-image]][license-url] 1735 | 1736 | © [Denys Dovhan](http://denysdovhan.com) 1737 | 1738 | [license-url]: http://www.wtfpl.net 1739 | [license-image]: https://img.shields.io/badge/License-WTFPL%202.0-lightgrey.svg?style=flat-square 1740 | [npm-url]: https://npmjs.org/package/wtfjs 1741 | [npm-image]: https://img.shields.io/npm/v/wtfjs.svg?style=flat-square 1742 | 1743 | Wersja polska od @[mbiesiad](https://github.com/mbiesiad) 1744 | -------------------------------------------------------------------------------- /README-pt-br.md: -------------------------------------------------------------------------------- 1 | # What the f\*ck JavaScript? 2 | 3 | [![WTFPL 2.0][license-image]][license-url] 4 | [![NPM version][npm-image]][npm-url] 5 | 6 | > Uma lista de exemplos engraçados e truques com JavaScript 7 | 8 | JavaScript é uma excelente linguagem. Ela tem uma sintaxe simples, um ecossistema grande e, o mais importante, uma grande comunidade. 9 | 10 | Ao mesmo tempo, todos nós sabemos que o JavaScript é uma linguagem engraçada com várias partes complicadas. Algumas delas porem rapidamente transformar seu trabalho em um inferno, e outras podem nos fazer gargalhar. 11 | 12 | A ideia original para o WTFJS é do [Brian Leroux](https://twitter.com/brianleroux). Essa lista é inspirada por sua talk [**“WTFJS”** no dotJS 2012](https://www.youtube.com/watch?v=et8xNAc2ic8): 13 | 14 | [![dotJS 2012 - Brian Leroux - WTFJS](https://img.youtube.com/vi/et8xNAc2ic8/0.jpg)](https://www.youtube.com/watch?v=et8xNAc2ic8) 15 | 16 | # Node Packaged Manuscript 17 | 18 | Você pode instalar esse manual usando o `npm`. É só rodar o comando: 19 | 20 | ``` 21 | $ npm install -g wtfjs 22 | ``` 23 | 24 | Você poderá rodar `wtfjs` na sua linha de comando. Esse comando vai abrir o manual na sua `$PAGER` selecionada ou você pode continuar lendo aqui mesmo. 25 | 26 | O código-fonte está disponível aqui . 27 | 28 | # Traduções 29 | 30 | Atualmente, temos essas traduções disponíveis de **wtfjs**: 31 | 32 | - [English (original)](./README.md) 33 | - [中文版](./README-zh-cn.md) 34 | - [Português do Brasil](./README-pt-br.md) 35 | 36 | [**Solicite outra tradução**][tr-request] 37 | 38 | [tr-request]: https://github.com/denysdovhan/wtfjs/issues/new?title=Translation%20Request:%20%5BPlease%20enter%20language%20here%5D&body=I%20am%20able%20to%20translate%20this%20language%20%5Byes/no%5D 39 | 40 | 41 | 42 | 43 | # Table of Contents 44 | 45 | - [💪🏻 Motivação](#-motiva%C3%A7%C3%A3o) 46 | - [✍🏻 Notação](#-nota%C3%A7%C3%A3o) 47 | - [👀 Exemplos](#-exemplos) 48 | - [`[]` é igual a `![]`](#-%C3%A9-igual-a-) 49 | - [`true` não é igual a `![]`, nem igual a `[]` também](#true-n%C3%A3o-%C3%A9-igual-a--nem-igual-a--tamb%C3%A9m) 50 | - [true é false](#true-%C3%A9-false) 51 | - [baNaNa](#banana) 52 | - [`NaN` não é um `NaN`](#nan-n%C3%A3o-%C3%A9-um-nan) 53 | - [É uma falha](#%C3%A9-uma-falha) 54 | - [`[]` é verdadeiro, mas não `true`](#-%C3%A9-verdadeiro-mas-n%C3%A3o-true) 55 | - [`null` é falso, mas não `false`](#null-%C3%A9-falso-mas-n%C3%A3o-false) 56 | - [`document.all` é um objeto (object), mas é indefinido (undefined)](#documentall-%C3%A9-um-objeto-object-mas-%C3%A9-indefinido-undefined) 57 | - [Valor mínimo é maior que zero](#valor-m%C3%ADnimo-%C3%A9-maior-que-zero) 58 | - [function não é uma function](#function-n%C3%A3o-%C3%A9-uma-function) 59 | - [Somando arrays](#somando-arrays) 60 | - [Vírgulas finais em arrays](#v%C3%ADrgulas-finais-em-arrays) 61 | - [Igualdade entre arrays é um monstro](#igualdade-entre-arrays-%C3%A9-um-monstro) 62 | - [`undefined` e `Number`](#undefined-e-number) 63 | - [`parseInt` é um vilão](#parseint-%C3%A9-um-vil%C3%A3o) 64 | - [Matemática com `true` e `false`](#matem%C3%A1tica-com-true-e-false) 65 | - [Comentários HTML são válidos no JavaScript](#coment%C3%A1rios-html-s%C3%A3o-v%C3%A1lidos-no-javascript) 66 | - [`NaN` ~~não~~ é um número](#nan-n%C3%A3o-%C3%A9-um-n%C3%BAmero) 67 | - [`[]` e `null` são objetos](#-e-null-s%C3%A3o-objetos) 68 | - [Aumentando números magicamente](#aumentando-n%C3%BAmeros-magicamente) 69 | - [Precisão de `0.1 + 0.2`](#precis%C3%A3o-de-01--02) 70 | - [Patching numbers](#patching-numbers) 71 | - [Comparação de três números](#compara%C3%A7%C3%A3o-de-tr%C3%AAs-n%C3%BAmeros) 72 | - [Matemática engraçada](#matem%C3%A1tica-engra%C3%A7ada) 73 | - [Soma de RegExps](#soma-de-regexps) 74 | - [Strings não são instâncias `String`](#strings-n%C3%A3o-s%C3%A3o-inst%C3%A2ncias-string) 75 | - [Chamando funções com backticks](#chamando-fun%C3%A7%C3%B5es-com-backticks) 76 | - [Call call call](#call-call-call) 77 | - [Uma propriedade `constructor`](#uma-propriedade-constructor) 78 | - [Objeto como uma chave de uma propriedade de objeto](#objeto-como-uma-chave-de-uma-propriedade-de-objeto) 79 | - [Acessando protótipos com `__proto__`](#acessando-prot%C3%B3tipos-com-__proto__) 80 | - [`` `${{Object}}` ``](#-object-) 81 | - [Desestruturação com valores padrão](#desestrutura%C3%A7%C3%A3o-com-valores-padr%C3%A3o) 82 | - [Pontos e dispersão](#pontos-e-dispers%C3%A3o) 83 | - [Rótulos](#r%C3%B3tulos) 84 | - [Rótulos aninhados](#r%C3%B3tulos-aninhados) 85 | - [`try..catch` traidor](#trycatch-traidor) 86 | - [Isto é herança múltipla?](#isto-%C3%A9-heran%C3%A7a-m%C3%BAltipla) 87 | - [Um gerador que produz a si mesmo](#um-gerador-que-produz-a-si-mesmo) 88 | - [Uma classe de classe](#uma-classe-de-classe) 89 | - [Objetos não coercíveis](#objetos-n%C3%A3o-coerc%C3%ADveis) 90 | - [Arrow functions traiçoeiras](#arrow-functions-trai%C3%A7oeiras) 91 | - [Arrow functions não podem ser construtores](#arrow-functions-n%C3%A3o-podem-ser-construtores) 92 | - [`arguments` e arrow functions](#arguments-e-arrow-functions) 93 | - [Retorno traiçoeiro](#retorno-trai%C3%A7oeiro) 94 | - [Encadeamento atribuições em um objeto](#encadeamento-atribui%C3%A7%C3%B5es-em-um-objeto) 95 | - [Acessando propriedades de objetos usando arrays](#acessando-propriedades-de-objetos-usando-arrays) 96 | - [Null e Operadores Relacionais](#null-e-operadores-relacionais) 97 | - [`Number.toFixed()` mostra números diferentes](#numbertofixed-mostra-n%C3%BAmeros-diferentes) 98 | - [`Math.max()` menor que `Math.min()`](#mathmax-menor-que-mathmin) 99 | - [Comparando `null` com `0`](#comparando-null-com-0) 100 | - [Redeclaração da mesma variável](#redeclara%C3%A7%C3%A3o-da-mesma-vari%C3%A1vel) 101 | - [Comportamento padrão Array.prototype.sort()](#comportamento-padr%C3%A3o-arrayprototypesort) 102 | - [📚 Outros recursos](#-outros-recursos) 103 | - [🎓 Licença](#-licen%C3%A7a) 104 | 105 | 106 | 107 | # 💪🏻 Motivação 108 | 109 | > Just for fun 110 | > 111 | > — _[**“Just for Fun: The Story of an Accidental Revolutionary”**](https://en.wikipedia.org/wiki/Just_for_Fun), Linus Torvalds_ 112 | 113 | O objetivo dessa lista era coletar alguns exemplos malucos e explicar como eles funcionam, se possível. Apenas porque é legal aprender algo que nós não conhecemos. 114 | 115 | Se você é um iniciante, você poderá utilizar esses pontos para se aprofundar no JavaScript. Eu espero que esses pontos te motivem em gastar um pouco mais de tempo lendo as especificações. 116 | 117 | Se você já é um desenvolvedor profissional, você pode considerar esses exemplos como uma excelente referência para todos as peculiaridades e pontos inesperados do nosso amado JavaScript. 118 | 119 | Em todo caso, leia. Você provavelmemte irá aprender algo novo. 120 | 121 | # ✍🏻 Notação 122 | 123 | **`// ->`** é utilizado para mostrar o resultado de uma expressão. Por exemplo: 124 | 125 | ```js 126 | 1 + 1; // -> 2 127 | ``` 128 | 129 | **`// >`** significa o resultado de `console.log` ou qualquer outra saída. Por exemplo: 130 | 131 | ```js 132 | console.log("hello, world!"); // -> hello, world! 133 | ``` 134 | 135 | **`//`** são apenas comentários para as explicações. Exemplo: 136 | 137 | ```js 138 | // Atribuindo uma função para a constante foo 139 | const foo = function() {}; 140 | ``` 141 | 142 | # 👀 Exemplos 143 | 144 | ## `[]` é igual a `![]` 145 | 146 | Array é igual a not array: 147 | 148 | ```js 149 | [] == ![]; // -> true 150 | ``` 151 | 152 | ### 💡 Explicação: 153 | 154 | O operador abstrato de igualdade converte os dois lados em números para compará-los, e os dois lados se tornam `0` por razões diferentes. Arrays são verdadeiros (truthy), então na direita, o oposto de um valor verdadeiro é `false`, o que é coagido para `0`. Na esquerda, todavia, um array vazio é coagido para um número sem se tornar um booleano (boolean) primeiro, e arrays vazios sempre forçados para `0`, apesar de serem verdadeiros. 155 | 156 | Aqui está uma simplificação dessa expressão: 157 | 158 | ```js 159 | +[] == +![]; 160 | 0 == +false; 161 | 0 == 0; 162 | true; 163 | ``` 164 | 165 | Veja também [`[]` is truthy, but not `true`](#-is-truthy-but-not-true). 166 | 167 | - [**12.5.9** Logical NOT Operator (`!`)](https://www.ecma-international.org/ecma-262/#sec-logical-not-operator) 168 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 169 | 170 | ## `true` não é igual a `![]`, nem igual a `[]` também 171 | 172 | Array não é igual a `true`, mas not Array também não é igual a `true`' 173 | Array é igual a `false`, not Array é igual a `false` também: 174 | 175 | ```js 176 | true == []; // -> false 177 | true == ![]; // -> false 178 | 179 | false == []; // -> true 180 | false == ![]; // -> true 181 | ``` 182 | 183 | ### 💡 Explicação: 184 | 185 | ```js 186 | true == []; // -> false 187 | true == ![]; // -> false 188 | 189 | // De acordo com a especificação 190 | 191 | true == []; // -> false 192 | 193 | toNumber(true); // -> 1 194 | toNumber([]); // -> 0 195 | 196 | 1 == 0; // -> false 197 | 198 | true == ![]; // -> false 199 | 200 | ![]; // -> false 201 | 202 | true == false; // -> false 203 | ``` 204 | 205 | ```js 206 | false == []; // -> true 207 | false == ![]; // -> true 208 | 209 | // De acordo com a especificação 210 | 211 | false == []; // -> true 212 | 213 | toNumber(false); // -> 0 214 | toNumber([]); // -> 0 215 | 216 | 0 == 0; // -> true 217 | 218 | false == ![]; // -> true 219 | 220 | ![]; // -> false 221 | 222 | false == false; // -> true 223 | ``` 224 | 225 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 226 | 227 | ## true é false 228 | 229 | ```js 230 | !!"false" == !!"true"; // -> true 231 | !!"false" === !!"true"; // -> true 232 | ``` 233 | 234 | ### 💡 Explicação: 235 | 236 | Considere esse passo-a-passo: 237 | 238 | ```js 239 | // true é 'truthy' e representado pelo valor 1 (number), 'true' como string é NaN. 240 | true == "true"; // -> false 241 | false == "false"; // -> false 242 | 243 | // 'false' não é uma string vazia, então ele é um valor verdadeiro (truthy) 244 | !!"false"; // -> true 245 | !!"true"; // -> true 246 | ``` 247 | 248 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 249 | 250 | ## baNaNa 251 | 252 | ```js 253 | "b" + "a" + +"a" + "a"; // -> 'baNaNa' 254 | ``` 255 | 256 | Essa é uma piada antiga no JavaScript, mas remasterizada. Aqui está a forma original: 257 | 258 | ```js 259 | "foo" + +"bar"; // -> 'fooNaN' 260 | ``` 261 | 262 | ### 💡 Explicação: 263 | 264 | A expressão é avaliada como `'foo' + (+'bar')`, o que converte `bar` para um "não número" (NaN - Not a Number). 265 | 266 | - [**12.8.3** The Addition Operator (`+`)](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus) 267 | - [12.5.6 Unary + Operator](https://www.ecma-international.org/ecma-262/#sec-unary-plus-operator) 268 | 269 | ## `NaN` não é um `NaN` 270 | 271 | ```js 272 | NaN === NaN; // -> false 273 | ``` 274 | 275 | ### 💡 Explicação: 276 | 277 | A especificação define estritamente a lógica por trás desse comportamento: 278 | 279 | > 1. Se `Type(x)` é diferente de `Type(y)`, retorne **false**. 280 | > 2. Se `Type(x)` é um Number, então 281 | > 1. Se `x` é um **NaN**, retorne **false**. 282 | > 2. Se `y` é um **NaN**, retorne **false**. 283 | > 3. … … … 284 | > 285 | > — [**7.2.14** Strict Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-strict-equality-comparison) 286 | 287 | Seguindo a definição de `NaN` do IEEE: 288 | 289 | > Quatro relações de exclusões mútuas são possíveis: menor que (less than), igual (equal), maior que (greater than), e não ordenado (unordered). O último caso surge quando, pelo menos, um operador é um NaN. Todo NaN deve comprarar não ordenado (unordered) com tudo, incluindo a si mesmo. 290 | > 291 | > — [“What is the rationale for all comparisons returning false for IEEE754 NaN values?”](https://stackoverflow.com/questions/1565164/1573715#1573715) no StackOverflow 292 | 293 | ## É uma falha 294 | 295 | Você não vai acreditar, mas ... 296 | 297 | ```js 298 | (![] + [])[+[]] + 299 | (![] + [])[+!+[]] + 300 | ([![]] + [][[]])[+!+[] + [+[]]] + 301 | (![] + [])[!+[] + !+[]]; 302 | // -> 'fail' 303 | ``` 304 | 305 | ### 💡 Explicação: 306 | 307 | Quando nós quebramos esses símbolos em pedaços, percebemos que o esse padrão se repete com frequência: 308 | 309 | ```js 310 | ![] + []; // -> 'false' 311 | ![]; // -> false 312 | ``` 313 | 314 | Então nós tentamos adicionar `[]` para `false`. Mas devido a um número interno de chamadas de função (`binary + Operator` -> `ToPrimitive` -> `[[DefaultValue]]`) nós acabamos convertendo o operador da direita para uma string: 315 | 316 | ```js 317 | ![] + [].toString(); // 'false' 318 | ``` 319 | 320 | Pensando em uma string como um array nós conseguimos acessar seu primeiro caractere usando `[0]`: 321 | 322 | ```js 323 | "false"[0]; // -> 'f' 324 | ``` 325 | 326 | O resto é óbvio, mas o `i` é ardiloso. O `i` em `fail` é pego através da geração da string `'falseundefined'` e pegando o element no índice `['10']` 327 | 328 | ## `[]` é verdadeiro, mas não `true` 329 | 330 | Um array é um valor verdadeiro (truthy), porém, não é igual a `true`. 331 | 332 | ```js 333 | !![] // -> true 334 | [] == true // -> false 335 | ``` 336 | 337 | ### 💡 Explicação: 338 | 339 | Aqui estão links das seções correspondentes especificação do ECMA-262: 340 | 341 | - [**12.5.9** Logical NOT Operator (`!`)](https://www.ecma-international.org/ecma-262/#sec-logical-not-operator) 342 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 343 | 344 | ## `null` é falso, mas não `false` 345 | 346 | Apesar do fato que `null` é um valor falso (falsy), ele não é igual a `false`. 347 | 348 | ```js 349 | !!null; // -> false 350 | null == false; // -> false 351 | ``` 352 | 353 | Ao mesmo tempo, outro valor falso (falsy), como `0` ou `''` são iguais a `false`. 354 | 355 | ```js 356 | 0 == false; // -> true 357 | "" == false; // -> true 358 | ``` 359 | 360 | ### 💡 Explicação: 361 | 362 | A explicação é a mesma dos exemplos anteriores. Aqui está o link correspondente: 363 | 364 | - [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) 365 | 366 | ## `document.all` é um objeto (object), mas é indefinido (undefined) 367 | 368 | > ⚠️ Esta é a parte da API Browser e não irá funcionar em um ambiente com Node.js - apenas em navegadores ⚠️ 369 | 370 | Apesar de document.all`ser um objeto parecido com um array, ele dá acesso aos nós do DOM na página, e responde como`undefined`na função`typeof`. 371 | 372 | ```js 373 | document.all instanceof Object; // -> true 374 | typeof document.all; // -> 'undefined' 375 | ``` 376 | 377 | Ao mesmo tempo, `document.all` não é igual a `undefined`. 378 | 379 | ```js 380 | document.all === undefined; // -> false 381 | document.all === null; // -> false 382 | ``` 383 | 384 | Mas ao mesmo tempo: 385 | 386 | ```js 387 | document.all == null; // -> true 388 | ``` 389 | 390 | ### 💡 Explicação: 391 | 392 | > `document.all` é usado como uma maneira de acessar todos os elementos do DOM, em particular com versões legadas do IE. Mesmo nunca tendo se tornado um padrão, foi amplamente usado nas eras antigas do JS. Quando o padrão progrediu com novas APIs (como `document.getElementById`) essa API (document.all) se tornou obsoleta e o comitê padrão teve que decidir o que fazer com ela. Por conta do amplo uso eles decidiram deixar a API mas introduziram uma violação intencional da especificação do JavaScript. 393 | > A razão que ele retorna como `false` quando usamos o [Comparador Estrito de Igualdade](https://www.ecma-international.org/ecma-262/#sec-strict-equality-comparison) com `undefined` e `true` quando usamos o [Comparador Abstrado de Igualdade](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) é devido a essa violação intencional que explicitamente permite isso. 394 | > 395 | > — [“Obsolete features - document.all”](https://html.spec.whatwg.org/multipage/obsolete.html#dom-document-all) em WhatWG - HTML spec 396 | > 397 | > — [“Chapter 4 - ToBoolean - Falsy values”](https://github.com/getify/You-Dont-Know-JS/blob/0d79079b61dad953bbfde817a5893a49f7e889fb/types%20%26%20grammar/ch4.md#falsy-objects) em YDKJS - Types & Grammar 398 | 399 | ## Valor mínimo é maior que zero 400 | 401 | `Number.MIN_VALUE` é o menor número, que ainda é maior que zero: 402 | 403 | ```js 404 | Number.MIN_VALUE > 0; // -> true 405 | ``` 406 | 407 | ### 💡 Explicação: 408 | 409 | > `Number.MIN_VALUE` é igual a `5e-324`, ou seja, o menor número positivo que pode ser representado com precisão float; ou seja, o mais próximo possível de zero. Isso define a melhor resolução que pontos flutuantes (floats) podem fornecer. 410 | > 411 | > Agora, o menor valor geral é `Number.NEGATIVE_INFINITY`, embora ele não seja realmente numérico em um senso estrito. 412 | > 413 | > — [“Why is `0` less than `Number.MIN_VALUE` in JavaScript?”](https://stackoverflow.com/questions/26614728/why-is-0-less-than-number-min-value-in-javascript) no StackOverflow 414 | 415 | - [**20.1.2.9** Number.MIN_VALUE](https://www.ecma-international.org/ecma-262/#sec-number.min_value) 416 | 417 | ## function não é uma function 418 | 419 | > ⚠️ Um bug presenta na V8 v5.5 or anterior (Node.js <=7) ⚠️ 420 | 421 | Todos vocês conhecem a chatice de _undefined is not a function_, mas e quanto a isso? 422 | 423 | ```js 424 | // Declare uma classe que extende de null 425 | class Foo extends null {} 426 | // -> [Function: Foo] 427 | 428 | new Foo() instanceof null; 429 | // > TypeError: function is not a function 430 | // > at … … … 431 | ``` 432 | 433 | ### 💡 Explicação: 434 | 435 | Isto não é parte da especificação. É apenas um bug que já foi arrumado, então isso não deverá ser um problema no futuro. 436 | 437 | ## Somando arrays 438 | 439 | E se você tentar somar dois arrays? 440 | 441 | ```js 442 | [1, 2, 3] + [4, 5, 6]; // -> '1,2,34,5,6' 443 | ``` 444 | 445 | ### 💡 Explicação: 446 | 447 | A concatenação ocorre. Passo-a-passo, ela ocorre mais ou menos assim: 448 | 449 | ```js 450 | [1, 2, 3] + 451 | [4, 5, 6][ 452 | // call toString() 453 | (1, 2, 3) 454 | ].toString() + 455 | [4, 5, 6].toString(); 456 | // concatenation 457 | "1,2,3" + "4,5,6"; 458 | // -> 459 | ("1,2,34,5,6"); 460 | ``` 461 | 462 | ## Vírgulas finais em arrays 463 | 464 | Você criou um array com 4 elementos vazios. Apesar disso, você terá um array com três elementos, por conta das vírgulas finais (trailing commas): 465 | 466 | ```js 467 | let a = [, , ,]; 468 | a.length; // -> 3 469 | a.toString(); // -> ',,' 470 | ``` 471 | 472 | ### 💡 Explicação: 473 | 474 | > **Trailing commas** (também chamadas de "final commas", ou em português, "vírgulas finais") são úteis quando você adiciona novos elementos, parâmetros ou propriedades em um código JS. Caso se você quer adicionar uma nova propriedade, você pode simplesmente adicionar uma nova linha sem modificar a anterior se ela já utiliza uma trailling comma. Isso faz com que os _diffs_ no versionamento de código sejam mais limpos, e também a edição do código menos problemática. 475 | > 476 | > — [Trailing commas](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Trailing_commas) no MDN 477 | 478 | ## Igualdade entre arrays é um monstro 479 | 480 | Igualdade de arrays é um monstro no JS, como você pode ver abaixo: 481 | 482 | ```js 483 | [] == '' // -> true 484 | [] == 0 // -> true 485 | [''] == '' // -> true 486 | [0] == 0 // -> true 487 | [0] == '' // -> false 488 | [''] == 0 // -> true 489 | 490 | [null] == '' // true 491 | [null] == 0 // true 492 | [undefined] == '' // true 493 | [undefined] == 0 // true 494 | 495 | [[]] == 0 // true 496 | [[]] == '' // true 497 | 498 | [[[[[[]]]]]] == '' // true 499 | [[[[[[]]]]]] == 0 // true 500 | 501 | [[[[[[ null ]]]]]] == 0 // true 502 | [[[[[[ null ]]]]]] == '' // true 503 | 504 | [[[[[[ undefined ]]]]]] == 0 // true 505 | [[[[[[ undefined ]]]]]] == '' // true 506 | ``` 507 | 508 | ### 💡 Explicação: 509 | 510 | Você deve observar bem cautelosamente os exemplos acima! O comportamento é descrito na seção [**7.2.13** Abstract Equality Comparison](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison) da especificação. 511 | 512 | ## `undefined` e `Number` 513 | 514 | Se nós não passarmos nenhum argumento em um construtor `Number`, nós teremos `0` como retorno. O valor `undefined` é atribuído em argumentos formais quando não não existem argumentos, então você deve esperar que `Number` sem argumentos receba `undefined` como um valor dos seus parâmetros. Todavia, quando passamos `undefined`, o retorno será `NaN`. 515 | 516 | ```js 517 | Number(); // -> 0 518 | Number(undefined); // -> NaN 519 | ``` 520 | 521 | ### 💡 Explicação: 522 | 523 | De acordo com a especificação: 524 | 525 | 1. Se nenhum argumento for passado na chamada da função, `n` será `+0`. 526 | 2. Se não, `n` será ? `ToNumber(value)`. 527 | 3. Em caso de `undefined`, `ToNumber(undefined)` deve retornar `NaN`. 528 | 529 | Aqui está a seção correspondente: 530 | 531 | - [**20.1.1** The Number Constructor](https://www.ecma-international.org/ecma-262/#sec-number-constructor) 532 | - [**7.1.3** ToNumber(`argument`)](https://www.ecma-international.org/ecma-262/#sec-tonumber) 533 | 534 | ## `parseInt` é um vilão 535 | 536 | `parseInt` é famoso por suas peculiaridades: 537 | 538 | ```js 539 | parseInt("f*ck"); // -> NaN 540 | parseInt("f*ck", 16); // -> 15 541 | ``` 542 | 543 | **💡 Explicação:** 544 | 545 | Isso acontece porque `parseInt` vai continuar parseando caractere por caractere até que ele atinja um caractere desconhecido. O `f` em `f*ck` é o dígito hexadecimal `15`. 546 | 547 | Se você parsear `Infinity` para um inteiro… 548 | 549 | ```js 550 | // 551 | parseInt("Infinity", 10); // -> NaN 552 | // ... 553 | parseInt("Infinity", 18); // -> NaN... 554 | parseInt("Infinity", 19); // -> 18 555 | // ... 556 | parseInt("Infinity", 23); // -> 18... 557 | parseInt("Infinity", 24); // -> 151176378 558 | // ... 559 | parseInt("Infinity", 29); // -> 385849803 560 | parseInt("Infinity", 30); // -> 13693557269 561 | // ... 562 | parseInt("Infinity", 34); // -> 28872273981 563 | parseInt("Infinity", 35); // -> 1201203301724 564 | parseInt("Infinity", 36); // -> 1461559270678... 565 | parseInt("Infinity", 37); // -> NaN 566 | ``` 567 | 568 | Tenha cuidado quando parsear um `null` também: 569 | 570 | ```js 571 | parseInt(null, 24); // -> 23 572 | ``` 573 | 574 | **💡 Explicação:** 575 | 576 | > Ele converte `null` para uma string `"null"` e tenta fazer o parse. Para raízes de 0 a 23, não existem numerais que ele possa converter, então ele retorna NaN. Em 24, `"n"`, a 14ª letra, é adicionada ao sistema numérico. Em 31, `"u"`, a 21ª letra, é adicionada e a string inteira poderá ser decodificada. Em 37 onde não existe mais nenhum numeral válido definido que poderá ser gerado, o retorno é `NaN`. 577 | > 578 | > — [“parseInt(null, 24) === 23… wait, what?”](https://stackoverflow.com/questions/6459758/parseintnull-24-23-wait-what) no StackOverflow 579 | 580 | Não se esqueça dos octals: 581 | 582 | ```js 583 | parseInt("06"); // 6 584 | parseInt("08"); // 8 se suporta ECMAScript 5 585 | parseInt("08"); // 0 se não suporta ECMAScript 5 586 | ``` 587 | 588 | **💡 Explicação:** 589 | 590 | Se uma string de entrada começa com "0", a raiz é oito (octal) ou 10 (decimal). A raiz que é escolhida dependerá da implementação. O ECMAScript 5 define que a 10 (decimal) é utilizada, mas nem todos os navegadores suportam isso ainda. Por essa razão sempre deixe explícito qual será a raiz utilizada quando você usar o `parseInt`. 591 | 592 | `parseInt` sempre converte a entrada para string: 593 | 594 | ```js 595 | parseInt({ toString: () => 2, valueOf: () => 1 }); // -> 2 596 | Number({ toString: () => 2, valueOf: () => 1 }); // -> 1 597 | ``` 598 | 599 | Tenha cuidado quando tentar fazer o parse de valores _floating ponts_ (pontos flutuantes) 600 | 601 | ```js 602 | parseInt(0.000001); // -> 0 603 | parseInt(0.0000001); // -> 1 604 | parseInt(1 / 1999999); // -> 5 605 | ``` 606 | 607 | **💡 Explicação:** 608 | 609 | `ParseInt` recebe uma string como argumento e retorna um inteiro da raiz específica. `ParseInt` também remove tudo depois e incluindo o primeiro _non-digit_ (não dígito) no parâmetro como string. `0.000001` é convertido para a string `"0.000001"` e o `parseInt` retorna `0`. Quando `0.0000001` é convertido para uma string ele é tratado como `"1e-7"` e, portanto, `parseInt` retorna `1`. `1/1999999` é interpretado como `5.00000250000125e-7` e o `parseInt` retorna `5`. 610 | 611 | ## Matemática com `true` e `false` 612 | 613 | Vamos fazer algumas contas: 614 | 615 | ```js 616 | true + 617 | true( 618 | // -> 2 619 | true + true 620 | ) * 621 | (true + true) - 622 | true; // -> 3 623 | ``` 624 | 625 | Hmmm… 🤔 626 | 627 | ### 💡 Explicação: 628 | 629 | Podemos forçar valores números com o construtor `Number`. É bem óbvio que `true` será forçado para `1`: 630 | 631 | ```js 632 | Number(true); // -> 1 633 | ``` 634 | 635 | O operador unário _soma_ (i++) tenta converter o valor para um número. Ele pode converter representações de inteiros e flutuantes em strings, bem como os valores que não são stings, como `true`, `false` e `null`. Se ele não conseguir parsear um valor particular, então será avaliado como `NaN`. Isso significa que nós podemos forçar `true` para `1` facilmente: 636 | 637 | ```js 638 | +true; // -> 1 639 | ``` 640 | 641 | Quando você realiza uma adição ou uma multiplicacão, o método `ToNumber` é invocado. 642 | De acordo com a especificação, esse método retorna: 643 | 644 | > Se `argument` é **true**, o retorno será **1**. Se `argumento` é `false`, o retorno será **0**. 645 | 646 | Por isso podemos adicionar valores booleanos (boolean) como números regulares e obtermos os resultados corretos. 647 | 648 | Seções correspondentes: 649 | 650 | - [**12.5.6** Unary `+` Operator](https://www.ecma-international.org/ecma-262/#sec-unary-plus-operator) 651 | - [**12.8.3** The Addition Operator (`+`)](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus) 652 | - [**7.1.3** ToNumber(`argument`)](https://www.ecma-international.org/ecma-262/#sec-tonumber) 653 | 654 | ## Comentários HTML são válidos no JavaScript 655 | 656 | Você ficará impressionado, mas `