prerequisites.html 21 KB

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