1
0
mirror of https://github.com/ruanyf/es6tutorial.git synced 2025-05-24 18:32:22 +00:00
es6tutorial/docs/class.md
2014-12-12 08:40:44 +08:00

413 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Class和Module
## Class
ES5通过构造函数定义并生成新对象。下面是一个例子。
```javascript
function Point(x,y){
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '('+this.x+', '+this.y+')';
}
```
ES6引入了Class这个概念作为对象的模板。通过class关键字可以定义类。上面的代码用“类”改写就是下面这样。
```javascript
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '('+this.x+', '+this.y+')';
}
}
var point = new Point(2,3);
point.toString() // (2, 3)
```
上面代码定义了一个“类”可以看到里面有一个constructor函数这就是构造函数而this关键字则代表实例对象。这个类除了构造方法还定义了一个toString方法。注意定义方法的时候前面不需要加上function这个保留字直接把函数定义放进去了就可以了。
Class之间可以通过extends关键字实现继承。
```javascript
class ColorPoint extends Point {}
```
上面代码定义了一个ColorPoint类该类通过extends关键字继承了Point类的所有属性和方法。但是由于没有部署任何代码所以这两个类完全一样等于复制了一个Point类。下面我们在ColorPoint内部加上代码。
```javascript
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 等同于super.constructor(x, y)
this.color = color;
}
toString() {
return this.color+' '+super();
}
}
```
上面代码中constructor方法和toString方法之中都出现了super关键字它指代父类的同名方法。在constructor方法内super指代父类的constructor方法在toString方法内super指代父类的toString方法。
## Module的基本用法
JavaScript没有模块module体系无法将一个大程序拆分成互相依赖的小文件再用简单的方法拼装起来。其他语言都有这项功能比如Ruby的require、Python的import甚至就连CSS都有@import但是JavaScript任何这方面的支持都没有这对开发大型的、复杂的项目形成了巨大障碍。
在ES6之前社区制定了一些模块加载方案最主要的有CommonJS和AMD两种。前者用于服务器后者用于浏览器。ES6在语言规格的层面上实现了模块功能而且实现得相当简单完全可以取代现有的CommonJS和AMD规范成为浏览器和服务器通用的模块解决方案。
**1export命令import命令**
模块功能主要由两个命令构成export和import。export命令用于用户自定义模块规定对外接口import命令用于输入其他模块提供的功能同时创造命名空间namespace防止函数名冲突。
ES6允许将独立的JS文件作为模块也就是说允许一个JavaScript脚本文件调用另一个脚本文件。该文件内部的所有变量外部无法获取必须使用export关键字输出变量。下面是一个JS文件里面使用export关键字输出变量。
```javascript
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
```
上面代码是profile.js文件保存了用户信息。ES6将其视为一个模块里面用export命令对外部输出了三个变量。
export的写法除了像上面这样还有另外一种。
```javascript
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
```
上面代码在export命令后面使用大括号指定所要输出的一组变量。它与前一种写法直接放置在var语句前是等价的但是应该优先考虑使用这种写法。因为这样就可以在脚本尾部一眼看清楚输出了哪些变量。
使用export命令定义了模块的对外接口以后其他JS文件就可以通过import命令加载这个模块文件
```javascript
// main.js
import {firstName, lastName, year} from './profile';
function sfirsetHeader(element) {
element.textContent = firstName + ' ' + lastName;
}
```
上面代码属于另一个文件main.jsimport命令就用于加载profile.js文件并从中输入变量。import命令接受一个对象用大括号表示里面指定要从其他模块导入的变量名。大括号里面的变量名必须与被导入模块profile.js对外接口的名称相同。
如果想为输入的变量重新取一个名字import语句中要使用as关键字将输入的变量重命名。
```javascript
import { lastName as surname } from './profile';
```
**2模块的整体输入module命令**
export命令除了输出变量还可以输出方法或类class。下面是一个circle.js文件它输出两个方法area和circumference。
```javascript
// circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
```
然后main.js输入circlek.js模块。
```javascript
// main.js
import { area, circumference } from 'circle';
console.log("圆面积:" + area(4));
console.log("圆周长:" + circumference(14));
```
上面写法是逐一指定要输入的方法。另一种写法是整体输入。
```javascript
import * as circle from 'circle';
console.log("圆面积:" + circle.area(4));
console.log("圆周长:" + circle.circumference(14));
```
module命令可以取代import语句达到整体输入模块的作用。
```javascript
// main.js
module circle from 'circle';
console.log("圆面积:" + circle.area(4));
console.log("圆周长:" + circle.circumference(14));
```
module命令后面跟一个变量表示输入的模块定义在该变量上。
**3export default命令**
如果想要输出匿名函数可以使用export default命令。
```javascript
// export-default.js
export default function () {
console.log('foo');
}
```
其他模块输入该模块时import命令可以为该匿名函数指定任意名字。
```javascript
// import-default.js
import customName from './export-default';
customName(); // 'foo'
```
上面代码的import命令可以用任意名称指向输出的匿名函数。需要注意的是这时import命令后面不使用大括号。
export default命令用在非匿名函数前也是可以的。
```javascript
// export-default.js
export default function foo() {
console.log('foo');
}
// 或者写成
function foo() {
console.log('foo');
}
export default foo;
```
上面代码中foo函数的函数名foo在模块外部是无效的。加载的时候视同匿名函数加载。
export default命令用于指定模块的默认输出。如果模块加载时只能输出一个值或方法那就是export default所指定的那个值或方法。所以import命令后面才不用加大括号。显然一个模块只能有一个默认输出因此export deault命令只能使用一次。
有了export default命令输入模块时就非常直观了以输入jQuery模块为例。
```javascript
import $ from 'jquery';
```
如果想在一条import语句中同时输入默认方法和其他变量可以写成下面这样。
```javascript
import customName, { otherMethod } from './export-default';
```
如果要输出默认的值,只需将值跟在`export default`之后即可。
```javascript
export default 42;
```
export default也可以用来输出类。
```javascript
// MyClass.js
export default class { ... }
// main.js
import MyClass from 'MyClass'
let o = new MyClass();
```
## 模块的继承
模块之间也可以继承。
假设有一个circleplus模块继承了circle模块。
```javascript
// circleplus.js
export * from 'circle';
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}
```
上面代码中的“export *”表示输出circle模块的所有属性和方法export default命令定义模块的默认方法。
这时也可以将circle的属性或方法改名后再输出。
```javascript
// circleplus.js
export { area as circleArea } from 'circle';
```
上面代码表示只输出circle模块的area方法且将其改名为circleArea。
加载上面模块的写法如下。
```javascript
// main.js
module math from "circleplus";
import exp from "circleplus";
console.log(exp(math.pi));
```
上面代码中的"import exp"表示将circleplus模块的默认方法加载为exp方法。
## ES6模块的转码
浏览器目前还不支持ES6模块为了现在就能使用可以将转为ES5的写法。
**1ES6 module transpiler**
[ES6 module transpiler](https://github.com/esnext/es6-module-transpiler)是square公司开源的一个转码器可以将ES6模块转为CommonJS模块或AMD模块的写法从而在浏览器中使用。
首先,安装这个转玛器。
```bash
$ npm install -g es6-module-transpiler
```
然后,使用`compile-modules convert`命令将ES6模块文件转码。
```bash
$ compile-modules convert file1.js file2.js
```
o参数可以指定转码后的文件名。
```bash
$ compile-modules convert -o out.js file1.js
```
**2SystemJS**
另一种解决方法是使用[SystemJS](https://github.com/systemjs/systemjs)。它是一个垫片库polyfill可以在浏览器内加载ES6模块、AMD模块和CommonJS模块将其转为ES5格式。它在后台调用的是Google的Traceur转码器。
使用时先在网页内载入system.js文件。
```html
<script src="system.js"></script>
```
然后,使用`System.import`方法加载模块文件。
```html
<script>
System.import('./app');
</script>
```
上面代码中的`./app`指的是当前目录下的app.js文件。它可以是ES6模块文件`System.import`会自动将其转码。
需要注意的是,`System.import`使用异步加载返回一个Promise对象可以针对这个对象编程。下面是一个模块文件。
```javascript
// app/es6-file.js:
export class q {
constructor() {
this.es6 = 'hello';
}
}
```
然后,在网页内加载这个模块文件。
```html
<script>
System.import('app/es6-file').then(function(m) {
console.log(new m.q().es6); // hello
});
</script>
```
上面代码中,`System.import`方法返回的是一个Promise对象所以可以用then方法指定回调函数。