",
5 | "main": "''",
6 | "jest": {
7 | "setupTestFrameworkScriptFile": "jest-chain"
8 | },
9 | "scripts": {
10 | "test": "jest --watch"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/pixari/dmfojs.git"
15 | },
16 | "keywords": [
17 | "javascript"
18 | ],
19 | "author": "",
20 | "license": "ISC",
21 | "bugs": {
22 | "url": "https://github.com/pixari/dmfojs/issues"
23 | },
24 | "homepage": "https://github.com/pixari/dmfojs#readme",
25 | "devDependencies": {
26 | "jest": "^24.8.0",
27 | "jest-chain": "^1.1.2"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Raffaele Pizzari
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | # Contributors
2 |
3 | Thanks goes to these people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
4 |
5 |
6 |
10 |
11 | ## 1. What is the double negation?
12 |
13 | > Example:
14 | ```js
15 | !!true; // true
16 | !!false; // false
17 | !!(new Boolean(true)); // true
18 | !!(new Boolean(false)); /
19 | ```
20 |
21 | TODO: explanation
22 |
23 | ## 2. Why && and || do not return a boolean value like other languages ?
24 |
25 | > Example:
26 | ```js
27 | true && "Hello world" && 2 // 2
28 | 54.3 && false && 3 // false
29 | "" && 1 // ""
30 | 2 && "hi" && null // null
31 | ```
32 |
33 | ```js
34 | true || "Hello world" || 2 // true
35 | false || 3 || 54.3 // 3
36 | "" || 1 // 1
37 | "" || undefined || null // null
38 | ```
39 |
40 | ### Explanation
41 |
42 | JavaScript coerces the operand value to boolean value to determine the value of a logical operation. If a value can be converted to true, the value is so-called truthy. If a value can be converted to false, the value is so-called falsy.
43 |
44 | **The logical operator && is evaluated from left to right and the evaluation stops once it finds a falsy value and returns the operand that has falsy value. If no falsy value is present then the last operand is returned.**
45 | * _In example 1_, all values are truthy hence last operand `2` is returned
46 | * _In example 2_, first value is truthy but as soon as second operand is evaluated it returned falsy value, hence `false` is returned
47 | * _In example 3_, "" is falsy hence evaluation stopped and next operand is not evaluated and `""` returned
48 | * _In example 4_, the first two operands are truthy but the last one is falsy hence `null` returned
49 |
50 | The logical operator || is the reverse of &&.
51 |
52 | **The logical operator || is evaluated from left to right and the evaluation stops once it finds a truthy value and returns the operand that has truthy value. If no truthy value is present then the last operand is returned.**
53 | * _In example 1_, the first operand has truthy value hence further operands are not evaluated and `true` is returned
54 | * _In example 2_, first value is falsy but as soon as second operand is evaluated it returned truthy value, hence `3` is returned
55 | * _In example 3_, "" is falsy hence evaluation moved forward and `1` returned
56 | * _In example 4_, all the operands are false hence `null` is returned
57 |
58 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
9 |
10 | Contributions welcome!
11 |
12 | **Before spending lots of time on something, ask for feedback on your idea first!**
13 |
14 | Please search issues and pull requests before adding something new to avoid duplicating
15 | efforts and conversations.
16 |
17 | This project welcomes non-code contributions, too! The following types of contributions
18 | are welcome:
19 |
20 | - **Ideas**: participate in an issue thread or start your own to have your voice heard.
21 | - **Writing**: contribute your expertise in an area by helping expand the included docs.
22 | - **Copy editing**: fix typos, clarify language, and improve the quality of the docs.
23 | - **Formatting**: help keep docs easy to read with consistent formatting.
24 |
25 | ## Project Governance
26 |
27 | Individuals making significant and valuable contributions are given commit-access to the
28 | project to contribute as they see fit. This project is more like an open wiki than a
29 | standard guarded open source project.
30 |
31 | ### Rules
32 |
33 | There are a few basic ground-rules for contributors:
34 |
35 | 1. **No `--force` pushes** or modifying the Git history in any way.
36 | 2. **Significant modifications** should be subject to a **pull request**
37 | to solicit feedback from other contributors.
38 | 3. **Pull requests** are *encouraged* for all contributions to solicit feedback, but left to
39 | the discretion of the contributor.
40 |
41 | ### Releases
42 |
43 | Declaring formal releases remains the prerogative of the project maintainer.
44 |
45 | ### Changes to this arrangement
46 |
47 | This is an experiment and feedback is welcome! This document may also be subject to pull-
48 | requests or changes by contributors where you believe you have something valuable to add
49 | or change.
50 |
51 | ## Developer's Certificate of Origin 1.1
52 |
53 | By making a contribution to this project, I certify that:
54 |
55 | - (a) The contribution was created in whole or in part by me and I have the right to
56 | submit it under the open source license indicated in the file; or
57 |
58 | - (b) The contribution is based upon previous work that, to the best of my knowledge, is
59 | covered under an appropriate open source license and I have the right under that license
60 | to submit that work with modifications, whether created in whole or in part by me, under
61 | the same open source license (unless I am permitted to submit under a different
62 | license), as indicated in the file; or
63 |
64 | - (c) The contribution was provided directly to me by some other person who certified
65 | (a), (b) or (c) and I have not modified it.
66 |
67 | - (d) I understand and agree that this project and the contribution are public and that a
68 | record of the contribution (including all personal information I submit with it,
69 | including my sign-off) is maintained indefinitely and may be redistributed consistent
70 | with this project or the open source license(s) involved.
71 |
--------------------------------------------------------------------------------
/content/02-arithmetic-operators.md:
--------------------------------------------------------------------------------
1 | # Chapter 2 - Arithmetic operators
2 |
3 |
10 |
11 | ## 1. Why 0.1 + 0.2 = 0.300000004?
12 |
13 | > Example:
14 |
15 | ```js
16 | 0.1 + 0.2; // 0.300000004
17 | ```
18 |
19 | ### Explanation
20 |
21 | This is not just a javascript language limitation but also a limitation for many other programming languages(C or Java or C++) . This is a problem with the format(IEEE 754 -binary floating point) that computers internally use to represent the numbers. This format cannot represent the numbers like 0.1 or 0.2 accurately because they store the numbers in binary and floating number cannot store all the decimal numbers properly
22 | For Example, 0.1 would be coverted in the following way
23 |
24 | ```
25 | 0.1 = 1/10 => 1/16 + (1/10-1/16) => 1/32 + (0.0375-1/32) ....so on
26 | and the ultimate result would be around 0.1000000000000000055511151231257827021181583404541015625
27 | ```
28 |
29 | So when the code is compiled or transpiled or interpreted,0.1 will be rounded/chopped off to nearest number in the representable binary format and hence when arithmetic operations are performed , there can be small rounding errors .Hence we get 0.300000004 instead of 0.3, when we add 0.1 and 0.2 . For more detailed explanation,check out this [paper by David Goldberg](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html)
30 | and [article](https://blog.angularindepth.com/javascripts-number-type-8d59199db1b6)
31 |
32 | ### Fix
33 |
34 | There is a simple fix to this issue as shown below
35 |
36 | ```javascript
37 | var a = 0.1 + 0.2; //0.300000004
38 | var b = +(0.1 + 0.2).toFixed(1); //round off to avoid errorneous value and convert it back to number by using +
39 | //b = 0.3
40 | ```
41 | Alternatively, if you want to compare floating point values, you can use this solution from [Kyle Simpson's "You Don't Know JS"](https://github.com/getify/You-Dont-Know-JS/blob/master/types%20%26%20grammar/ch2.md) which uses what is commonly known as "machine epsilon" as a tolerance value.
42 |
43 | ```javascript
44 | function numbersCloseEnoughToEqual(n1,n2) {
45 | return Math.abs( n1 - n2 ) < Number.EPSILON;
46 | }
47 |
48 | numbersCloseEnoughToEqual( a, b ); // true
49 | numbersCloseEnoughToEqual( 0.0000001, 0.0000002 );
50 | ```
51 |
52 | Polyfill for `Number.EPSILON` pre-ES6:
53 | ```javascript
54 | if (!Number.EPSILON) {
55 | Number.EPSILON = Math.pow(2,-52);
56 | }
57 | ```
58 | =======
59 | ## 2. Why (! + [] + [] + ![]).length is 9?
60 |
61 | > Example:
62 |
63 | ```js
64 | (!+[] + [] + ![]).length; // 9
65 | ```
66 |
67 | ### Explanation
68 |
69 | JavaScript does operations from right to left.
70 | The + operand first tries to add the left to the right, if that isn't possible it tries to convert the operand on the right to a number and if it can't do that it converts it to a string. If there is something to the left of the + it adds them together, and if it can't it sticks around. If there is nothing to the left it goes away.
71 | The ! operand converts the operand to the right to a boolean and then reverts it.
72 | The detailed explaniation see also the test.
73 |
74 | ```
75 | expect(!+[] + [] + ![])
76 | .toBe((!+[]) + ([]) + (![]))
77 | .toBe('true' + '' + 'false')
78 | .toHaveLength(9);
79 | ```
80 |
81 | For more detailed explanation,check out this [by Tomas Forsman](https://dev.to/tomasforsman/why-length-is-9-2i4l)
82 |
--------------------------------------------------------------------------------
/test/spec.js:
--------------------------------------------------------------------------------
1 | describe(`Chapter 1 - Comparison`, () => {
2 | it(`NaN isn't equal to NaN`, () => {
3 | expect(NaN === NaN).toBeFalsy();
4 | expect(NaN == NaN).toBeFalsy();
5 | });
6 | it(`[] == ![] but [] == []`, () => {
7 | expect([] == ![]).toBeTruthy();
8 | expect([] == []).toBeFalsy();
9 | });
10 | it(`Does the new String(...) makes any sense?`, () => {
11 | let str = new String("foo"); // String {"foo"}
12 | expect(typeof str).toBe("object");
13 | expect(typeof "foo").toBe("string"); // 'foo'
14 |
15 | expect(str)
16 | .toEqual("foo")
17 | .not.toBe("foo");
18 | });
19 | it(`As Javascript is weakly typed language, instead of throwing an error for operands of different types , it implicitly converts true to 1`, () => {
20 | expect(1 < 2 < 3).toBeTruthy();
21 | expect(3 > 2 > 1).toBeFalsy();
22 | });
23 | });
24 | describe(`Chapter 2 - Arithmetic operators`, () => {
25 | it(`This format cannot represent the numbers like 0.1 or 0.2 accurately because they store the numbers in binary and floating number cannot store all the decimal numbers properly`, () => {
26 | const adding = 0.1 + 0.2;
27 | expect(adding).not.toBe(0.3);
28 | expect(+adding.toFixed(1)).toBe(0.3);
29 | });
30 | it(`The ! operand converts the operand to the right to a boolean and then reverts it.`, () => {
31 | expect(!+[] + [] + ![])
32 | .toBe((!+[]) + ([]) + (![]))
33 | .toBe('true' + '' + 'false')
34 | .toBe('truefalse')
35 | .toHaveLength(9);
36 | });
37 | });
38 | describe(`Chapter 3 -Types`, () => {
39 | it(`NaN is a number`, () => {
40 | expect(typeof NaN).toBe("number");
41 | expect(isNaN(NaN)).toBeTruthy();
42 | });
43 | it(`Conversion to String()`, () => {
44 | expect(String(null)).toBe("null");
45 | expect(String(undefined)).toBe("undefined");
46 | expect(String([null]))
47 | .toBe(String([undefined]))
48 | .toBe("");
49 | });
50 | it(`Conversion to Number()`, () => {
51 | expect(Number(null)).toBe(0);
52 | expect(Number(undefined)).toBe(NaN);
53 | expect(Number([null])).toBe(0);
54 | expect(Number([undefined])).toBe(0);
55 | });
56 | });
57 | describe(`Chapter 4 - operators`, () => { });
58 | it(`What is the double negation?`, () => {
59 | expect(!!true)
60 | .toBe(!!new Boolean(true))
61 | .toBe(!!new Boolean(false))
62 | .toBeTruthy();
63 | expect(!!false).toBeFalsy();
64 | });
65 | it(`The logical operator && is evaluated from left to right and the evaluation stops once it finds a falsy value and returns the operand that has falsy value. If no falsy value is present then the last operand is returned.`, () => {
66 | expect(true && "Hello world" && 2).toBe(2);
67 | expect(54.3 && false && 3).toBe(false);
68 | expect("" && 1).toBe("");
69 | expect(2 && "hi" && null).toBe(null);
70 | expect(true || "Hello world" || 2).toBe(true);
71 | expect(false || 3 || 54.3).toBe(3);
72 | expect("" || 1).toBe(1);
73 | expect("" || undefined || null).toBe(null);
74 | });
75 | describe(`Chapter 5 - Arrays`, () => {
76 | it(`What's Array(k) really doing?`, () => {
77 | const a = Array(3);
78 | const b = Array.apply(null, Array(3));
79 | expect(a)
80 | .toEqual(b)
81 | .toEqual([undefined, undefined, undefined]);
82 | expect(a[2])
83 | .toEqual(b[2])
84 | .toBeUndefined(); // undefined
85 | expect(a.length)
86 | .toBe(b.length)
87 | .toBe(3); // 3
88 | expect(a.map((v, idx) => idx)).toEqual([undefined, undefined, undefined]); // [ ]
89 |
90 | expect(b.map((v, idx) => idx)).toEqual([0, 1, 2]);
91 | });
92 | });
93 |
--------------------------------------------------------------------------------
/content/01-comparison-operators.md:
--------------------------------------------------------------------------------
1 | # Chapter 1 - Comparison
2 |
3 |
10 |
11 | ## 1. Why NaN isn't equal to NaN?
12 |
13 | > Example:
14 | ```js
15 | NaN === NaN; // false
16 | NaN == NaN; // false
17 | ```
18 |
19 | ### Explanation
20 |
21 | This behavior is specified by [ECMA-262](http://www.ecma-international.org/ecma-262) in _Strict Equality Comparison_ and _Abstract Equality Comparison_ sections. In both comparisons, wheter strict (`===`) or not (`==`), if any of the operand is `NaN` the result is `false`. The pseudo code mentionned is as follows :
22 |
23 | ```
24 | 1. If Type(x) is different from Type(y), return false.
25 | 2. If Type(x) is Number, then
26 | 1. If x is NaN, return false.
27 | 2. If y is NaN, return false.
28 | ```
29 |
30 | This is inherited from [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754), the IEEE standard for floating-point arithmetic, which states that any operation performed on `NaN` should yield a false value or raise an error.
31 |
32 | ## 2. Why [] == ![] but [] == []?
33 |
34 | > Example:
35 | ```js
36 | [] == [] // false
37 | [] == ![] // true
38 | [] === [] // false
39 | [] === ![] // false
40 | ```
41 |
42 | ### Explanation
43 |
44 | With Javascript, comparing empty arrays (or any arrays) only returns true when the array is compared to itself. In the first example, two new empty arrays are created and compared. Since both values before and after the equal signs are implicitly declared and not referencing the same object, the comparison returns false.
45 |
46 | A different behaviour in Javascript is that an empty array is considered a truthy value, thus converting an empty array to a boolean value returns `true`. In the second example, an empty array is compared to `![]`, which resolves to `false`. For the comparison, the first empty array is converted to its primitive value, which is an empty string (`""`). An empty string is considered a falsy value. The result is that a falsy value is compared to `false`, which returns true.
47 |
48 | For the third example, two empty arrays are again implicitly declared and referencing two different arrays. This returns `false` as the references are checked are not equal.
49 |
50 | The final example does a strict comparison against an empty array, thus an `Array` type, and `![]`, which once again resolves into `true`. Doing a strict comparison first checks both values' types, which are `Array` and `Boolean` here, and returns `false` if not equal.
51 |
52 | ## 3. Does the new String(...) makes any sense?
53 |
54 | > Example:
55 | ```js
56 | new String('foo'); // String {"foo"}
57 | typeof new String('foo'); // 'object'
58 | 'foo'; // 'foo'
59 | typeof 'foo'; // 'string'
60 |
61 | //but...
62 |
63 | new String('foo') == 'foo'; // true
64 | ```
65 |
66 | TODO: explanation
67 |
68 | ## 4. How does x < y < z / x > y > z works?
69 |
70 | > Example:
71 | ```js
72 | 1 < 2 < 3; // true
73 | 3 > 2 > 1; // false
74 | ```
75 |
76 | ### Explanation
77 | TL;DR: This is javascript way of evaluating above expressions and the reason for such wierd results
78 | 
79 |
80 | Generally the expression 3>2>1 is expected to return true since it is mathematically correct. But as javascript is a weak typed language, the evaluation of the above expression is done a bit differently. So lets break the evaluation down to 3 fundamental steps
81 | 1. ### Operator Precedence
82 | There are 2 operators(>,>) used in this expression (3>2>1) which have the same precedence. So the expression is evaluated from left to right as per [Operator precedence table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table)
83 | 2. ### Evaluation of left most expression
84 | The left most expression in `3>2>1` is `3>2`. Javascript evaluates this expression and returns `true` as 3 is greater than 2. Hence we are left with the expression `true>1`
85 | 3. ### Implcit conversion
86 | Javascript now evaluates the left out expression i.e., `true>1`. As Javascript is weakly typed language, instead of throwing an error for operands of different types , it implicitly converts `true` to `1`. So the expression is transformed to `1>1` which is obviously false. Hence the value is returned as false.
87 |
88 | These are the steps that are followed to evaluate the expression and are the main reason for the weird results like the below ones
89 | ```js
90 | 3>2>=1 //true
91 | 0<3<2 //true
92 | ```
93 |
94 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
9 |
10 | 
11 | 
12 | 
13 | 
14 |
15 |
16 | ## Read it online (free):
17 |
18 | - "Don't make fun of JavaScript" - [GitBook Format](https://book.dmfoj.dev) - https://book.dmfoj.dev
19 |
20 | ## What is this?
21 |
22 | JavaScript is a easy language to learn and easy to use or at least we can all agree that has a attractive and gradual learning curve.
23 | In fact, anyone can run its first "Hello World!" script in 1 minute just opening the browser's console and typing "console.log('Hello World!')".
24 |
25 | This is one of the (many) reasons why it is one of the most widely used programming language supported by an extremely large community.
26 |
27 | Despite those unquestionable greatest attribute, JavaScript has also a bad reputation: I heard it's the "worst language in the world", or "it's totally unreliable" and "it's just stupid interpreted language used to animate buttons".
28 |
29 | I understand where all these concerns are coming from, but I'm truly convinced that JavaScript it's just the world's most misunderstood programming language.
30 |
31 | That's why I decide to start collecting all the jokes, the critics and the misconceptions about JavaScript and try to
32 | demystify most of them.
33 |
34 | Feel free to contribute 🙏
35 |
36 | ## Table of Contents
37 |
38 | 1. [Comparison operators](/content/01-comparison-operators.md)
39 | 2. [Arithmetic operators](/content/02-arithmetic-operators.md)
40 | 3. [Types](/content/03-types.md)
41 | 4. [Arrays](/content/04-arrays.md)
42 | 5. [Logical operators](/content/05-logical-operators.md)
43 |
44 | ## Contributing
45 |
46 | I would really appreciate if you could contribute to this project.
47 | For example, you can:
48 |
49 | - Suggest a new "topic"
50 | - Add a new "joke"
51 | - Add/improve an explanation
52 | - Share this project
53 | - Give me a feedback
54 |
55 | ### Code of Conduct
56 |
57 | If have adopted the same Code of Conduct as Facebook that we expect project participants to adhere to. Please read [the full text](https://code.facebook.com/codeofconduct) so that you can understand what actions will and will not be tolerated.
58 |
59 |
60 | ## Run tests with Jest
61 |
62 | ```
63 | npm install
64 | npm run test
65 | ```
66 |
67 | ### Contributing Guide
68 |
69 | Read our [contributing guide](/CONTRIBUTING.md) to learn about how you can contribute, how to propose improvements or if you are interested in translating the content.
70 |
71 | ## License
72 |
73 | All projects and packages in this repository are [MIT licensed](/LICENSE).
74 |
75 | ## Contributors
76 |
77 | Thanks goes to these people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
78 |
79 |
80 |
81 |