先决条件

这些文章意在帮助你学习如何使用three.js。 假设你知道怎么使用JavaScript编程。假设 你知道DOM是什么,怎么写HTML以及使用JavaScript创建 DOM元素。假设你知道如何使用 <script>标签来 引用外部的JavaScript文件以及行内脚本。 假设你了解CSS并且知道 CSS选择器. 还假设你了解ES5、 ES6或者一些ES7。 假设你知道浏览器通过事件和回调函数来运行JavaScript。 假设你知道什么是闭包。

这有一些简单的复习和笔记。

document.querySelector and document.querySelectorAll

你可以使用document.querySelector来选择和CSS选择器 匹配的第一个元素。 document.querySelectorAll返回 所有和CSS选择器匹配的元素。

You don't need onbody

很多20年前的页面像这样使用HTML

<body onload="somefunction()">

这种风格已经被弃用了。将你的脚本放在 页面的底部。

<html>
  <head>
    ...
  </head>
  <body>
     ...
  </body>
  <script>
    // inline javascript
  </script>
</html>

or use the defer property.

了解闭包如何工作

function a(v) {
  const foo = v;
  return function() {
     return foo;
  };
}

const f = a(123);
const g = a(456);
console.log(f());  // prints 123
console.log(g());  // prints 456

在上面的代码中函数a每次被调用都会创建一个新的函数。新函数 会封存变量foo. 这里有 更多信息.

理解this的工作原理

this并不是什么魔法。它实际上像是一个像被自动传给函数的参数一样的变量。 简单的说就是像这样直接调用函数

somefunction(a, b, c);

this将会为null (使用严格模式时) 当你使用.操作符像这样调用函数时

someobject.somefunction(a, b, c);

this将会被设置为someobject

令人困惑的部分是使用回调函数。

 const callback = someobject.somefunction;
 loader.load(callback);

并没有像不熟悉的所期望的那样工作,因为当 loader.load调用回调函数时并没有使用.操作符。 所以默认this将会为null (除非loader明确将他设置为某些东西)。 如果你希望thissomeobject当回调函数执行时你需要 通过将this绑定到函数来告诉JavaScript。

 const callback = someobject.somefunction.bind(someobject);
 loader.load(callback);

this article might help explain this.

ES5/ES6/ES7 特性

var已经被弃用,使用constlet

没有任何理由再使用var,基于此使用它被认为是 坏习惯。大所数时间如果变量不会被重新分配使用const。 变量会改变的情况下使用let。这将会帮助避免大量bug。

使用for(elem of collection)而不是for(elem in collection)

for of是新的,for in是旧的。 for of解决了for in的问题。

举个例子,你可以像这样迭代一个对象的所有键/值对

for (const [key, value] of Object.entries(someObject)) {
  console.log(key, value);
}

使用 forEach, map, 和 filter

数组新增的函数forEachmapfilter 在现代JavaScript中使用都是相当广泛的。

使用解构赋值

假设有一个对象const dims = {width: 300, height: 150}

老的代码

 const width = dims.width;
 const height = dims.height;

新代码

 const {width, height} = dims;

使用对象声明简写

老的代码

 const width = 300;
 const height = 150;
 const obj = {
   width: width,
   height: height,
   area: function() {
     return this.width * this.height
   },
 };

新代码

 const width = 300;
 const height = 150;
 const obj = {
   width,
   height,
   area() {
     return this.width * this.height;
   },
 };

使用扩展运算符...

扩展运算符有大量的用途。例如

 function log(className, ...args) {
   const elem = document.createElement('div');
   elem.className = className;
   elem.textContent = [...args].join(' ');
   document.body.appendChild(elem);
 }

另一个例子

const position = [1, 2, 3];
somemesh.position.set(...position);

使用class

大多数人都不熟悉在ES5之前生成类对象的语法。 ES5之后你现在可以使用class 关键字 接近于C++/C#/Java的语法。

理解 getters 和 setters

Getterssetters是 在大多数现代语言中常见的。ES6class语法 让他们比ES6之前的更容易。

合理使用箭头函数

回调函数和promise使用箭头函数非常有用

loader.load((texture) => {
  // use textrue
});

箭头函数会绑定this,它是下面的简写

(function(args) {/* code */}).bind(this))

Promises 以及 async/await

Promises改善异步代码的处理。Async/await改善 promise的使用。

这是一个需要深入了解的话题你可以在这里 细读promisesasync/await.

使用模板字符串

模板字符串是使用反引号代替引号的字符串。

const foo = `this is a template literal`;

模板字符串有两个基本的特点。一个是它可以多行

const foo = `this
is
a
template
literal`;
const bar = "this\nis\na\ntemplate\nliteral";

上面的foobar是一样的。

另一个是你可以超越字符串模式 使用${javascript表达式}插入JavaScript代码段。这是模板部分。比如:

const r = 192;
const g = 255;
const b = 64;
const rgbCSSColor = `rgb(${r},${g},${b})`;

or

const color = [192, 255, 64];
const rgbCSSColor = `rgb(${color.join(',')})`;

or

const aWidth = 10;
const bWidth = 20;
someElement.style.width = `${aWidth + bWidth}px`;

学习JavaScript代码风格。

尽管欢迎您以任何方式组织您的代码,但至少有一个约定您应该知道。 在JavaScript中变量、函数名、方法名 都是小驼峰。构造函数、类名都是 大驼峰。如果你遵守这些约定你的diamagnetic将会和大部分JavaScript匹配。

考虑使用Visual Studio Code

当然你想想用什么编辑器就用什么但是如果你没尝试过它那就考虑下 使用Visual Studio Code来写JavaScript。 安装完之后设置 eslint。 可能会花几分钟来设置但是会对你寻找JavaScript的bug有极大的帮助。

一些例子

如果你开启no-undef规则然后 VSCode通过ESLint将会警告你很多没有定义的变量。

上面你可以看到我将doTheThing误写成了doThing。有一个红色的曲线 在doThing下面并且鼠标悬停会提醒我们它未定义。这样就避免了一个错误。

使用THREE会得到警告所以将/* global THREE */放在你的 JavaScript文件的顶部来告诉eslintTHREE的存在。

上面你可以看到eslint知道使用UpperCaseNames规则的是构造函数 所以你应该使用new操作符。另一个错误被捕捉并避免了。这是the new-cap规则

这里有100多条规则你可以打开或者关闭或者自定义 。比如上面我提醒你 应该使用constlet代替var

这里我使用了var它警告我应该使用let或者const

这里我是用了let但是它发现我一直没改变值所以建议我使const

当然如果你更希望继续使用var你只要关闭那条规则。 如我上面所说所以我更喜欢使用constlet而不是var因为 他们工作的更好而且能减少bugs。

对于确实需要重写这些规则的情况你可以添加注释 来禁用 他们 通过单行或者一段代码。

如果你确实需要支持老的浏览器请使用编译器

大多数现代浏览器都是自动更新的,所以使用这些新的特性会帮助你提高效率 和避免bug。意思是说,如果你正在做一个需要支持老的浏览器的项目, 有工具会把ES5/ES6/ES7代码 转换成ES5之前的Javascript.