1
0

prerequisites.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. Title: Three.js Prerequisites
  2. Description: What you need to know to use this site.
  3. TOC: Prerequisites
  4. These articles are meant to help you learn how to use three.js.
  5. They assume you know how to program in JavaScript. They assume
  6. you know what the DOM is, how to write HTML as well as create DOM elements
  7. in JavaScript. They assume you know how to use
  8. [es6 modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
  9. via import and via `<script type="module">` tags.
  10. They assume you know some CSS and that you know what
  11. [CSS selectors are](https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors).
  12. They also assume you know ES5, ES6 and maybe some ES7.
  13. They assume you know that the browser runs JavaScript only via events and callbacks.
  14. They assume you know what a closure is.
  15. Here's some brief refreshers and notes
  16. ## es6 modules
  17. es6 modules can be loaded via the `import` keyword in a script
  18. or inline via a `<script type="module">` tag. Here's an example of
  19. both
  20. ```html
  21. <script type="module">
  22. import * as THREE from './resources/threejs/r132/build/three.module.js';
  23. ...
  24. </script>
  25. ```
  26. Paths must be absolute or relative. Relative paths always start with `./` or `../`
  27. which is different than other tags like `<img>` and `<a>` and css references.
  28. More details are mentioned at the bottom of [this article](threejs-fundamentals.html).
  29. ## `document.querySelector` and `document.querySelectorAll`
  30. You can use `document.querySelector` to select the first element
  31. that matches a CSS selector. `document.querySelectorAll` returns
  32. all elements that match a CSS selector.
  33. ## You don't need `onload`
  34. Lots of 20yr old pages use HTML like
  35. <body onload="somefunction()">
  36. That style is deprecated. Put your scripts
  37. at the bottom of the page.
  38. ```html
  39. <html>
  40. <head>
  41. ...
  42. </head>
  43. <body>
  44. ...
  45. </body>
  46. <script>
  47. // inline javascript
  48. </script>
  49. </html>
  50. ```
  51. or [use the `defer` property](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script).
  52. ## Know how closures work
  53. ```js
  54. function a(v) {
  55. const foo = v;
  56. return function() {
  57. return foo;
  58. };
  59. }
  60. const f = a(123);
  61. const g = a(456);
  62. console.log(f()); // prints 123
  63. console.log(g()); // prints 456
  64. ```
  65. In the code above the function `a` creates a new function every time it's called. That
  66. function *closes* over the variable `foo`. Here's [more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures).
  67. ## Understand how `this` works
  68. `this` is not magic. It's effectively a variable that is automatically passed to functions just like
  69. an argument is passed to function. The simple explanation is when you call a function directly
  70. like
  71. somefunction(a, b, c);
  72. `this` will be `null` (when in strict mode or in a module) where as when you call a function via the dot operator `.` like this
  73. someobject.somefunction(a, b, c);
  74. `this` will be set to `someobject`.
  75. The parts where people get confused is with callbacks.
  76. const callback = someobject.somefunction;
  77. loader.load(callback);
  78. doesn't work as someone inexperienced might expect because when
  79. `loader.load` calls the callback it's not calling it with the dot `.` operator
  80. so by default `this` will be null (unless the loader explicitly sets it to something).
  81. If you want `this` to be `someobject` when the callback happens you need to
  82. tell JavaScript that by binding it to the function.
  83. const callback = someobject.somefunction.bind(someobject);
  84. loader.load(callback);
  85. [*this* article might help explain `this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this).
  86. ## ES5/ES6/ES7 stuff
  87. ### `var` is deprecated. Use `const` and/or `let`
  88. There is no reason to use `var` **EVER** and at this point it's considered bad practice
  89. to use it at all. Use `const` if the variable will never be reassigned which is most of
  90. the time. Use `let` in those cases where the value changes. This will help avoid tons of bugs.
  91. ### Use `for(elem of collection)` never `for(elem in collection)`
  92. `for of` is new, `for in` is old. `for in` had issues that are solved by `for of`
  93. As one example you can iterate over all the key/value pairs of an object with
  94. ```js
  95. for (const [key, value] of Object.entries(someObject)) {
  96. console.log(key, value);
  97. }
  98. ```
  99. ### Use `forEach`, `map`, and `filter` where useful
  100. Arrays added the functions [`forEach`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach),
  101. [`map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map), and
  102. [`filter`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) and
  103. are used fairly extensively in modern JavaScript.
  104. ### Use destructuring
  105. Assume an object `const dims = {width: 300, height: 150}`
  106. old code
  107. ```js
  108. const width = dims.width;
  109. const height = dims.height;
  110. ```
  111. new code
  112. ```js
  113. const {width, height} = dims;
  114. ```
  115. Destructuring works with arrays too. Assume an array `const position = [5, 6, 7, 1]`;
  116. old code
  117. ```js
  118. const y = position[1];
  119. const z = position[2];
  120. ```
  121. new code
  122. ```js
  123. const [, y, z] = position;
  124. ```
  125. Destructuring also works in function arguments
  126. ```js
  127. const dims = {width: 300, height: 150};
  128. const vector = [3, 4];
  129. function lengthOfVector([x, y]) {
  130. return Math.sqrt(x * x + y * y);
  131. }
  132. const dist = lengthOfVector(vector); // dist = 5
  133. function area({width, height}) {
  134. return width * height;
  135. }
  136. const a = area(dims); // a = 45000
  137. ```
  138. ### Use object declaration short cuts
  139. old code
  140. ```js
  141. const width = 300;
  142. const height = 150;
  143. const obj = {
  144. width: width,
  145. height: height,
  146. area: function() {
  147. return this.width * this.height
  148. },
  149. };
  150. ```
  151. new code
  152. ```js
  153. const width = 300;
  154. const height = 150;
  155. const obj = {
  156. width,
  157. height,
  158. area() {
  159. return this.width * this.height;
  160. },
  161. };
  162. ```
  163. ### Use the rest parameter and the spread operator `...`
  164. The rest parameter can be used to consume any number of parameters. Example
  165. ```js
  166. function log(className, ...args) {
  167. const elem = document.createElement('div');
  168. elem.className = className;
  169. elem.textContent = args.join(' ');
  170. document.body.appendChild(elem);
  171. }
  172. ```
  173. The spread operator can be used to expand an iterable into arguments
  174. ```js
  175. const position = [1, 2, 3];
  176. someMesh.position.set(...position);
  177. ```
  178. or copy an array
  179. ```js
  180. const copiedPositionArray = [...position];
  181. copiedPositionArray.push(4); // [1,2,3,4]
  182. console.log(position); // [1,2,3] position is unaffected
  183. ```
  184. or to merge objects
  185. ```
  186. const a = {abc: 123};
  187. const b = {def: 456};
  188. const c = {...a, ...b}; // c is now {abc: 123, def: 456}
  189. ```
  190. ### Use `class`
  191. The syntax for making class like objects pre ES5 was unfamiliar to most
  192. programmers. As of ES5 you can now [use the `class`
  193. keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)
  194. which is closer to the style of C++/C#/Java.
  195. ### Understand getters and setters
  196. [Getters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) and
  197. [setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) are
  198. common in most modern languages. The `class` syntax
  199. of ES5 makes them much easier than pre ES5.
  200. ### Use arrow functions where appropriate
  201. This is especially useful with callbacks and promises.
  202. ```js
  203. loader.load((texture) => {
  204. // use texture
  205. });
  206. ```
  207. Arrow functions bind `this` to the context in which you create the arrow function.
  208. ```js
  209. const foo = (args) => {/* code */};
  210. ```
  211. is a shortcut for
  212. ```js
  213. const foo = (function(args) {/* code */}).bind(this));
  214. ```
  215. See link above for more info on `this`.
  216. ### Promises as well as async/await
  217. Promises help with asynchronous code. Async/await help
  218. use promises.
  219. It's too big a topic to go into here but you can [read up
  220. on promises here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises)
  221. and [async/await here](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await).
  222. ### Use Template Literals
  223. Template literals are strings using backticks instead of quotes.
  224. const foo = `this is a template literal`;
  225. Template literals have basically 2 features. One is they can be multi-line
  226. ```js
  227. const foo = `this
  228. is
  229. a
  230. template
  231. literal`;
  232. const bar = "this\nis\na\ntemplate\nliteral";
  233. ```
  234. `foo` and `bar` above are the same.
  235. The other is that you can pop out of string mode and insert snippets of
  236. JavaScript using `${javascript-expression}`. This is the template part. Example:
  237. ```js
  238. const r = 192;
  239. const g = 255;
  240. const b = 64;
  241. const rgbCSSColor = `rgb(${r},${g},${b})`;
  242. ```
  243. or
  244. ```js
  245. const color = [192, 255, 64];
  246. const rgbCSSColor = `rgb(${color.join(',')})`;
  247. ```
  248. or
  249. ```js
  250. const aWidth = 10;
  251. const bWidth = 20;
  252. someElement.style.width = `${aWidth + bWidth}px`;
  253. ```
  254. # Learn JavaScript coding conventions.
  255. While you're welcome to format your code any way you chose there is at least one
  256. convention you should be aware of. Variables, function names, method names, in
  257. JavaScript are all lowerCasedCamelCase. Constructors, the names of classes are
  258. CapitalizedCamelCase. If you follow this rule you code will match most other
  259. JavaScript. Many [linters](https://eslint.org), programs that check for obvious errors in your code,
  260. will point out errors if you use the wrong case since by following the convention
  261. above they can know when you're using something incorrectly.
  262. ```js
  263. const v = new vector(); // clearly an error if all classes start with a capital letter
  264. const v = Vector(); // clearly an error if all functions start with a lowercase latter.
  265. ```
  266. # Consider using Visual Studio Code
  267. Of course use whatever editor you want but if you haven't tried it consider
  268. using [Visual Studio Code](https://code.visualstudio.com/) for JavaScript and
  269. after installing it [setup
  270. eslint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint).
  271. It might take a few minutes to setup but it will help you immensely with finding
  272. bugs in your JavaScript.
  273. Some examples
  274. If you enable [the `no-undef` rule](https://eslint.org/docs/rules/no-undef) then
  275. VSCode via ESLint will warn you of many undefined variables.
  276. <div class="threejs_center"><img style="width: 615px;" src="resources/images/vscode-eslint-not-defined.png"></div>
  277. Above you can see I mis-spelled `doTheThing` as `doThing`. There's a red squiggle
  278. under `doThing` and hovering over it it tells me it's undefined. One error
  279. avoided.
  280. If you're using `<script>` tags to include three.js you'll get warnings using `THREE` so add `/* global THREE */` at the top of your
  281. JavaScript files to tell eslint that `THREE` exists. (or better, use `import` 😉)
  282. <div class="threejs_center"><img style="width: 615px;" src="resources/images/vscode-eslint-not-a-constructor.png"></div>
  283. Above you can see eslint knows the rule that `UpperCaseNames` are constructors
  284. and so you should be using `new`. Another error caught and avoided. This is [the
  285. `new-cap` rule](https://eslint.org/docs/rules/new-cap).
  286. There are [100s of rules you can turn on or off or
  287. customize](https://eslint.org/docs/rules/). For example above I mentioned you
  288. should use `const` and `let` over `var`.
  289. Here I used `var` and it warned me I should use `let` or `const`
  290. <div class="threejs_center"><img style="width: 615px;" src="resources/images/vscode-eslint-var.png"></div>
  291. Here I used `let` but it saw I never change the value so it suggested I use `const`.
  292. <div class="threejs_center"><img style="width: 615px;" src="resources/images/vscode-eslint-let.png"></div>
  293. Of course if you'd prefer to keep using `var` you can just turn off that rule.
  294. As I said above though I prefer to use `const` and `let` over `var` as they just
  295. work better and prevent bugs.
  296. For those cases where you really need to override a rule [you can add comments
  297. to disable
  298. them](https://eslint.org/docs/user-guide/configuring#disabling-rules-with-inline-comments)
  299. for a single line or a section of code.
  300. # If you really need to support legacy browsers use a transpiler
  301. Most modern browsers are auto-updated so using all these features will help you
  302. be productive and avoid bugs. That said, if you're on a project that absolutely
  303. must support old browsers there are [tools that will take your ES5/ES6/ES7 code
  304. and transpile the code back to pre ES5 Javascript](https://babeljs.io).
粤ICP备19079148号