├── .gitignore ├── .notes.md ├── .travis.yml ├── DRAFTS.md ├── NOTES.md ├── README.md ├── _notes └── phoenix.md ├── docs ├── CNAME ├── _layouts │ ├── base.jade │ ├── book.jade │ ├── chapter.jade │ ├── example.jade │ ├── includes │ │ └── analytics.jade │ └── landing.jade ├── assets │ ├── script.js │ └── style.scss ├── es2015 │ ├── classes.md │ ├── destructuring.md │ ├── examples │ │ ├── functions-short.jade │ │ ├── variables-const.jade │ │ ├── variables-let.jade │ │ └── variables-scoping.jade │ ├── functions.md │ ├── index.jade │ ├── modules.md │ ├── objects.md │ ├── overview.md │ ├── strings.md │ └── variables.md ├── index.jade └── redux │ ├── actions.md │ ├── examples │ ├── actions-second-try.jade │ ├── intro-dispatching.jade │ ├── intro-first-store.jade │ ├── intro-simple-read.jade │ ├── intro-subscribe.jade │ ├── intro-updating.jade │ └── reducers-sample.jade │ ├── index.jade │ ├── introduction.md │ ├── middleware.md │ ├── react.md │ └── reducers.md ├── lib ├── example.js ├── helpers │ └── jquery.autoexpand.js ├── meta.js ├── middleware.js ├── web-example │ └── index.js └── web │ ├── actions │ ├── load_next_slide.js │ └── navigate_to_hash.js │ ├── behaviors │ ├── html-mobile-scroll-offset.js │ ├── iframe-seamless.js │ └── page-scroller.js │ ├── helpers │ └── on_scrollup.js │ └── index.js ├── metalsmith.js ├── package.json ├── sass ├── _variables.scss ├── base │ ├── _base.scss │ ├── _blockquote.scss │ ├── _code.scss │ ├── _details.scss │ ├── _headings.scss │ └── _hr.scss ├── book │ ├── _chapter-links.scss │ └── _cover-section.scss ├── components │ ├── _button-link.scss │ ├── _chapter-prelude.scss │ ├── _container.scss │ ├── _example-block.scss │ ├── _hljs.scss │ ├── _nav.scss │ ├── _output-line.scss │ ├── _page-dots.scss │ ├── _page-section.scss │ ├── _playground-box.scss │ ├── _spinner-box.scss │ ├── _up-next.scss │ └── page-scroller.scss ├── extensions │ ├── _literate.scss │ └── _muting.scss ├── mixins │ ├── _clearfix.scss │ ├── _hit-area.scss │ └── _hr-rule.scss └── style.scss ├── superstatic.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | public 3 | -------------------------------------------------------------------------------- /.notes.md: -------------------------------------------------------------------------------- 1 | ## Annotations 2 | 3 | These will (eventually) be parsed to a different presentation. 4 | 5 | - `// ...` - collapse this line 6 | - `// ^--^` - underlines the upper text 7 | - `//@` - highlight line 8 | - `// <--` - comment on this line 9 | - `/*...*/` - snipping code that's not important 10 | - `/*[ hello ]*/` - annotations 11 | - `> ↳` - caption of a figure 12 | - `#####` (h5) - the title of the figure 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '4' 4 | script: 5 | - npm run build 6 | - test -e public/index.html 7 | - test -e public/CNAME 8 | after_success: 9 | - if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then ./node_modules/.bin/git-update-ghpages -e; fi 10 | cache: 11 | directories: 12 | - node_modules 13 | addons: 14 | apt: 15 | sources: 16 | - ubuntu-toolchain-r-test 17 | packages: 18 | - g++-4.8 19 | env: 20 | global: 21 | - CXX: g++-4.8 22 | - GIT_NAME: Travis CI 23 | - GIT_EMAIL: nobody@nobody.org 24 | - GITHUB_REPO: rstacruz/devguides.io 25 | - GIT_SOURCE: public 26 | -------------------------------------------------------------------------------- /DRAFTS.md: -------------------------------------------------------------------------------- 1 | # Phoenix: i18n 2 | 3 | * The structure 4 | - priv/gettext/*.pot 5 | - priv/gettext/en/LC_MESSAGES/*.po 6 | - gettext("Hello, world") 7 | - gettext("Hello, %{name}", name: "Phoenix") 8 | 9 | * Updating PO files 10 | - mix gettext.extract --merge 11 | 12 | * Plurals 13 | - ngettext "%{count} apple", "%{count} apples", count 14 | -------------------------------------------------------------------------------- /NOTES.md: -------------------------------------------------------------------------------- 1 | Metalsmith 2 | ---------- 3 | 4 | This is a metalsmith website. Start a dev server like this: 5 | 6 | npm install 7 | npm start 8 | npm start -- --port 3005 9 | 10 | Examples 11 | -------- 12 | 13 | Embed an example using: 14 | 15 | 16 | 17 | Then create it as `redux/examples/simple.jade`. 18 | 19 | Each example has: 20 | 21 | - `external` (list) 22 | - `given` (list, required at least 0) 23 | - `examples` (list, required at least 1) 24 | 25 | Each `external` is a string to JavaScript URLs to be embedded. 26 | 27 | Each `given` item has: 28 | 29 | - `code` (required) 30 | - `hide` - if *true*, then it'll never be shown. 31 | 32 | Each `examples` item has: 33 | 34 | - `code` (required) 35 | - `placeholder` - Text to be shown before focus. Will be hljs highlighted. 36 | - `class` - CSS class name of the block. 37 | - `secret` - a hint text that's only shown after focus. 38 | - `auto` - if *true*, then the example output will be shown even before trying it. 39 | - `action` (default "Try") - the button text. 40 | 41 | Annotations 42 | ----------- 43 | 44 | You can use this inside code: 45 | 46 | - `/*...*/` - ellipsis 47 | - `/*[ foo ]*/ - placeholders 48 | - `//!` - warnings 49 | - `///` - checkmarks 50 | - `// <--` - arrows 51 | - `// -->` - arrows 52 | - `//=#` - results 53 | - `//+` - line highlight 54 | - `//-` - line mute 55 | - `// ---` - horiz rule 56 | - `/*{*/highlight/*}*/` - highlights 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Devguides.io 2 | 3 | Let me try to explain complicated things in simple ways. Every guide here follows a golden rule: every page must fit in a pocket-sized note. Great for viewing on mobile! 4 | 5 | **http://devguides.io** 6 | 7 | ## Thanks 8 | 9 | **devguides** © 2016-2017, Rico Sta. Cruz.
10 | Authored and maintained by Rico Sta. Cruz with help from contributors ([list][contributors]). 11 | 12 | > [ricostacruz.com](http://ricostacruz.com)  ·  13 | > GitHub [@rstacruz](https://github.com/rstacruz)  ·  14 | > Twitter [@rstacruz](https://twitter.com/rstacruz) 15 | 16 | [contributors]: http://github.com/rstacruz/pocket-explainer/contributors 17 | -------------------------------------------------------------------------------- /_notes/phoenix.md: -------------------------------------------------------------------------------- 1 | Phoenix Guides 2 | ============== 3 | 4 | Introduction 5 | ------------ 6 | 7 | - Installing Elixir 8 | - brew install erlang elixir 9 | - mix local.hex 10 | 11 | - Installing Node 12 | - brew install node.js 13 | 14 | - Installing Phoenix (-> mix) 15 | - mix archive.install http://... 16 | - mix --help 17 | 18 | - Start a project 19 | - mix phoenix.gen hello 20 | 21 | - Set up the database 22 | - vim config/dev.exs 23 | - mix ecto.create 24 | 25 | - Make a model (-> models) 26 | - mix phoenix.gen.html 27 | - mix ecto.migrate 28 | 29 | - Add a route (-> routes) 30 | - resources :document, DocumentController 31 | - mix routes 32 | 33 | - Inspect the controller (-> controllers) 34 | - Navigate to /documents 35 | - web/controllers/document_controller.rb 36 | 37 | - Edit some CSS (-> assets) 38 | - web/static && priv/static 39 | 40 | ## Pages 41 | 42 | Controllers and actions, views, templates 43 | 44 | - Try creating a page 45 | - mix phoenix.gen.html --no-model 46 | - list of files made 47 | 48 | - Routes 49 | - resources :document, DocumentController 50 | - document_path helpers 51 | 52 | ## Models 53 | 54 | - Ecto and stuff 55 | 56 | ## Routes 57 | 58 | ## Assets 59 | 60 | ## Migrations 61 | 62 | - Make your first migration 63 | - mix ecto.gen.migration add_document_fields 64 | - Run it 65 | - mix ecto.migrate 66 | 67 | ## Mix 68 | 69 | - What is mix 70 | -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | devguides.io 2 | -------------------------------------------------------------------------------- /docs/_layouts/base.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | meta(charset='utf-8') 5 | meta(name='viewport' content='width=device-width') 6 | link(rel='stylesheet' href=(base + '/assets/style.css')) 7 | if next 8 | link(rel='prefetch' href=next) 9 | link(rel='prerender' href=next) 10 | link(rel='next' href=next) 11 | title 12 | block title 13 | block head 14 | block body 15 | -------------------------------------------------------------------------------- /docs/_layouts/book.jade: -------------------------------------------------------------------------------- 1 | extends ./base.jade 2 | 3 | block title 4 | = title 5 | 6 | mixin content(chapters) 7 | .book-nav 8 | .nav-button 9 | 10 | .chapter-nav 11 | strong= title 12 | 13 | #body.markdown-body 14 | .cover-section 15 | .cover-front 16 | h5.chapter-prelude 17 | a.root(href='/') devguides.io 18 | span= ' / ' 19 | a.book(href='.')= title 20 | 21 | .space 22 | .cover-front-title 23 | p.prelude= prelude 24 | h1.title= title 25 | 26 | .space 27 | 28 | .cover-content 29 | .space 30 | block description 31 | 32 | .chapter-links 33 | each chapter in chapters 34 | if chapter.unavailable 35 | .chapter-link.-unavailable 36 | span 37 | strong.title= chapter.title 38 | span.description= chapter.description 39 | span.soon Coming soon 40 | else 41 | .chapter-link 42 | a(href=chapter.id) 43 | strong.title= chapter.title 44 | span.description= chapter.description 45 | .space 46 | 47 | script(src=(base + '/assets/common.min.js')) 48 | script(src=(base + '/assets/script.min.js')) 49 | include ./includes/analytics.jade 50 | -------------------------------------------------------------------------------- /docs/_layouts/chapter.jade: -------------------------------------------------------------------------------- 1 | extends ./base.jade 2 | 3 | block title 4 | = chapter + ' - ' + book 5 | 6 | block body 7 | body.-chapter 8 | .book-nav 9 | .nav-button 10 | 11 | .chapter-nav 12 | a(href='.')= book 13 | span= chapter 14 | 15 | #body(data-js-page-scroller) 16 | .markdown-body.-literate 17 | .page-section 18 | .container 19 | h5.chapter-prelude 20 | a.root(href='/') devguides.io 21 | span= ' / ' 22 | a.book(href='.')= book 23 | != contents 24 | 25 | script(src=(base + '/assets/common.min.js')) 26 | script(src=(base + '/assets/script.min.js')) 27 | include ./includes/analytics.jade 28 | -------------------------------------------------------------------------------- /docs/_layouts/example.jade: -------------------------------------------------------------------------------- 1 | extends ./base.jade 2 | 3 | block head 4 | script(src='https://cdn.rawgit.com/davidjbradshaw/iframe-resizer/v3.5.3/js/iframeResizer.contentWindow.min.js') 5 | 6 | mixin example-body(given, examples, external) 7 | if external 8 | each script in external 9 | script(src=script) 10 | 11 | body.-example 12 | each blk in examples 13 | .markdown-body.example-block(role='example' data-auto=(blk.auto ? 'true' : 'false') class=(blk.class || '')) 14 | .example-example(role='example-input') 15 | .code 16 | if blk.placeholder 17 | .placeholder(role='placeholder') 18 | pre 19 | code(class='language-js')= blk.placeholder 20 | textarea(style='display:none' spellcheck='false' role='code')= blk.code.trim() 21 | else 22 | textarea(spellcheck='false' role='code')= blk.code.trim() 23 | if blk.hint 24 | span.hint(role="hint")= blk.hint 25 | if blk.secret 26 | span.hint.-hide(role="hint")= blk.secret 27 | 28 | button.try(role='try') 29 | = blk.action ? blk.action : 'Try' 30 | 31 | .example-output.-hide(role='output') 32 | 33 | -// This will be moved inside example-example 34 | .example-givens.-hide(role='givens') 35 | -// h3 Context 36 | each blk in given 37 | .example-given(role='given' class=(blk.hide ? '-hide' : '')) 38 | textarea(spellcheck='false' role='code')= blk.code.trim() 39 | 40 | script(src=(base + '/assets/common.js')) 41 | script(src=(base + '/assets/example.js')) 42 | -------------------------------------------------------------------------------- /docs/_layouts/includes/analytics.jade: -------------------------------------------------------------------------------- 1 | script. 2 | if (window.location.hostname.indexOf('devguides.io') > -1) { 3 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','https://www.google-analytics.com/analytics.js','ga') 4 | ga('create', 'UA-79044901-1', 'auto') 5 | ga('send', 'pageview') 6 | } 7 | -------------------------------------------------------------------------------- /docs/_layouts/landing.jade: -------------------------------------------------------------------------------- 1 | extends ./base.jade 2 | 3 | block title 4 | = title 5 | 6 | mixin body-content() 7 | body.-landing 8 | if block 9 | block 10 | script(src=(base + '/assets/common.min.js')) 11 | script(src=(base + '/assets/script.min.js')) 12 | include ./includes/analytics.jade 13 | -------------------------------------------------------------------------------- /docs/assets/script.js: -------------------------------------------------------------------------------- 1 | require('../../lib/web') 2 | -------------------------------------------------------------------------------- /docs/assets/style.scss: -------------------------------------------------------------------------------- 1 | @import '../../sass/style.scss'; 2 | -------------------------------------------------------------------------------- /docs/es2015/classes.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: ES2015 4 | chapter: Classes 5 | next: strings 6 | --- 7 | 8 | # Classes 9 | 10 | You can now write classes in ES2015. Classes let you define your own object types. 11 | 12 | ```js 13 | /*{*/class Circle {/*}*/ 14 | constructor (radius) { 15 | this.radius = radius 16 | } 17 | getArea () { 18 | return Math.PI * 2 * this.radius 19 | } 20 | } 21 | ``` 22 | 23 | --- 24 | 25 | You create instances of classes using `new`. These instances have functions called *methods*, such as `getArea()` here. 26 | 27 | ```js 28 | c = new Circle(2) 29 | c.getArea() //=> 12.56 30 | ``` 31 | 32 | > Also see: [Classes (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) 33 | 34 | 35 | 36 | > Next: How do you define methods? [Next](#methods) 37 | 38 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 39 | 40 | # Methods 41 | 42 | You can write methods similar to the object function shorthand. Note that there are no commas, unlike objects! 43 | 44 | ```js 45 | class Circle { 46 | /*{*/getArea ()/*}*/ { 47 | return Math.PI * this.radius * this.radius 48 | } 49 | getCircumference () { //- 50 | return Math.PI * 2 * this.radius //- 51 | } //- 52 | } 53 | ``` 54 | 55 | ```js 56 | c = new Circle(2) 57 | c.getArea() //=> 12.56 58 | ``` 59 | 60 | > Also see: [Methods (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Prototype_methods) 61 | 62 | 63 | 64 | > Next: What about constructors? [Next](#constructors) 65 | 66 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 67 | 68 | # Constructors 69 | 70 | When you have a method with the name `constructor`, it will be called when doing `new YourClass(...)`. 71 | 72 | ```js 73 | class Circle { 74 | /*{*/constructor (radius) {/*}*/ 75 | this.radius = radius 76 | } 77 | } 78 | ``` 79 | 80 | ```js 81 | c = new Circle(10.5) 82 | c.radius //=> 10.5 83 | ``` 84 | 85 | > Also see: [Constructors (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/constructor) 86 | 87 | > Next: What about static methods? [Next](#static-methods) 88 | 89 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 90 | 91 | # Static methods 92 | 93 | You can define functions that can be called without instanciating it (calling `new YourClass`). These are called static methods. 94 | 95 | ```js 96 | class Circle { 97 | /*{*/static createFromDiameter (diameter) {/*}*/ 98 | return new Circle(diameter / 2) 99 | } 100 | } 101 | ``` 102 | 103 | ```js 104 | c = Circle.createFromDiameter(21) 105 | /// Same as `new Circle(10.5)` 106 | ``` 107 | 108 | > Next: Let's learn about inheritance. [Next](#inheritance) 109 | 110 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 111 | 112 | # Inheritance 113 | 114 | You can build on top of other classes using `extends`. This makes the methods of the parent class available in your class. 115 | 116 | ```js 117 | class Shape { 118 | show () { /*...*/ } 119 | hide () { /*...*/ } 120 | } 121 | // --- 122 | /*{*/class Circle extends Shape {/*}*/ 123 | roll () { /*...*/ } 124 | } 125 | // --- 126 | let c = new Circle() 127 | c.show() 128 | c.roll() 129 | ``` 130 | 131 | > Also see: [Sub classing (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Sub_classing_with_extends) 132 | 133 | 134 | 135 | > Next: How do I extend methods? [Continue](#compatibility) 136 | 137 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 138 | 139 | # Super 140 | 141 | If you use the same method name in a subclass, in overrides what's in the parent class. To call methods from a class's parent, use `super`. 142 | 143 | ```js 144 | class Logger { 145 | log (message) { 146 | console.log(message) 147 | } 148 | } 149 | // --- 150 | class ErrorLogger extends Logger { 151 | log (message) { 152 | /*{*/super/*}*/('Error: ' + message) 153 | } 154 | } 155 | ``` 156 | 157 | --- 158 | 159 | You can also use `super` for static methods, but it works a little differently. 160 | 161 | ```js 162 | static log (message) { 163 | /*{*/super.log/*}*/('Error: ' + message) 164 | } 165 | ``` 166 | 167 | > Also see: [super (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) 168 | 169 | 170 | 171 | > Next: Are all these backward-compatible? [Continue](#compatibility) 172 | 173 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 174 | 175 | # Compatibility 176 | 177 | Classes are simply syntactic sugar over ES5's prototypes. In fact, these two are equivalent. 178 | 179 | ```js 180 | class Circle { 181 | constructor (r) { this.radius = r } 182 | getDiameter () { return this.radius * 2 } 183 | } 184 | // --- 185 | function Circle (r) { this.radius = r } 186 | Circle.prototype.getDiameter = function () { return this.r * 2 } 187 | ``` 188 | 189 | --- 190 | 191 | You can both use them in the same way. 192 | 193 | ```js 194 | c = new Circle(20) 195 | ``` 196 | 197 | > Next: Let's recap what we've learned. [Next](#recap) 198 | 199 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 200 | 201 | # Recap 202 | 203 | ES2015 lets you write classes instead of dealing with prototypes. 204 | 205 | ```js 206 | class Circle extends Shape { 207 | constructor (radius) { 208 | this.radius = radius 209 | } 210 | 211 | /// Methods: 212 | getArea () { return Math.PI * 2 * this.radius } 213 | 214 | /// Static methods: 215 | static createFromDiameter (d) { return new Circle(d / 2) } 216 | } 217 | ``` 218 | 219 | ```js 220 | c = new Circle(10) 221 | c = Circle.createFromDiameter(20) 222 | c.getArea() 223 | ``` 224 | 225 | > Next: Let's learn about strings. [Next chapter](strings) 226 | -------------------------------------------------------------------------------- /docs/es2015/destructuring.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: ES2015 4 | chapter: Destructuring 5 | next: modules 6 | --- 7 | 8 | # Destructuring 9 | 10 | The new destructuring syntax lets you extract data from arrays and objects into their own variables. 11 | 12 | ```js 13 | const name = ['John', 'F', 'Kennedy'] 14 | const /*{*/[first, middle, last]/*}*/ = name 15 | 16 | console.log(first) //=> 'John' 17 | console.log(middle) //=> 'F' 18 | console.log(last) //=> 'Kennedy' 19 | ``` 20 | 21 | --- 22 | 23 | This works great for swapping variables! No need for temporary variables. 24 | 25 | ```js 26 | let [a, b] = [b, a] 27 | ``` 28 | 29 |
30 | Further reading... 31 | 32 | - [Destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) (Mozilla Developer Network) 33 |
34 | 35 | 36 | 37 | > Next: What if there's more than 3 items? [Next](#spread) 38 | 39 | * * * * 40 | 41 | # Spread 42 | 43 | You can use `...` to clump many arguments into on array. 44 | 45 | ```js 46 | const countries = ['USA', 'Canada', 'Portugal'] 47 | const [usa, /*{*/...others/*}*/] = countries 48 | 49 | console.log(usa) //=> 'USA' 50 | console.log(others) //=> ['Canada', 'Portugal'] 51 | ``` 52 | 53 | --- 54 | 55 | This works on the other side of `=` too! You can use the `...` syntax as part of an array literal. In fact, destructuring syntax was made so that they can be used as literals, too. 56 | 57 | ```js 58 | const people = [leader, ...members] 59 | ``` 60 | 61 |
62 | Further reading... 63 | 64 | - [Spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) (MDN) 65 |
66 | 67 | > Next: Let's try them on objects, too. [Next](#objects) 68 | 69 | * * * * 70 | 71 | # Objects 72 | 73 | Destructuring works for objects, too. 74 | 75 | ```js 76 | const album = { 77 | artist: 'Miles Davis', 78 | title: 'Kind of Blue' 79 | } 80 | 81 | const /*{*/{ artist, title }/*}*/ = album 82 | 83 | console.log(artist) //=> 'Miles Davis' 84 | console.log(album) //=> 'Kind of Blue' 85 | ``` 86 | 87 | --- 88 | 89 | ```js 90 | let a, b 91 | ({a, b} = {a:1, b:2}) 92 | ``` 93 | 94 | When used outside of `let` (or `var` or `const`), you'll need to wrap them in parentheses. 95 | 96 |
97 | Why parentheses? 98 | 99 | The parentheses prevents `{a, b}` from being treated as a block statement. This is the same rule that prevents `{hi: 'world'};` from being a valid JS statement. 100 |
101 | 102 |
103 | Further reading... 104 | 105 | - [Destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) (MDN) 106 |
107 | 108 | 109 | 110 | > Next: Let's use them outside assignments. [Next](#function-arguments) 111 | 112 | * * * * 113 | 114 | # Function arguments 115 | 116 | Destructuring also works in function arguments. It's not just for assignments! 117 | 118 | ```js 119 | function greet (/*{*/{name, greeting}/*}*/) { 120 | console.log(`${greeting}, ${name}!`) 121 | } 122 | 123 | greet({ greeting: 'Hello', name: 'John' }) 124 | //=> 'Hello, John!' 125 | ``` 126 | 127 | > Next: What if you want to change the name? [Next](#changing-names) 128 | 129 | * * * * 130 | 131 | # Changing names 132 | 133 | Your variables don't need to have the same name as the object keys. You can extract a property into a different name. 134 | 135 | ```js 136 | const name = { 137 | first: 'Sherlock', 138 | last: 'Holmes' 139 | } 140 | 141 | const { /*{*/first: firstName/*}*/ } = name 142 | console.log(firstName) //=> 'Sherlock' 143 | ``` 144 | 145 | 146 | 147 | > Next: Let's learn about default values. [Next](#default-values) 148 | 149 | * * * * 150 | 151 | # Default values 152 | 153 | Use the default value syntax to set defaults in case a property doesn't exist. 154 | 155 | ```js 156 | const song = { 157 | title: 'Across the Universe', 158 | artist: 'The Beatles' 159 | } 160 | 161 | const { /*{*/genre = 'Unknown'/*}*/ } = song 162 | 163 | console.log(genre) 164 | //=> 'Unknown' 165 | ``` 166 | 167 | > Next: What about objects inside objects? [Next](#deep-objects) 168 | 169 | * * * * 170 | 171 | # Deep objects 172 | 173 | You can go down into nested objects with destructuring, too. 174 | 175 | ```js 176 | const page = { 177 | uri: { domain: 'devguides.io', path: '/es2015' }, 178 | title: 'ES2015 guides' 179 | } 180 | 181 | const { uri: /*{*/{domain}/*}*/ } = page 182 | 183 | console.log(domain) 184 | //=> 'devguides.io' 185 | ``` 186 | 187 | > Next: Let's recap what we've learned. [Next](#recap) 188 | 189 | * * * * 190 | 191 | # Recap 192 | 193 | **Arrays** can be destructured. Spread (`...`) can be used when destructuring arrays. 194 | 195 | ```js 196 | const name = ['John', 'F', 'Kennedy'] //- 197 | const /*{*/[first, middle, last]/*}*/ = name 198 | const [first, /*{*/...others/*}*/] = name 199 | ``` 200 | 201 | --- 202 | 203 | **Objects** can be destructured. You can even assign them to new names. 204 | 205 | ```js 206 | const name = { first: 'Jon', last: 'Snow' } //- 207 | const /*{*/{ first, last }/*}*/ = name 208 | const /*{*/{ first: firstName }/*}*/ = name 209 | ``` 210 | 211 | --- 212 | 213 | **Function arguments** can also be destructured. 214 | 215 | ```js 216 | function greet (/*{*/{name, greeting}/*}*/) { 217 | console.log(`${greeting}, ${name}!`) //- 218 | } //- 219 | ``` 220 | 221 | > Next: Let's learn about import and export. [Next chapter](modules) 222 | -------------------------------------------------------------------------------- /docs/es2015/examples/functions-short.jade: -------------------------------------------------------------------------------- 1 | --- 2 | given: 3 | - code: | 4 | let list = [4, 9, 16, 25, 36] 5 | examples: 6 | - code: | 7 | list.map(n => Math.sqrt(n)) 8 | --- 9 | extends ../../_layouts/example.jade 10 | block body 11 | +example-body(given, examples, external) 12 | -------------------------------------------------------------------------------- /docs/es2015/examples/variables-const.jade: -------------------------------------------------------------------------------- 1 | --- 2 | given: [] 3 | examples: 4 | - auto: true 5 | secret: | 6 | Hint: try changing 'const' to 'let'. 7 | placeholder: | 8 | const name = 'John' 9 | name = name.toUpperCase() //! 10 | code: | 11 | const name = 'John' 12 | name = name.toUpperCase() 13 | console.log(name) 14 | --- 15 | extends ../../_layouts/example.jade 16 | block body 17 | +example-body(given, examples, external) 18 | -------------------------------------------------------------------------------- /docs/es2015/examples/variables-let.jade: -------------------------------------------------------------------------------- 1 | --- 2 | given: [] 3 | examples: 4 | - auto: true 5 | placeholder: | 6 | function greet (user) { 7 | if (user.gender === 'male') { 8 | let fullname = 'Mr. ' + user.name 9 | } else { 10 | let fullname = 'Ms. ' + user.name 11 | } 12 | console.log('Hello, ' + fullname) //! 13 | } 14 | 15 | greet({ name: 'John', gender: 'male' }) 16 | code: | 17 | function greet (user) { 18 | if (user.gender === 'male') { 19 | let fullname = 'Mr. ' + user.name 20 | } else { 21 | let fullname = 'Ms. ' + user.name 22 | } 23 | console.log('Hello, ' + fullname) 24 | } 25 | 26 | greet({ name: 'John', gender: 'male' }) 27 | 28 | - secret: | 29 | We can fix this by placing 'let' on a higher scope. 30 | class: '-discreet' 31 | placeholder: | 32 | // --> Click here for solution 33 | code: | 34 | function greet (user) { 35 | let fullname 36 | if (user.gender === 'male') { 37 | fullname = 'Mr. ' + user.name 38 | } else { 39 | fullname = 'Ms. ' + user.name 40 | } 41 | console.log('Hello, ' + fullname) 42 | } 43 | 44 | greet({ name: 'John', gender: 'male' }) 45 | --- 46 | extends ../../_layouts/example.jade 47 | block body 48 | +example-body(given, examples, external) 49 | -------------------------------------------------------------------------------- /docs/es2015/examples/variables-scoping.jade: -------------------------------------------------------------------------------- 1 | --- 2 | given: [] 3 | examples: 4 | - auto: true 5 | placeholder: | 6 | let msg = 'hi' 7 | if (true) { 8 | let msg = 'hello' 9 | } 10 | console.log(msg) 11 | code: | 12 | let msg = 'hi' 13 | if (true) { 14 | let msg = 'hello' 15 | } 16 | console.log(msg) 17 | --- 18 | extends ../../_layouts/example.jade 19 | block body 20 | +example-body(given, examples, external) 21 | -------------------------------------------------------------------------------- /docs/es2015/functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: ES2015 4 | chapter: Functions 5 | next: destructuring 6 | --- 7 | 8 | # Arrow functions 9 | 10 | In ES2015, you can now write functions with the `=>` syntax, known as arrow functions. 11 | 12 | ```js 13 | const greet = (name) => { 14 | console.log(`Hello, ${name}`) 15 | } 16 | ``` 17 | 18 | --- 19 | 20 | For the most part, that's is the same as these examples that you would write in ES5. 21 | 22 | ```js 23 | var greet = function (name) { 24 | console.log('Hello, ' + name) 25 | } 26 | // --- 27 | function greet (name) { 28 | console.log('Hello, ' + name) 29 | } 30 | ``` 31 | 32 | > Next: But what makes them different? [Next](#this) 33 | 34 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 35 | 36 | # This 37 | 38 | When using `this` inside arrow functions, they take whatever's the value of `this` from its parent scope. 39 | 40 | ```js 41 | addItems: function (items) { 42 | this.show() 43 | items.forEach((item) => { 44 | /*{*/this/*}*/.append(item) 45 | }) 46 | } 47 | ``` 48 | 49 | In this example, both instances of `this` refer to the same object. 50 | 51 | --- 52 | 53 | In ES5, you may have worked around this by keeping track of `this` yourself. If you didn't, `this.append()` will likely throw an error. 54 | 55 | 56 | ```js 57 | addItems: function (items) { 58 | this.show() 59 | /*{*/var self = this/*}*/ 60 | items.forEach(function (item) { 61 | /*{*/self/*}*/.append(item) /// 62 | // --> Without arrow functions, `this` means something else here. 63 | // --> We're using another variable to preserve the previous `this`. 64 | }) 65 | } 66 | ``` 67 | 68 | > Also see: [Lexical this (Babel)](http://babeljs.io/docs/learn-es2015/#arrows) 69 | 70 | 71 | 72 | > Next: How else are arrow functions useful? [Next](#short-syntax) 73 | 74 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 75 | 76 | # Short syntax 77 | 78 | You can omit the curly braces. If you do, it implicitly returns the expression after the arrow. 79 | All these lines do the same thing. 80 | 81 | 82 | 83 | ```js 84 | list.map(n => /*{*/{ return/*}*/ Math.sqrt(n) /*{*/}/*}*/) 85 | list.map(function (n) { return Math.sqrt(n) }) 86 | ``` 87 | 88 | > Useful for functions like `map` and `reduce`. 89 | 90 | --- 91 | 92 | You may have noticed we omitted the parentheses as well. You can do this if your function only takes in one argument. It makes no difference. 93 | 94 | ```js 95 | /// These two are the same. 96 | list.map(n => Math.sqrt(n)) 97 | list.map(/*{*/(n)/*}*/ => Math.sqrt(n)) 98 | ``` 99 | 100 | ```js 101 | //! It only works if you have 1 argument. 102 | list.reduce((a, b) => a + b) 103 | list.reduce(a, b => a + b) //! Error 104 | ``` 105 | 106 | 107 | 108 | 109 | > Next: What else is it useful for? [Next](#currying) 110 | 111 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 112 | 113 | # Currying 114 | 115 | You can take advantage of the short syntax to return functions. This is often called *currying.* In this example, we make a function, that returns a function, that returns a function. 116 | 117 | ```js 118 | const logger = next => dispatch => action => { 119 | dispatch(action) 120 | } 121 | // --- 122 | logger(next)(store.dispatch)({ type: 'init' }) 123 | ``` 124 | 125 | > This is how [Redux middleware](../redux/middleware) are built. 126 | 127 | 128 | 129 | > Next: Set default arguments. [Next](#default-arguments) 130 | 131 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 132 | 133 | # Default arguments 134 | 135 | You can now define defaults for arguments that are omitted. 136 | 137 | ```js 138 | function greet(/*{*/name = "Jerry"/*}*/) { 139 | return `Hello ${name}`; 140 | } 141 | // --- 142 | greet() //=> "Hello, Jerry" 143 | greet("Kyle") //=> "Hello, Kyle" 144 | ``` 145 | 146 | > Next: Let's write functions with multiple arguments. [Next](#rest-and-spread) 147 | 148 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 149 | 150 | # Rest and spread 151 | 152 | Write functions that take in multiple arguments by using the *rest* syntax. 153 | 154 | ```js 155 | function greet(/*{*/...names/*}*/) { 156 | return `Hello ${names.join(', ')}!`; 157 | } 158 | // --- 159 | greet('Moe', 'Larry', 'Curly') /// Hello Moe, Larry, Curly! 160 | ``` 161 | 162 | --- 163 | 164 | Similarly, you can call functions with an array of arguments by using the *spread* syntax. 165 | 166 | ```js 167 | let names = ['Moe', 'Larry', 'Curly'] 168 | // --- 169 | greet(/*{*/...names/*}*/) /// same as: `greet('Moe', 'Larry', 'Curly')` 170 | ``` 171 | 172 | > See also: [Spread operator (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) 173 | 174 | 175 | 176 | > Next: Let's recap what we've learned. [Next](#recap) 177 | 178 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 179 | 180 | # Recap 181 | 182 | **Default, rest, and spread** make dynamic arguments easier. 183 | 184 | ```js 185 | function greet(/*{*/name = "Jerry"/*}*/) { /*...*/ } 186 | function greet(/*{*/...names/*}*/) { /*...*/ } 187 | // --- 188 | greet(/*{*/...names/*}*/) 189 | ``` 190 | 191 | --- 192 | 193 | **Arrow functions** preserve the lexical `this`. 194 | 195 | ```js 196 | list.forEach(item => { 197 | this.addItem(item) 198 | }) 199 | ``` 200 | 201 | --- 202 | 203 | Omit the curly braces for short functions. 204 | 205 | ```js 206 | list.map(n => Math.PI * Math.sqrt(n)) 207 | ``` 208 | 209 | > Next: Let's learn about destructuring. [Next chapter](destructuring) 210 | -------------------------------------------------------------------------------- /docs/es2015/index.jade: -------------------------------------------------------------------------------- 1 | --- 2 | title: ES2015 3 | prelude: Introduction to 4 | next: variables 5 | chapters: 6 | - id: overview 7 | title: Overview 8 | description: Overview of new features 9 | - id: variables 10 | title: Variables 11 | description: About let, const, and block scoping 12 | - id: objects 13 | title: Objects 14 | description: New shorthand for objects 15 | - id: classes 16 | title: Classes 17 | description: An alternative to prototypes 18 | - id: strings 19 | title: Strings 20 | description: New string syntax for ES2015 21 | - id: functions 22 | title: Functions 23 | description: All about arrow functions 24 | - id: destructuring 25 | title: Destructuring 26 | description: Shorthand for accessing properties 27 | - id: modules 28 | title: Modules 29 | description: All about import and export 30 | - id: generators 31 | title: Generators 32 | description: Functions that can be paused 33 | unavailable: true 34 | --- 35 | extends ../_layouts/book.jade 36 | 37 | block description 38 | :markdown-it 39 | ES2015, previously called ES6, is the new version of JavaScript. It's supported by Node.js and modern browsers. Older browsers such as IE and iOS Safari will have to rely on [Babel](http://babeljs.io), a compiler that converts ES2015 to ES5 code. 40 | 41 | block body 42 | body.-book 43 | +content(chapters) 44 | -------------------------------------------------------------------------------- /docs/es2015/modules.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: ES2015 4 | chapter: Modules 5 | # next: objects 6 | --- 7 | 8 | # Modules 9 | 10 | Use `import` as a substitute for *require()*. These two lines do the same thing in most cases. 11 | 12 | ```js 13 | var fs = require('fs') // --> ES5 14 | import fs from 'fs' /// ES2015 15 | ``` 16 | 17 | > Next: How can we import many things from a module? [Next](#destructuring) 18 | 19 | * * * * 20 | 21 | # Destructuring 22 | 23 | You can also extract certain things from a module using [destructuring](destructuring). 24 | 25 | ```js 26 | var readFile = require('fs').readFile // --> ES5 27 | import { readFile } from 'fs' /// ES2015 28 | ``` 29 | 30 | --- 31 | 32 | You can also use the *assign to new name* destructuring syntax to extract things into new names. 33 | 34 | ```js 35 | var openFile = require('fs').openFile // --> ES5 36 | import { open: openFile } from 'fs' /// ES2015 37 | ``` 38 | 39 | > Next: Let's learn about hoisting. [Next](#hoisting) 40 | 41 | * * * * 42 | 43 | # Hoisting 44 | 45 | If `import` appears on the top-level, but not at the top, they will be *hoisted* to the top. 46 | 47 | ```js 48 | console.log(util.inspect('hello')) 49 | import util from 'util' 50 | // --- 51 | // -- This will work as if the `import` was placed on top. 52 | ``` 53 | 54 | --- 55 | 56 | `import` can't be used inside a block (like a function), unlike *require()*. 57 | 58 | ```js 59 | function openFile (file) { //- 60 | import fs from 'fs' //! 61 | return fs.readFileSync(file) //- 62 | } //- 63 | 64 | // --- 65 | //! Error: 'import' and 'export' may only appear at the top level. 66 | ``` 67 | 68 | > Next: How can we export? [Next](#exporting) 69 | 70 | * * * * 71 | 72 | # Exporting 73 | 74 | Use `export default` as a substitute for assigning to `module.exports`. 75 | 76 | ```js 77 | function start () { //- 78 | return 'Starting engines...' //- 79 | } //- 80 | 81 | module.exports = start // --> ES5 82 | export default start /// ES2015 83 | ``` 84 | 85 | --- 86 | 87 | You can also export inline function definitions. 88 | In fact, you can export any expression, not just functions! 89 | 90 | ```js 91 | export default function () { 92 | return 'hello' 93 | } 94 | ``` 95 | 96 | ```js 97 | export default { 98 | name: 'devguides', 99 | version: '1.0.0' 100 | } 101 | ``` 102 | 103 | > Next: How can we export many things from one module? [Next](#named-exports) 104 | 105 | * * * * 106 | 107 | # Named exports 108 | 109 | You can have as many named exports in a module.
110 | Use `export function` to export functions.
111 | Use `export var` to export variables. 112 | 113 | ```js 114 | /*{*/export function start () {/*}*/ 115 | return 'Vroom!' //- 116 | } 117 | // --- 118 | /*{*/export var/*}*/ version = '1.0.0' 119 | ``` 120 | 121 | --- 122 | 123 | You can then import named exports by the [destructuring](destructuring) syntax. 124 | 125 | ```js 126 | import { start, version } from './engine' 127 | 128 | // --> You can also assign different names: 129 | import { start as engineStart } from './engine' 130 | ``` 131 | 132 | Try not to mix `default` exports and named exports! Let's find out why in the next section. 133 | 134 | > Next: Can we mix this with `export default`? [Next](#mixing-exports) 135 | 136 | * * * * 137 | 138 | # Mixing exports 139 | 140 | You can mix `default` exports with named exports, but there are caveats. 141 | 142 | ```js 143 | export default function () { 144 | /*...*/ 145 | } 146 | 147 | export function start () { 148 | /*...*/ 149 | } 150 | ``` 151 | 152 | --- 153 | 154 | __With a default export:__ Doing `import X from` will fetch the default export if it's available. 155 | 156 | ```js 157 | import Engine from './engine' // --> Yields `[Function]` 158 | import { start } from './engine' 159 | ``` 160 | 161 | --- 162 | 163 | __Without a default export:__ Doing `import X from` will result in an error. 164 | 165 | ```js 166 | import Engine from './engine' //! Error 167 | ``` 168 | 169 | --- 170 | 171 | This is different from CommonJS's `require()`! To emulate this behavior with require, you need to do this: 172 | 173 | ```js 174 | // --> ES5 equivalent: 175 | var Engine = require('./engine').default 176 | var start = require('./engine').start 177 | // --- 178 | //! This has no ES2016 equivalent: 179 | var start = require('./engine') 180 | ``` 181 | 182 |
183 | Further reading... 184 | 185 | - [Difference between default and named exports](http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281) *(Stack Overflow)* 186 |
187 | 188 | > Next: Let's recap what we've learned. [Next](#recap) 189 | 190 | * * * * 191 | 192 | # Recap 193 | 194 | `import` is the new `require()`. 195 | 196 | ```js 197 | import fs from 'fs' 198 | var fs = require('fs') //- 199 | ``` 200 | 201 | ```js 202 | import { readFile } from 'fs' 203 | var readFile = require('fs').readFile //- 204 | ``` 205 | 206 | --- 207 | 208 | `export` is the new `module.exports`. You can export `default`, `function`, or `var`. 209 | 210 | ```js 211 | export default start 212 | module.exports = start //- 213 | ``` 214 | 215 | ```js 216 | export function start () { /*...*/ } 217 | export var PI = 3.14159 218 | 219 | 220 | exports.start = function () { ... } //- 221 | exports.PI = 3.14159 //- 222 | ``` 223 | 224 | --- 225 | 226 | When mixing `export default` with other exports, `import` will fetch the default export. This different from the `require()` behavior. 227 | 228 | ```js 229 | import Engine from './engine' // --> Gets `export default` 230 | import { start } from './engine' // --> Gets `export function` 231 | 232 | 233 | var Engine = //- 234 | require('./engine').default || //- 235 | require('./engine') //- 236 | ``` 237 | 238 | > Next: That's all for now! [Back](.) 239 | -------------------------------------------------------------------------------- /docs/es2015/objects.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: ES2015 4 | chapter: Objects 5 | next: classes 6 | --- 7 | 8 | # Objects 9 | 10 | ES2015 offers some shorthand for writing object 11 | [Names](#name-shorthand), 12 | [Functions](#functions-shorthand), 13 | [Getters and setters](#getters-and-setters), and 14 | [Computed name](#computed-names) properties. 15 | 16 | ```js 17 | App = { 18 | /*{*/handler/*}*/, 19 | 20 | // --> Functions: 21 | /*{*/start ()/*}*/ { return this.go() }, 22 | 23 | // --> Getters and setters: 24 | /*{*/get closed ()/*}*/ { return this.status === 'closed' }, 25 | /*{*/set closed (val)/*}*/ { this.status = val ? 'closed' : 'open' }, 26 | 27 | // --> Computed properties: 28 | /*{*/[ 'prop_' + n ]/*}*/: 42 29 | } 30 | ``` 31 | 32 | > Next: What's `handler` up there mean? [Next](#name-shorthand) 33 | 34 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 35 | 36 | # Name shorthand 37 | 38 | Ever type `{ foo: foo }` and find it repetitive? This is common when writing exports. You can now shorten this in ES2015. 39 | 40 | 41 | ```js 42 | module.exports = { 43 | /*{*/update: update/*}*/, 44 | save: save 45 | } 46 | // --- 47 | module.exports = { /*{*/update/*}*/, save } 48 | ``` 49 | 50 | > `update` rolls out into `update: update`. 51 | 52 | --- 53 | 54 | You can use this shorthand anywhere in a `{...}` object. 55 | 56 | ```js 57 | module.exports = { /*{*/update/*}*/, save, create: createItem } 58 | ``` 59 | 60 | > Next: You can shorten functions, too. [Next](#function-shorthand) 61 | 62 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 63 | 64 | # Function shorthand 65 | 66 | JavaScript lets you define properties as functions. You can now shorten this in ES2015. 67 | 68 | ```js 69 | App = { 70 | /*{*/start: function () { /*...*/ }/*}*/ 71 | } 72 | // --- 73 | App = { 74 | /*{*/start ()/*}*/ { /*...*/ } 75 | } 76 | // --- 77 | App.start() 78 | ``` 79 | 80 | > Next: Learn about getters and setters. [Next](#getters-and-setters) 81 | 82 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 83 | 84 | # Getters and setters 85 | 86 | Apart from function shorthands, you can define special attributes that do something when read or set. 87 | 88 | ```js 89 | Shop = { 90 | /*{*/get closed ()/*}*/ { 91 | return this.status === 'closed' 92 | }, 93 | /*{*/set closed (value)/*}*/ { 94 | this.status = value ? 'closed' : 'open' 95 | } 96 | } 97 | // --- 98 | Shop.closed = true // --> invokes `set closed()` 99 | Shop.status // --> `'closed'` 100 | Shop.closed // --> `true` (invokes `get closed()`) 101 | ``` 102 | 103 | > Also see: [get (MDN)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) 104 | 105 | 106 | 107 | > Next: Learn about writing dynamic property names. [Next](#computed-names) 108 | 109 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 110 | 111 | # Computed names 112 | 113 | You can write properties with key names derived from expressions. 114 | 115 | ```js 116 | let id = 'john' 117 | let Users = { /*{*/[id]/*}*/: "John Frobisher" } 118 | // --- 119 | Users.john //=> "John Frobisher" 120 | ``` 121 | 122 | --- 123 | 124 | You would've written it like the long way in ES5: 125 | 126 | ```js 127 | var id = 'john' 128 | var Users = {} 129 | Users[id] = "John Frobisher" 130 | ``` 131 | 132 | --- 133 | 134 | This works with the other function shorthands, too. This example creates a function `gettitle()`. 135 | 136 | ```js 137 | var key = 'title' 138 | App = { 139 | /*{*/['get' + key]()/*}*/ { return this[key] } 140 | } 141 | ``` 142 | 143 | > Next: Let's recap what we've learned. [Next](#recap) 144 | 145 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 146 | 147 | # Recap 148 | 149 | ES2015 offers some shorthand for writing object 150 | [Names](#name-shorthand), 151 | [Functions](#functions-shorthand), 152 | [Getters and setters](#getters-and-setters), and 153 | [Computed name](#computed-names) properties. 154 | 155 | ```js 156 | App = { 157 | /*{*/handler/*}*/, 158 | 159 | // --> Functions: 160 | /*{*/start ()/*}*/ { return this.go() }, 161 | 162 | // --> Getters and setters: 163 | /*{*/get closed ()/*}*/ { return this.status === 'closed' }, 164 | /*{*/set closed (val)/*}*/ { this.status = val ? 'closed' : 'open' }, 165 | 166 | // --> Computed names: 167 | /*{*/[ 'prop_' + n ]/*}*/: 42 168 | } 169 | ``` 170 | 171 | > Next: Let's learn about classes. [Next chapter](classes) 172 | -------------------------------------------------------------------------------- /docs/es2015/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: ES2015 4 | chapter: Overview 5 | next: variables 6 | --- 7 | 8 | # ES2015 9 | 10 | Here's an overview of what's new with ES2015, previously known as ES6. 11 | 12 | > Next: See what's new with variables. [Next](#variables) 13 | 14 | * * * * 15 | 16 | # Variables 17 | 18 | __Block scoping:__ `let` is the new `var`. These variables are only available in their respective blocks. 19 | [#](variables) 20 | 21 | ```js 22 | function fn () { 23 | /*{*/let x = 0/*}*/ 24 | if (true) { 25 | /*{*/let x = 1/*}*/ /*[ only inside this `if` ]*/ 26 | } 27 | } 28 | ``` 29 | 30 | ---- 31 | 32 | __Constants__ are variables that you can't modify. 33 | [#](variables#constants) 34 | 35 | ```js 36 | /*{*/const DAY = 86400/*}*/ 37 | ``` 38 | 39 |
40 | Further reading... 41 | 42 | See the [ES2015: variables](variables) guide. 43 |
44 | 45 | 46 | 47 | > Next: Learn about template strings. [Next](#strings) 48 | 49 | * * * * 50 | 51 | # Strings 52 | 53 | __Template strings__ are surrounded by backticks. You can do interpolation with them. 54 | [#](strings) 55 | 56 | ```js 57 | var message = /*{*/`Hello ${name}`/*}*/ 58 | ``` 59 | 60 | ---- 61 | 62 | __Multiline__ strings are also supported through backticks. 63 | [#](strings) 64 | 65 | ```js 66 | console.log(` 67 | Usage: 68 | parse-csv [file] 69 | 70 | Parses a CSV file. 71 | `) 72 | ``` 73 | 74 |
75 | Further reading... 76 | 77 | Learn more at the [ES2015: Strings](strings) guide. 78 |
79 | 80 | > Next: Write objects easier. [Next](#objects) 81 | 82 | * * * * 83 | 84 | # Objects 85 | 86 | __New shorthand:__ there are now shorter syntaxes for getters, setters, and methods. 87 | [#](objects) 88 | 89 | ```js 90 | App = { 91 | // --> Functions: 92 | /*{*/start ()/*}*/ { return this.go() }, 93 | 94 | // --> Getters and setters: 95 | /*{*/get closed ()/*}*/ { return this.status === 'closed' }, 96 | /*{*/set closed (val)/*}*/ { this.status = val ? 'closed' : 'open' }, 97 | } 98 | ``` 99 | 100 | --- 101 | 102 | __Same-name properties__ also get a new shorthand. 103 | [#](objects#name-shorthand) 104 | 105 | ```js 106 | // --> Short for `{ start: start, reset: reset }` 107 | module.exports = /*{*/{ start, reset }/*}*/ 108 | ``` 109 | 110 | --- 111 | 112 | __Computed property names__ let you make dynamic names. 113 | [#](objects#computed-names) 114 | 115 | ```js 116 | return { 117 | /*{*/[ 'prop_' + n ]/*}*/: 42 118 | } 119 | ``` 120 | 121 |
122 | Further reading... 123 | 124 | Learn more at the [ES2015: Objects](objects) guide. 125 |
126 | 127 | > Next: See new function features. [Next](#functions) 128 | 129 | * * * * 130 | 131 | # Functions 132 | 133 | __Default, rest and spread__ make dynamic arguments easier. 134 | [#](functions#default-arguments) 135 | [#](functions#rest-and-spread) 136 | 137 | ```js 138 | function greet(/*{*/name = "Jerry"/*}*/) { /*...*/ } 139 | function greet(/*{*/...names/*}*/) { /*...*/ } 140 | // --- 141 | greet(/*{*/...names/*}*/) 142 | ``` 143 | 144 | --- 145 | 146 | __Arrow functions__ preserve the lexical `this`. 147 | [#](functions) 148 | 149 | ```js 150 | list.forEach(/*{*/item => {/*}*/ 151 | this.addItem(item) 152 | /*{*/}/*}*/) 153 | ``` 154 | 155 | --- 156 | 157 | __Short functions:__ Omit the curly braces for short functions. 158 | [#](functions#short-syntax) 159 | 160 | ```js 161 | list.map(/*{*/n => Math.PI * Math.sqrt(n)/*}*/) 162 | ``` 163 | 164 |
165 | Further reading... 166 | 167 | Learn more at the [ES2015: Functions](functions) guide. 168 |
169 | 170 | > Next: Write classes, not prototypes. [Next](#classes) 171 | 172 | * * * * 173 | 174 | # Classes 175 | 176 | ES2015 lets you write classes instead of dealing with prototypes. 177 | [#](classes) 178 | 179 | ```js 180 | /*{*/class Circle extends Shape {/*}*/ 181 | constructor (radius) { 182 | this.radius = radius 183 | } 184 | 185 | // --> Methods: 186 | getArea () { return Math.PI * 2 * this.radius } 187 | 188 | // --> Static methods: 189 | static createFromDiameter (d) { return new Circle(d / 2) } 190 | } 191 | ``` 192 | 193 | ```js 194 | c = new Circle(10) 195 | c = Circle.createFromDiameter(20) 196 | c.getArea() 197 | ``` 198 | 199 |
200 | Further reading... 201 | 202 | Learn more at the [ES2015: Classes](classes) guide. 203 |
204 | 205 | > Next: Extract variables through destructuring. [Next](#destructuring) 206 | 207 | * * * * 208 | 209 | # Destructuring 210 | 211 | __Arrays__ can be destructured. The spread operator can be used when destructuring arrays. 212 | [#](destructuring) 213 | 214 | ```js 215 | const name = ['John', 'F', 'Kennedy'] //- 216 | const /*{*/[first, middle, last]/*}*/ = name 217 | const [first, /*{*/...others/*}*/] = name 218 | ``` 219 | 220 | --- 221 | 222 | __Objects__ can be destructured. You can even assign them to new names. 223 | [#](destructuring#objects) 224 | 225 | ```js 226 | const name = { first: 'Jon', last: 'Snow' } //- 227 | const /*{*/{ first, last }/*}*/ = name 228 | const /*{*/{ first: firstName }/*}*/ = name 229 | ``` 230 | 231 | --- 232 | 233 | [Function arguments](destructuring#function-arguments) can also be destructured. 234 | 235 | ```js 236 | function greet (/*{*/{name, greeting}/*}*/) { 237 | console.log(`${greeting}, ${name}!`) //- 238 | } //- 239 | ``` 240 | 241 |
242 | Further reading... 243 | 244 | Learn more at the [ES2015: Destructuring](destructuring) guide. 245 |
246 | 247 | 248 | 249 | > Next: Let's learn about importing and exporting. [Next](#modules) 250 | 251 | * * * * 252 | 253 | # Modules 254 | 255 | [import](modules) is the new `require()`. 256 | 257 | ```js 258 | import fs from 'fs' 259 | var fs = require('fs') //- 260 | ``` 261 | 262 | ```js 263 | import { readFile } from 'fs' 264 | var readFile = require('fs').readFile //- 265 | ``` 266 | 267 | --- 268 | 269 | [export](modules#exporting) is the new `module.exports`. You can export `default`, `function`, or `var`. 270 | 271 | ```js 272 | export default start 273 | module.exports = start //- 274 | ``` 275 | 276 | ```js 277 | export function start () { /*...*/ } 278 | export var PI = 3.14159 279 | 280 | 281 | exports.start = function () { ... } //- 282 | exports.PI = 3.14159 //- 283 | ``` 284 | 285 | --- 286 | 287 | When mixing `export default` with other exports, `import` will fetch the default export. [This is different](modules#named-exports) from the `require()` behavior. 288 | 289 | ```js 290 | import Engine from './engine' // <-- Gets `export default` 291 | import { start } from './engine' // <-- Gets `export function` 292 | 293 | 294 | var Engine = require('./engine').default || require('./engine') //- 295 | ``` 296 | 297 |
298 | Further reading... 299 | 300 | Learn more at the [ES2015: Modules](modules) guide. 301 |
302 | 303 | > Next: See what's new with variables. [Next chapter](variables) 304 | -------------------------------------------------------------------------------- /docs/es2015/strings.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: ES2015 4 | chapter: Strings 5 | next: functions 6 | --- 7 | 8 | # Template strings 9 | 10 | You can use `${...}` to add expressions inside strings. To do this, surround your string with backticks. 11 | 12 | ```js 13 | var message = `Hello ${name}` 14 | ``` 15 | 16 | --- 17 | 18 | Template strings are also used for multi-line strings. 19 | 20 | ```js 21 | var help = ` 22 | Usage: 23 | $0 [options] [files...] 24 | ` 25 | ``` 26 | 27 | > Next: Why is it called a "template"? [Next](#tagged-templates) 28 | 29 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 30 | 31 | # Tagged templates 32 | 33 | Template strings can be "tagged" by putting a function before it. 34 | 35 | ```js 36 | tpl `hello ${name}! I'm ${me}` 37 | ``` 38 | 39 | --- 40 | 41 | `tpl` is a function you write. It will be invoked like so. 42 | While this is not used very often, it lets us write things like template engines. 43 | 44 | ```js 45 | function tpl (strings, values) { 46 | strings //=> ['hello ', "! I'm", ''] 47 | values //=> [name, me] 48 | } 49 | ``` 50 | 51 |
52 | Further reading... 53 | 54 | - [Tagged template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals) *(Mozilla Developer Network)* 55 |
56 | 57 | 58 | 59 | > Next: Let's learn about what's new with functions. [Next chapter](functions) 60 | -------------------------------------------------------------------------------- /docs/es2015/variables.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: ES2015 4 | chapter: Variables 5 | next: objects 6 | --- 7 | 8 | # Let 9 | 10 | `let` works just like `var`. In most cases, you can use `let` instead of var. 11 | 12 | ```js 13 | function greet (user) { 14 | /*{*/let name = user.name/*}*/ 15 | console.log('Hello, ' + name) 16 | } 17 | ``` 18 | 19 | > Next: But what makes it different? [Next](#let-vs-var) 20 | 21 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 22 | 23 | # let vs. var 24 | 25 | A `let` is only available inside the `{ ... }` block they're in. 26 | In this example, the `name`s are only available inside their respective *if* and *else* blocks. 27 | 28 | 29 | 30 |
31 | Further reading... 32 | 33 | - [Block scope](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let) *(Mozilla Developer Network)* 34 |
35 | 36 | > Next: Learn about `let`'s cousin. [Next](#constants) 37 | 38 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 39 | 40 | # Constants 41 | 42 | `const` is just like *let*, except you can't reassign it to a new value. 43 | Most guides now recommend using *let* and *const* instead of `var`. 44 | 45 | 46 | 47 |
48 | Further reading... 49 | 50 | - [Constants](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) *(Mozilla Developer Network)* 51 |
52 | 53 | > Next: What is block scoping? [Next](#block-scoping) 54 | 55 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 56 | 57 | # Block scoping 58 | 59 | `let` and `const` are said to be *block scoping.* In JavaScript, a block is code inside `{` and `}`. These variables are only available inside their blocks. 60 | 61 | 62 | 63 | --- 64 | 65 | Block scoping affects other kinds of blocks. 66 | 67 | ```js 68 | function greet () { /*...*/ } 69 | if (hidden) { /*...*/ } 70 | else { /*...*/ } 71 | try { /*...*/ } 72 | catch (e) { /*...*/ } 73 | finally { /*...*/ } 74 | switch (state) { /*...*/ } 75 | for (;;) { /*...*/ } 76 | while (true) { /*...*/ } 77 | ``` 78 | 79 |
80 | Further reading... 81 | 82 | - [Block statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/block) *(Mozilla Developer Network)* 83 |
84 | 85 | > Next: What about blocks inside blocks? [Next](#nested-blocks) 86 | 87 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 88 | 89 | # Nested blocks 90 | 91 | Variables defined using `let` and `const` are available only inside `{...}` blocks, and other blocks inside them. 92 | 93 | ```js 94 | function run (user) { 95 | if (user) { 96 | /*{*/let running = user.state === 'running'/*}*/ 97 | if (running) { 98 | /// `running` is still available here 99 | } else { 100 | /// and here, too 101 | } 102 | } else { 103 | //! but not here! 104 | } 105 | } 106 | ``` 107 | 108 | > Next: Learn recap what we've learned. [Next](#recap) 109 | 110 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 111 | 112 | # Recap 113 | 114 | `let` is the new `var`. `const` is the same, but doesn't let you change it. 115 | 116 | ```js 117 | let a = 'hello' 118 | const b = 'hi' 119 | ``` 120 | 121 | --- 122 | 123 | They are *block scoping*: they are only available within `{...}` blocks, but not outside them. 124 | 125 | ```js 126 | if (true) { 127 | let a = 'hello' 128 | } 129 | console.log(a) //! undefined 130 | ``` 131 | 132 | > Next: Learn what's new with objects. [Next chapter](objects) 133 | -------------------------------------------------------------------------------- /docs/index.jade: -------------------------------------------------------------------------------- 1 | extends ./_layouts/landing.jade 2 | 3 | block body 4 | +body-content() 5 | h1 Guides 6 | 7 | ul 8 | li 9 | a(href='redux/') Redux 10 | li 11 | a(href='es2015/') ES2015 12 | -------------------------------------------------------------------------------- /docs/redux/actions.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: Redux 4 | chapter: Actions 5 | next: reducers 6 | --- 7 | 8 | # Actions 9 | 10 | So far we've learned about actions: things you `dispatch()` to a store to change its state. 11 | 12 | ```js 13 | store.dispatch(/*{*/{ type: 'PUBLISH' }/*}*/) 14 | ``` 15 | 16 | Actions are objects and always have a `type` key. This isn't required, but it's just the way everyone does it. 17 | 18 | > Next: How would we do it asynchronously? [Next](#the-three-states) 19 | 20 | * * * * 21 | 22 | # The three states 23 | 24 | Processes are *asynchronous* when they take a long time, such as AJAX calls to load some data. They usually have 3 states: `pending`, `success`, and `error`. Imagine it looking like this: 25 | 26 | ```js 27 | store.dispatch(/*{*/{ type: 'LOAD_START' }/*}*/) 28 | fetch('/data.json') 29 | .then(data => 30 | store.dispatch(/*{*/{ type: 'LOAD_FINISH', data: data })/*}*/) 31 | .catch(error => 32 | store.dispatch(/*{*/{ type: 'LOAD_ERROR', error: error })/*}*/) 33 | // --- 34 | // -- Assuming `fetch()` returns a promise, we can use it to trigger store actions when something happens. 35 | ``` 36 | 37 | 38 | 39 | > Next: Let's try to hook this up to our store. [Next](#first-try) 40 | 41 | * * * * 42 | 43 | # First try 44 | 45 | Let's try putting this logic in the reducer. Let's add `fetch()` into it. 46 | 47 | ```js 48 | function reducer (state, action) { 49 | if (action.type === 'LOAD_START') { 50 | /*{*/fetch('/data.json').then(/*[ ?? ]*/).catch(/*[ ?? ]*/)/*}*/ 51 | return { ...state, loading: true } 52 | } else { //- 53 | return state //- 54 | } //- 55 | } //- 56 | 57 | createStore(reducer) //- 58 | ``` 59 | 60 | It seems you can't `dispatch()` inside a reducer! This is how Redux was designed. Reducers only define how to move from one state to another; it can't have side effects. 61 | 62 | > Next: Let's try a different approach. [Next](#second-try) 63 | 64 | * * * * 65 | 66 | # Second try 67 | 68 | Let's try putting that logic in a function outside the store. Let's make a function. 69 | 70 | 71 | 72 | > By passing `dispatch` to `load()`, it can dispatch events. 73 | 74 | --- 75 | 76 | But now we're not being consistent: we often use `store.dispatch()` to trigger actions, but this time we're using `load(...)`. We can do better. 77 | 78 | ```js 79 | /*{*/load(store.dispatch)/*}*/ // <-- this new way 80 | // --- 81 | store.dispatch({ type: 'INIT' }) // <-- everything else 82 | ``` 83 | 84 | > Next: Let's make things more consistent. [Next](#meet-redux-thunk) 85 | 86 | * * * * 87 | 88 | # Meet redux-thunk 89 | 90 | Let's improve our design. [redux-thunk](https://www.npmjs.com/package/redux-thunk) is a plugin for Redux. It makes your `dispatch()` accept functions just like the one earlier. 91 | 92 | ```js 93 | import thunk from 'redux-thunk' //- 94 | import { createStore, applyMiddleware } from 'redux' //- 95 | 96 | store = createStore(reducer, {}, /*{*/applyMiddleware(thunk)/*}*/) 97 | ``` 98 | 99 | --- 100 | 101 | redux-thunk is a Middleware, or a plugin that extends `dispatch()` to do more things. 102 | 103 | ```js 104 | function load (dispatch, getState) { 105 | /*...*/ 106 | } 107 | 108 | store.dispatch(/*{*/load/*}*/) 109 | ``` 110 | 111 | > We can take the `load()` function earlier and use it as an action. 112 | 113 | 114 | 115 | > Also see: [applyMiddleware()](http://redux.js.org/docs/api/applyMiddleware.html) [redux-thunk](https://www.npmjs.com/package/redux-thunk) 116 | 117 | 118 | 119 | > Next: Let's sort out our action creators. [Next](#action-creators) 120 | 121 | * * * * 122 | 123 | # Action creators 124 | 125 | In a typical app, we'll likely have a few of action creators. It's best to organize these into one file. 126 | 127 | ```js 128 | export function loadProject (id) { 129 | return function (dispatch) { //- 130 | dispatch({ type: 'PROJECT_LOADING', data }) //- 131 | return fetch(`/projects/${id}`) //- 132 | .then(data => dispatch({ type: 'PROJECT_LOADED', data })) //- 133 | .catch(err => dispatch({ type: 'PROJECT_ERROR', err })) //- 134 | } //- 135 | } 136 | 137 | export function saveProject (id) { /*...*/ } 138 | export function deleteProject (id) { /*...*/ } 139 | export function createProject (id, data) { /*...*/ } 140 | ``` 141 | 142 | > Save this file as `actions.js`. 143 | 144 | --- 145 | 146 | *Action Creators are* functions that return an action. `loadProject()` and friends return functions, which redux-thunk will happily accept as actions. 147 | 148 | ```js 149 | import { loadProject } from './actions' 150 | 151 | store.dispatch(/*{*/loadProject()/*}*/) 152 | ``` 153 | 154 | > Invoke these actions by passing the functions' results to `dispatch()`. 155 | 156 | 157 | 158 | > Also see: [Actions](http://redux.js.org/docs/basics/Actions.html) 159 | 160 | 161 | 162 | > Next: Let's build more action creators. [Next](#simple-action-creators) 163 | 164 | * * * * 165 | 166 | # Simple action creators 167 | 168 | Action creators don't have to only be for asynchronous actions. Even simple actions can have action creators. 169 | 170 | ```js 171 | export function publishProject (id) { 172 | return { type: 'PROJECT_UPDATE', id, published: true } 173 | } 174 | ``` 175 | 176 | > Next: Let's recap what we've learned. [Next](#recap) 177 | 178 | * * * * 179 | 180 | # Recap 181 | 182 | **Action creators** are functions that return things that you can pass to `dispatch()`. 183 | 184 | ```js 185 | export function publishProject (id) { 186 | return { type: 'PROJECT_UPDATE', id, published: true } 187 | } 188 | // --- 189 | store.dispatch(/*{*/publishProject(12)/*}*/) 190 | ``` 191 | 192 | --- 193 | 194 | **redux-thunk** is a plugin that will allow you to pass functions to `dispatch()`. Great for asynchronous actions. 195 | 196 | ```js 197 | export function loadProject (id) { 198 | /*{*/return function (dispatch) {/*}*/ 199 | dispatch({ type: 'PROJECT_LOADING', data }) 200 | return fetch(`/projects/${id}`) 201 | .then(data => dispatch({ type: 'PROJECT_LOADED', data })) 202 | .catch(err => dispatch({ type: 'PROJECT_ERROR', err })) 203 | } 204 | } 205 | // --- 206 | store.dispatch(/*{*/loadProject(12)/*}*/) 207 | ``` 208 | 209 | 210 | --- 211 | 212 | **Middleware** are plugins for Redux that extends `dispatch()` to do more things. 213 | 214 | ```js 215 | store = createStore(reducer, {}, /*{*/applyMiddleware(reduxThunk)/*}*/) 216 | ``` 217 | 218 | > Next: Let's learn about reducers. [Next](reducers) 219 | -------------------------------------------------------------------------------- /docs/redux/examples/actions-second-try.jade: -------------------------------------------------------------------------------- 1 | --- 2 | external: 3 | - /vendor/redux.js 4 | given: 5 | - code: | 6 | var createStore = require('redux').createStore 7 | 8 | function reducer (state, action) { 9 | switch (action.type) { 10 | case 'LOAD_START': 11 | return { status: 'loading' } 12 | case 'LOAD_FINISH': 13 | return { status: 'finish', data: action.data } 14 | case 'LOAD_ERROR': 15 | return { status: 'error', error: action.error.message } 16 | default: 17 | return state 18 | } 19 | } 20 | 21 | var store = createStore(reducer, {}) 22 | store.subscribe(() => { console.log(store.getState()) }) 23 | examples: 24 | - placeholder: | 25 | /*{*/function load (dispatch) {/*}*/ 26 | dispatch({ type: 'LOAD_START' }) 27 | fetch('https://httpbin.org/ip') 28 | .then(res => res.json()) 29 | .then(data => 30 | dispatch({ type: 'LOAD_FINISH', data: data })) 31 | .catch(error => 32 | dispatch({ type: 'LOAD_ERROR', error: error })) 33 | } 34 | code: | 35 | function load (dispatch) { 36 | dispatch({ type: 'LOAD_START' }) 37 | fetch('https://httpbin.org/ip') 38 | .then(res => res.json()) 39 | .then(data => 40 | dispatch({ type: 'LOAD_FINISH', data: data })) 41 | .catch(error => 42 | dispatch({ type: 'LOAD_ERROR', error: error })) 43 | } 44 | 45 | load(store.dispatch) 46 | --- 47 | extends ../../_layouts/example.jade 48 | block body 49 | +example-body(given, examples, external) 50 | -------------------------------------------------------------------------------- /docs/redux/examples/intro-dispatching.jade: -------------------------------------------------------------------------------- 1 | --- 2 | external: 3 | - /vendor/redux.js 4 | given: 5 | - code: | 6 | var createStore = require('redux').createStore 7 | 8 | function reducer (state, action) { 9 | switch (action.type) { 10 | case 'SET': 11 | return action.value 12 | case 'ADD': 13 | return state + action.value 14 | default: 15 | return state 16 | } 17 | } 18 | 19 | // The second parameter (initial state) is optional. 20 | var store = createStore(reducer) 21 | examples: 22 | - code: | 23 | store.dispatch({ type: 'SET', value: 200 }) 24 | store.dispatch({ type: 'ADD', value: 5 }) 25 | console.log(store.getState()) 26 | --- 27 | extends ../../_layouts/example.jade 28 | block body 29 | +example-body(given, examples, external) 30 | -------------------------------------------------------------------------------- /docs/redux/examples/intro-first-store.jade: -------------------------------------------------------------------------------- 1 | --- 2 | external: 3 | - /vendor/redux.js 4 | given: 5 | - code: | 6 | var createStore = require('redux').createStore 7 | 8 | var initialState = { 9 | title: 'Kind of Blue', 10 | artist: 'Miles Davis', 11 | year: 1959 12 | } 13 | 14 | function reducer (state, action) { 15 | return state 16 | } 17 | 18 | var store = createStore(reducer, initialState) 19 | examples: 20 | - action: Read 21 | auto: true 22 | code: | 23 | var state = store.getState() 24 | console.log(state.title) 25 | --- 26 | extends ../../_layouts/example.jade 27 | block body 28 | +example-body(given, examples, external) 29 | -------------------------------------------------------------------------------- /docs/redux/examples/intro-simple-read.jade: -------------------------------------------------------------------------------- 1 | --- 2 | given: 3 | - code: | 4 | var album = { 5 | title: 'Kind of Blue', 6 | artist: 'Miles Davis', 7 | year: 1959 8 | } 9 | examples: 10 | - action: Read 11 | code: | 12 | console.log(album.title) 13 | - action: Write 14 | code: | 15 | album.genre = 'Jazz' 16 | console.log(album) 17 | --- 18 | extends ../../_layouts/example.jade 19 | block body 20 | +example-body(given, examples) 21 | -------------------------------------------------------------------------------- /docs/redux/examples/intro-subscribe.jade: -------------------------------------------------------------------------------- 1 | --- 2 | external: 3 | - /vendor/redux.js 4 | given: 5 | - code: | 6 | var createStore = require('redux').createStore 7 | 8 | function reducer (state, action) { 9 | switch (action.type) { 10 | case 'SET': 11 | return action.value 12 | case 'ADD': 13 | return state + action.value 14 | default: 15 | return state 16 | } 17 | } 18 | 19 | var store = createStore(reducer) 20 | examples: 21 | - placeholder: | 22 | store.subscribe(() => { 23 | /*...*/ 24 | }) 25 | code: | 26 | store.subscribe(() => { 27 | console.log(store.getState()) 28 | }) 29 | 30 | store.dispatch({ type: 'SET', value: 200 }) 31 | store.dispatch({ type: 'ADD', value: 5 }) 32 | --- 33 | extends ../../_layouts/example.jade 34 | block body 35 | +example-body(given, examples, external) 36 | -------------------------------------------------------------------------------- /docs/redux/examples/intro-updating.jade: -------------------------------------------------------------------------------- 1 | --- 2 | external: 3 | - /vendor/redux.js 4 | given: 5 | - code: | 6 | var createStore = require('redux').createStore 7 | 8 | function reducer (state, action) { 9 | switch (action.type) { 10 | case 'PUBLISH': 11 | return Object.assign({}, state, { published: true }) 12 | default: 13 | return state 14 | } 15 | } 16 | 17 | var article = { title: 'Global Warming' } 18 | var store = createStore(reducer, article) 19 | examples: 20 | - placeholder: | 21 | console.log(store.getState()) //=> { ... } 22 | 23 | store.dispatch({ type: 'PUBLISH' }) 24 | console.log(store.getState()) //=> { ..., published: true } 25 | code: | 26 | console.log(store.getState()) 27 | 28 | store.dispatch({ type: 'PUBLISH' }) 29 | console.log(store.getState()) 30 | --- 31 | extends ../../_layouts/example.jade 32 | block body 33 | +example-body(given, examples, external) 34 | -------------------------------------------------------------------------------- /docs/redux/examples/reducers-sample.jade: -------------------------------------------------------------------------------- 1 | --- 2 | given: 3 | - code: | 4 | function reducer (state, action) { 5 | switch (action.type) { 6 | case 'PUBLISH': 7 | return { ...state, published: true } 8 | case 'UNPUBLISH': 9 | return { ...state, published: false } 10 | case 'UPDATE': 11 | return { ...state, ...action.data } 12 | default: 13 | return state 14 | } 15 | } 16 | 17 | var state = { title: 'Hello world' } 18 | examples: 19 | - code: | 20 | reducer(state, { type: 'PUBLISH' }) 21 | - code: | 22 | reducer(state, { type: 'UPDATE', data: { title: 'Hola mundo' } }) 23 | --- 24 | extends ../../_layouts/example.jade 25 | block body 26 | +example-body(given, examples) 27 | -------------------------------------------------------------------------------- /docs/redux/index.jade: -------------------------------------------------------------------------------- 1 | --- 2 | title: Redux 3 | prelude: Introduction to 4 | next: introduction 5 | chapters: 6 | - id: introduction 7 | title: Introduction 8 | description: An introduction to Redux 9 | - id: actions 10 | title: Actions 11 | description: Modifying the state 12 | - id: reducers 13 | title: Reducers 14 | description: Defining state transitions 15 | - id: react 16 | title: Using with React 17 | description: Integrating via react-redux 18 | - id: middleware 19 | title: Middleware 20 | description: Managing side effects 21 | --- 22 | extends ../_layouts/book.jade 23 | 24 | block description 25 | :markdown-it 26 | [Redux](http://redux.js.org) is a library for managing data in a React application. This guide assumes an intermediate knowledge of JavaScript. 27 | 28 | block body 29 | body.-book 30 | +content(chapters) 31 | -------------------------------------------------------------------------------- /docs/redux/introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: Redux 4 | chapter: Introduction 5 | next: actions 6 | --- 7 | 8 | Redux 9 | ===== 10 | 11 | [Redux](http://redux.js.org/) is used to manage data in a React application. Using redux means you create a *store* that a React app listens to. 12 | 13 | ```js 14 | import { createStore } from 'redux' 15 | 16 | var store = createStore(/*...*/) 17 | ``` 18 | 19 | > Next: What's a store? [Next](#stores) 20 | 21 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 22 | 23 | Stores 24 | ====== 25 | 26 | Think of a store as a bunch of data. In fact, you may have already done this: the example here is a plain JS object that stores data. 27 | 28 | ```js 29 | var album = { 30 | title: 'Kind of Blue', 31 | artist: 'Miles Davis', 32 | year: 1959 33 | } 34 | ``` 35 | 36 | --- 37 | 38 | You can read and write data into a plain JS object. You can do the same in Redux, but just a little differently. 39 | 40 | 41 | 42 | > Next: How would you do that in Redux? [Next](#our-first-store) 43 | 44 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 45 | 46 | Our first store 47 | =============== 48 | 49 | Stores are created using `createStore()`. 50 | 51 | ```js 52 | import { createStore } from 'redux' //- 53 | 54 | var reducer = /*...*/ 55 | var store = /*{*/createStore(reducer, album)/*}*/ 56 | ``` 57 | 58 | --- 59 | 60 | You can read from a store by checking its *state* using `getState()`. 61 | Writing data works a bit different, though. That's where `reducer` comes in. 62 | 63 | 64 | 65 | --- 66 | 67 |
68 | Further reading... 69 | 70 | - [createStore docs](http://redux.js.org/docs/basics/Actions.html) (redux.js.org) 71 |
72 | 73 | > Next: How do you write to a store? [Next](#updating-the-store) 74 | 75 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 76 | 77 | Updating the store 78 | ================== 79 | 80 | You can't change the store's state from outside the store. To do that, you'll need to create actions. Actions are made through *reducer functions*, which is used by `createStore()`. 81 | 82 | ```js 83 | import { createStore } from 'redux' //- 84 | 85 | var store = createStore(/*{*/reducer/*}*/, article) 86 | 87 | function reducer (state, action) { 88 | if (action.type === 'PUBLISH') { 89 | return { ...state, published: true } 90 | } else { 91 | return state 92 | } 93 | } 94 | ``` 95 | 96 | Reducers take the current state and return a new one. How it changes the store depends on `action`. 97 | 98 | --- 99 | 100 | To run an action, use `dispatch()`. This changes the store's *state*. 101 | 102 | 103 | 104 | > See also: [Reducer docs](http://redux.js.org/docs/basics/Reducers.html) 105 | 106 |
107 | 108 | > Next: What does `...state` mean? [Next](#the-spread-operator) 109 | 110 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 111 | 112 | The spread operator 113 | =================== 114 | 115 | The `...` symbol is the *object spread operator*. It's available in Babel and in the 2017 version of JavaScript. 116 | These two are roughly equivalent. 117 | 118 | ```js 119 | return { /*{*/...state/*}*/, published: true } 120 | // --- 121 | return { 122 | /*{*/title: state.title,/*}*/ 123 | /*{*/body: state.body,/*}*/ 124 | published: true 125 | } 126 | // --- 127 | // -- The contents of `state` is rolled out in place of `...state`. 128 | ``` 129 | 130 | 134 | 135 |
136 | 137 | > See also: [Object spread docs](http://redux.js.org/docs/recipes/UsingObjectSpreadOperator.html) 138 | 139 |
140 | 141 | > Next: Let's learn more about actions. [Next](#dispatching-actions) 142 | 143 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 144 | 145 | Dispatching actions 146 | =================== 147 | 148 | The only way to change the store's state is by dispatching actions. You can then easily make a log of what actions have happened, or even undo them. 149 | 150 | 151 | 152 | --- 153 | 154 | You can also listen for changes in the store using `subscribe()`. 155 | 156 | 157 | 158 | > Next: Let's recap what we've learned. [Next](#recap) 159 | 160 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 161 | 162 | # Recap 163 | 164 | **Stores** are made from reducer functions. 165 | 166 | ```js 167 | import { createStore } from 'redux' //- 168 | store = createStore(reducer, {/*[ initial state ]*/}) 169 | ``` 170 | 171 | --- 172 | 173 | **Actions** are dispatched to the reducer. 174 | 175 | ```js 176 | store.dispatch(/*{*/{ type: 'PUBLISH' }/*}*/) 177 | ``` 178 | 179 | --- 180 | 181 | **Reducers** tell us how to change a `state` based on an `action`. 182 | 183 | ```js 184 | function reducer (state, action) { 185 | if /*{*/(action.type === 'PUBLISH')/*}*/ { 186 | return { ...state, published: true } 187 | } 188 | return state 189 | } 190 | ``` 191 | 192 | --- 193 | 194 | **States:** the store keeps a state, and you can listen for updates using `subscribe()`. 195 | 196 | ```js 197 | /*{*/store.getState()/*}*/.published 198 | store.subscribe(() => { /*...*/ }) 199 | ``` 200 | 201 | > Next: Let's learn more about actions. [Next chapter](actions) 202 | -------------------------------------------------------------------------------- /docs/redux/middleware.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: Redux 4 | chapter: Middleware 5 | --- 6 | 7 | Middleware 8 | ========== 9 | 10 | Redux plugins are often made as *middleware*. 11 | Middleware are just functions. Here's a middleware that does nothing. 12 | 13 | 14 | ```js 15 | createStore(reducer, {}, /*{*/applyMiddleware(logger)/*}*/) 16 | ``` 17 | 18 | ```js 19 | function logger (store) { 20 | return function (dispatch) { 21 | return function (action) { 22 | return dispatch(action) 23 | } 24 | } 25 | } 26 | // --- 27 | // -- It make look complicated at first, but let's learn about this later! 28 | ``` 29 | 30 | --- 31 | 32 | With ES2015, you can shorten this to: 33 | 34 | ```js 35 | const logger = store => dispatch => action => { 36 | return dispatch(action) 37 | } 38 | ``` 39 | 40 |
41 | See related documentation 42 | 43 | - [applyMiddleware()](http://redux.js.org/docs/api/applyMiddleware.html) (redux.js.org) 44 |
45 | 46 | 47 | 48 | > Next: Let's give extra powers to `dispatch()`. [Next](#decorating-dispatch) 49 | 50 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 51 | 52 | Decorating dispatch 53 | =================== 54 | 55 | Middleware is most commonly used to make `dispatch()` do something else. 56 | 57 | ```js 58 | const logger = store => dispatch => action => { 59 | console.log('Dispatching:', action.type) 60 | console.log('Old state:', store.getState()) 61 | var result = dispatch(action) 62 | console.log('New state:', store.getState()) 63 | return result 64 | } 65 | ``` 66 | 67 | --- 68 | 69 | In this example, we've made `dispatch()` log some messages before and after dispatching. 70 | 71 | ```js 72 | store.dispatch({ type: 'SAVE' }) 73 | // --- 74 | //=> Dispatching: SAVE 75 | //=> Old state: { ... } 76 | //=> New state: { ... } 77 | ``` 78 | 79 | > Next: Let's use this for something useful. [Next](#side-effects) 80 | 81 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 82 | 83 | Side effects 84 | ============ 85 | 86 | A store's reducers should have no side effects. Middleware is often used for that instead. Let's write a middleware that performs AJAX requests using [window.fetch()](https://fetch.spec.whatwg.org/). 87 | 88 | ```js 89 | const fetcher = store => dispatch => action => { 90 | const { type, next, url } = action 91 | if (type === 'FETCH') { 92 | /*{*/dispatch({ type: `${next}_PENDING` })/*}*/ 93 | return fetch(url) 94 | .then(result => /*{*/dispatch({ type: `${next}_SUCCESS`, result })/*}*/) 95 | .then(error => /*{*/dispatch({ type: `${next}_ERROR`, error })/*}*/) 96 | } else { 97 | return dispatch(action) 98 | } 99 | } 100 | // --- 101 | // -- This function will replace `dispatch()`. It listens for `FETCH` actions. 102 | ``` 103 | 104 | ```js 105 | store.dispatch({ type: 'FETCH', next: 'LOAD', url: '/data.json' }) 106 | // --- 107 | // -- When using the middleware, this dispatches `LOAD_PENDING`, `LOAD_SUCCESS` and `LOAD_ERROR`. 108 | ``` 109 | 110 |
111 | 112 | > Next: Let's improve your Redux experience with npm. [Next](#common-middleware) 113 | 114 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 115 | 116 | Common middleware 117 | ================= 118 | 119 | The npm ecosystem has a lot of useful Redux middleware. For instance, [redux-thunk](https://www.npmjs.com/package/redux-thunk) lets you dispatch functions. 120 | 121 | ```js 122 | store.dispatch((dispatch) => { /*...*/ }) 123 | ``` 124 | 125 | --- 126 | 127 | [redux-multi](https://github.com/ashaffer/redux-multi) lets you dispatch many actions in one action. 128 | 129 | ```js 130 | store.dispatch([ 131 | { type: 'INCREMENT', payload: 2 }, 132 | { type: 'INCREMENT', payload: 3 } 133 | ]) 134 | ``` 135 | 136 | --- 137 | 138 | [redux-logger](https://github.com/evgenyrodionov/redux-logger) shows you Redux actions as they happen. 139 | 140 | ``` 141 | action @ 13:11:00 FETCH (in 0.1ms) 142 | action @ 13:11:01 LOAD_PENDING (in 0.1ms) 143 | action @ 13:11:02 LOAD_SUCCESS (in 0.1ms) 144 | ``` 145 | 146 | > Next: Did you wonder why middleware looks like `store => dispatch => action`? [Next](#middleware-signature) 147 | 148 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 149 | 150 | Middleware signature 151 | ==================== 152 | 153 | You may have noticed that middleware functions look a bit confusing. It's a function, that returns a function, that returns a function. 154 | 155 | ```js 156 | const logger = store => dispatch => action => { 157 | return dispatch(action) 158 | } 159 | ``` 160 | 161 | Forget about its strange look. Think of it as a single function. 162 | 163 | ```js 164 | function logger (store, dispatch, action) { /*...*/ } 165 | ``` 166 | 167 | --- 168 | 169 | Having them as functions-that-return-functions makes for something interesting: it breaks the middleware into 3 steps that are applied separately. 170 | 171 | ```js 172 | const logger = function (store) { 173 | // <-- This function runs on `createStore()`. 174 | // <-- It returns a decorator for dispatch(). 175 | // <-- You can get store.getState() here. 176 | return function (dispatch) { 177 | // <-- This function runs on `createStore()` too. 178 | // <-- This returns a new `dispatch()` function to 179 | // <-- replace the old one. 180 | return function (action) { 181 | // <-- This runs every `dispatch()`. 182 | } 183 | } 184 | } 185 | ``` 186 | 187 | Most middleware will not need this, but the Redux docs has [examples](http://redux.js.org/docs/advanced/Middleware.html) when this can be useful. 188 | 189 |
190 | 191 | > Next: Let's recap what we've learned. [Next](#recap) 192 | 193 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 194 | 195 | Recap 196 | ===== 197 | 198 | **Middleware** are Redux plugins you can attach to your store. 199 | 200 | ```js 201 | createStore(reducer, {}, applyMiddleware(/*{*/logger/*}*/, /*{*/thunk/*}*/)) 202 | ``` 203 | 204 | --- 205 | 206 | They give `dispatch()` more powers. 207 | 208 | ```js 209 | store.dispatch({ type: 'SAVE' }) /// Normal 210 | store.dispatch(fetch('/data.json')) /// Promises 211 | store.dispatch(() => { /*...*/ }) /// Functions/thunks 212 | store.dispatch(/*...*/) /// ...and more 213 | ``` 214 | 215 | --- 216 | 217 | You can use middleware to write side effects to actions. 218 | 219 | ```js 220 | const middleware = store => dispatch => action => { 221 | if (action.type === 'FETCH') { 222 | doSomethingDifferent() 223 | } 224 | dispatch(action) 225 | } 226 | ``` 227 | 228 | > Next: That's all for now! [Back](.) 229 | -------------------------------------------------------------------------------- /docs/redux/react.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: _layouts/chapter.jade 3 | book: Redux 4 | chapter: Using with React 5 | next: middleware 6 | --- 7 | 8 | Using with React 9 | ================ 10 | 11 | **react-redux** is the official package used to make Redux and React work together. To use it, wrap your main app (your top-most React component) inside a ``. This lets your components see the `store`. 12 | 13 | ```js 14 | import React from 'react' //- 15 | import { render } from 'react-dom' //- 16 | import { createStore } from 'redux' //- 17 | import { /*{*/Provider/*}*/ } from 'react-redux' 18 | 19 | let store = createStore(todoApp) 20 | 21 | render( 22 | 23 | 24 | , 25 | document.getElementById('root')) 26 | ``` 27 | 28 | > Also see: [Usage with React](http://redux.js.org/docs/basics/UsageWithReact.html) 29 | 30 | 31 | 32 | > Next: How do I see the state in my components? [Next](#connecting-to-a-store) 33 | 34 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 35 | 36 | Connecting to a store 37 | ===================== 38 | 39 | react-redux provides `connect()` to let components see the store's state. 40 | 41 | ```js 42 | import { connect } from 'redux' 43 | 44 | PhotosList = React.createClass({ /*...*/ }) 45 | PhotosList = /*{*/connect(mapState)/*}*/(PhotosList) 46 | ``` 47 | 48 | --- 49 | 50 | What's `mapState`? It takes the `state` and returns props to be used by the component. Write this function and pass it to *connect()*. 51 | 52 | ```js 53 | function mapState (state) { 54 | return /*{*/{ photos: state.photos }/*}*/ 55 | } 56 | ``` 57 | 58 | --- 59 | 60 | You can use the props you made in *mapState()* inside your component as `this.props`. 61 | 62 | ```js 63 | var PhotosList = React.createClass({ 64 | render () { 65 | let photos = /*{*/this.props.photos/*}*/ 66 | return
{photos.map(/*...*/)}
67 | } 68 | }) 69 | ``` 70 | 71 | > Next: What about dispatching events? [Next](#dispatching) 72 | 73 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 74 | 75 | Dispatching 76 | =========== 77 | 78 | `connect()` also lets you send *props* to your Components that map to dispatch calls. The 2nd argument of `connect()` lets you do this. 79 | 80 | ```js 81 | var PhotosList = connect(mapState, /*{*/mapDispatch/*}*/)(PhotosList) 82 | ``` 83 | 84 | --- 85 | 86 | Provide it a function that returns properties to be added to your component. These properties are functions that you can call later on. 87 | 88 | ```js 89 | function mapDispatch (dispatch) { 90 | return { 91 | onPublishClick: function () { 92 | dispatch({ type: 'PUBLISH' }) 93 | } 94 | } 95 | } 96 | ``` 97 | 98 | --- 99 | 100 | These properties will be available in `props` in your component. You can then call them on certain events like *onClick*. 101 | 102 | ```js 103 |