ECMAScript 6教程 (三) Class和Module(类和模块)

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文连接,博客地址为 http://www.cnblogs.com/jasonnode/ 。该系列课程是汇智网 整理编写的,课程地址为 http://www.hubwiz.com/course/5594e91ac086935f4a6fb8ef/

Class基本语法



ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

//定义类class Point {
    constructor(x, y) {        this.x = x;        this.y = y;
    }
    toString() {         return ‘(‘+this.x+‘, ‘+this.y+‘)‘;
    }
}

上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。

constructor方法

constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。

实例对象

var point = new Point(2, 3);

name属性

class Point {}
Point.name // "Point"

class表达式

与函数一样,Class也可以使用表达式的形式定义。

const MyClass = class Me {
    getClassName() {        return Me.name;
    }
};

Class的继承



Class之间可以通过extends关键字,实现继承。

子类会继承父类的属性和方法。

class Point {
    constructor(x, y) {        this.x = x;        this.y = y;
    }
}
 
class ColorPoint extends Point {
    constructor(x, y, color) {        this.color = color; // ReferenceError        super(x, y);        this.color = color; // 正确    }
}

上面代码中,子类的constructor方法没有调用super之前,就使用this关键字,结果报错,而放在super方法之后就是正确的。

注意:ColorPoint继承了父类Point,但是它的构造函数必须调用super方法。

下面是生成子类实例的代码。

let cp = new ColorPoint(25, 8, ‘green‘);
 
cp instanceof ColorPoint // truecp instanceof Point // true

class的取值函数(getter)和存值函数(setter)



在Class内部可以使用get和set关键字,对某个属性设置存值函数和取值函数。

class MyClass {
  get prop() {
    return ‘getter‘;
  }
  set prop(value) {
    document.write(‘setter: ‘+value);
  }
}
 
let inst = new MyClass();
 
inst.prop = 123;// setter: 123 inst.prop// ‘getter‘

Class的Generator方法



如果某个方法之前加上星号(*),就表示该方法是一个Generator函数。

class Foo {
    constructor(...args) {        this.args = args;
    }    * [Symbol.iterator]() {        for (let arg of this.args) {
            yield arg;
        }
    }
} 
for (let x of new Foo(‘hello‘, ‘world‘)) {
    document.write(x);
}// hello// world

上面代码中,Foo类的Symbol.iterator方法前有一个星号,表示该方法是一个Generator函数。Symbol.iterator方法返回一个Foo类的默认遍历器,for...of循环会自动调用这个遍历器。

上面代码中,prop属性有对应的存值函数和取值函数,因此赋值和读取行为都被自定义了。

Class的静态方法



类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

class Foo {
    static classMethod() {        return ‘hello‘;
    }
}
Foo.classMethod() // ‘hello‘var foo = new Foo();
foo.classMethod()// TypeError: undefined is not a function

上面代码中,Foo类的classMethod方法前有static关键字,表明该方法是一个静态方法,可以直接在Foo类上调用(Foo.classMethod()),而不是在Foo类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。

父类的静态方法,可以被子类继承。

class Foo {
    static classMethod() {        return ‘hello‘;
    }
}
class Bar extends Foo {
}
Bar.classMethod(); // ‘hello‘

上面代码中,父类Foo有一个静态方法,子类Bar可以调用这个方法。

静态方法也是可以从super对象上调用的。

class Foo {
    static classMethod() {        return ‘hello‘;
    }
}
class Bar extends Foo {
    static classMethod() {        return super.classMethod() + ‘, too‘;
    }
}
Bar.classMethod();

new.target属性



new是从构造函数生成实例的命令。ES6为new命令引入了一个new.target属性,(在构造函数中)返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。

function Person(name) {
  if (new.target !== undefined) {
    this.name = name;
  } else {
    throw new Error(‘必须使用new生成实例‘);
  }
} 
// 另一种写法function Person(name) {
  if (new.target === Person) {
    this.name = name;
  } else {
    throw new Error(‘必须使用new生成实例‘);
  }
} 
var person = new Person(‘张三‘); // 正确var notAPerson = Person.call(person, ‘张三‘); // 报错

上面代码确保构造函数只能通过new命令调用。

  • Class内部调用new.target,返回当前Class。
  • 子类继承父类时,new.target会返回子类。

修饰器



修饰器(Decorator)是一个表达式,用来修改类的行为。

修饰器函数可以接受三个参数,依次是目标函数、属性名和该属性的描述对象。后两个参数可省略。上面代码中,testable函数的参数target,就是所要修饰的对象。如果希望修饰器的行为,能够根据目标对象的不同而不同,就要在外面再封装一层函数。

function testable(isTestable) {return function(target) {
  target.isTestable = isTestable;
}
}
 
@testable(true) class MyTestableClass () {}
document.write(MyTestableClass.isTestable) // true @testable(false) class MyClass () {}
document.write(MyClass.isTestable) // false

如果想要为类的实例添加方法,可以在修饰器函数中,为目标类的prototype属性添加方法。

function testable(target) {
    target.prototype.isTestable = true;
}
 
@testable
class MyTestableClass () {}
 
let obj = new MyClass();
 
document.write(obj.isTestable) // true

export命令



模块功能主要由两个命令构成:export和import。

  • export命令用于用户自定义模块,规定对外接口;
  • import命令用于输入其他模块提供的功能,同时创造命名空间(namespace),防止函数名冲突。

ES6允许将独立的JS文件作为模块,允许一个JavaScript脚本文件调用另一个脚本文件。

现有profile.js文件,保存了用户信息。ES6将其视为一个模块,里面用export命令对外部输出了三个变量。

// profile.jsvar firstName = ‘Michael‘;var lastName = ‘Jackson‘;var year = 1958;
 
export {firstName, lastName, year};

import命令



使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)。

// main.jsimport {firstName, lastName, year} from ‘./profile‘; 
function sfirsetHeader(element) {
  element.textContent = firstName + ‘ ‘ + lastName;
}

上面代码属于另一个文件main.js,import命令就用于加载profile.js文件,并从中输入变量。import命令接受一个对象(用大括号表示),里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。

如果想为输入的变量重新取一个名字,import语句中要使用as关键字,将输入的变量重命名。

import { lastName as surname } from ‘./profile‘;

ES6支持多重加载,即所加载的模块中又加载其他模块。

模块的整体输入



export命令除了输出变量,还可以输出方法或类(class)。下面是一个circle.js文件,它输出两个方法area和circumference。

// circle.jsexport function area(radius) {
  return Math.PI * radius * radius;
}
export function circumference(radius) {
  return 2 * Math.PI * radius;
}

然后,main.js输入circlek.js模块。

// main.jsimport { area, circumference } from ‘circle‘;
document.write("圆面积:" + area(4));
document.write("圆周长:" + circumference(14));

上面写法是逐一指定要输入的方法。另一种写法是整体输入。

import * as circle from ‘circle‘;
document.write("圆面积:" + circle.area(4));
document.write("圆周长:" + circle.circumference(14));

module命令



module命令可以取代import语句,达到整体输入模块的作用。

// main.jsmodule circle from ‘circle‘;
 
document.write("圆面积:" + circle.area(4));
document.write("圆周长:" + circle.circumference(14));

module命令后面跟一个变量,表示输入的模块定义在该变量上。

export default命令



为加载模块指定默认输出,使用export default命令。

// export-default.jsexport default function () {
  document.write(‘foo‘);
}

上面代码是一个模块文件export-default.js,它的默认输出是一个函数。

其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。

// import-default.jsimport customName from ‘./export-default‘;
customName(); // ‘foo‘

上面代码的import命令,可以用任意名称指向export-default.js输出的方法。需要注意的是,这时import命令后面,不使用大括号。

模块的继承



模块之间也可以继承。

假设有一个circleplus模块,继承了circle模块。

// circleplus.js export * from ‘circle‘;
export var e = 2.71828182846;
export default function(x) {
  return Math.exp(x);
}

上面代码中的“export *”,表示输出circle模块的所有属性和方法,export default命令定义模块的默认方法。

这时,也可以将circle的属性或方法,改名后再输出。

// circleplus.js export { area as circleArea } from ‘circle‘;

上面代码表示,只输出circle模块的area方法,且将其改名为circleArea。

加载上面模块的写法如下。

// main.js module math from "circleplus";
import exp from "circleplus";
document.write(exp(math.pi));

上面代码中的"import exp"表示,将circleplus模块的默认方法加载为exp方法。

时间: 2024-10-26 06:40:21

ECMAScript 6教程 (三) Class和Module(类和模块)的相关文章

Android基础入门教程——8.3.1 三个绘图工具类详解

Android基础入门教程--8.3.1 三个绘图工具类详解 标签(空格分隔): Android基础入门教程 本节引言: 上两小节我们学习了Drawable以及Bitmap,都是加载好图片的,而本节我们要学习的绘图相关的 一些API,他们分别是Canvas(画布),Paint(画笔),Path(路径)!本节非常重要,同时也是我们 自定义View的基础哦~好的,话不多说开始本节内容~ 官方API文档:Canvas:Paint:Path: 1.相关方法详解 1)Paint(画笔): 就是画笔,用于设

electron教程(三): 使用ffi-napi引入C++的dll

我的electron教程系列 electron教程(一): electron的安装和项目的创建 electron教程(二): http服务器, ws服务器, 进程管理 electron教程(三): 使用ffi-napi引入C++的dll ? 引言 ? 这一篇将介绍如何在node.js+electron环境中, 使用node-ffi/ffi-napi调用C/C++编写的动态链接库(即dll), 实现调用C/C++代码. 本教程适用于electron 4.x-6.x版本. 如electron 4.2

Junit 4 Tutorials(Junit 4 教程) 三、Junit4 断言方法

Junit 4 断言方法允许检查测试方法的期望结果值和真实返回值.Junit的org.junit.Assert类提供了各种断言方法来写junit测试.这些方法被用来检查方法的真实结果值和期望值.下列一些有用的断言方法列表: Junit 4 Assert Methods Method Description assertNull(java.lang.Object object) 检查对象是否为空 assertNotNull(java.lang.Object object) 检查对象是否不为空 as

AngularJS Module类的方法

AngularJS Module类的方法 AngularJS中的Module类负责定义应用如何启动,它还可以通过声明的方式定义应用中的各个片段.我们来看看它是如何实现这些功能的. 一.Main方法在哪里 如果你是从Java或者Python编程语言转过来的,那么你可能很想知道AngularJS里面的main方法在哪里?这个把所有东西启动起来,并且第一个被执行的方法在哪里?JavaScript代码里面负责实例化并且把所有东西组合到一起,然后命令应用开始运行的那个方法在哪里? 事实上,AngularJ

BootStrap入门教程 (三)

上讲回顾:Bootstrap的基础CSS(Base CSS)提供了优雅,一致的多种基础Html页面要素,包括排版,表格,表单,按钮等,能够满足前端工程师的基本要素需求. Bootstrap作为完整的前端工具集,内建了大量的强大优雅可重用的组件,包括按钮(Button),导航(Navigation),标签(Labels),徽章(Badges),排版(Typography),缩略图( thumbnails),提醒(Alert),进度条(progress bar),杂项(Miscellaneous).

I学霸官方免费教程三十一:Java集合框架之List集合

集合框架 在数组的使用过程中可以看到,想要向数组中插入元素和删除元素非常麻烦,而且数组的长度是无法改变的.java为我们提供了批量存储数据更加方便的容器,就是集合.集合和数组的作用一样,都是为了使用一个变量来存储一批数据的:但集合使用起来更加方便,而且集合的长度是可以变化的. List接口 List集合可以存储有序的,可重复的数据:常用的子类是ArrayList和LinkedList两个类 ArrayList类 这是一个底层由数组实现的集合类,是对数组进行了封装. 实例: package col

I学霸官方免费教程三十二:Java集合框架之Set集合

Set接口 Set集合是无序的.元素不可重复的结合常用集合类有HashSet和TreeSet HashSet类常用的两种List集合各有各的优点,那么有没有同时具备这两种List集合的优点的集合呢?答案是肯定的,就是Set集合. 实例: package collection.set.hashSet; import java.util.HashSet; import java.util.Iterator; /**  * 演示HashSet  * @author 学霸联盟 - 赵灿  */ publ

PySide——Python图形化界面入门教程(三)

PySide——Python图形化界面入门教程(三) ——使用内建新号和槽 ——Using Built-In Signals and Slots 上一个教程中,我们学习了如何创建和建立交互widgets,以及将他们布局的两种不同的方法.今天我们继续讨论Python/Qt应用响应用户触发的事件:信号和槽. 当用户执行一个动作——点击按钮,选择组合框的值,在文本框中打字——这个widget就会发出一个信号.这个信号自己什么都不做,它必须和槽连接起来才行.槽是一个接受信号的执行动作的对象. 连接内建P

BootStrap入门教程 (三) :可重用组件(按钮,导航,标签,徽章,排版,缩略图,提醒,进度条,杂项)

上讲回顾:Bootstrap的基础CSS(Base CSS)提供了优雅,一致的多种基础Html页面要素,包括排版,表格,表单,按钮等,能够满足前端工程师的基本要素需求. Bootstrap作为完整的前端工具集,内建了大量的强大优雅可重用的组件,包括按钮(Button),导航(Navigation),标签(Labels),徽章(Badges),排版(Typography),缩略图( thumbnails),提醒(Alert),进度条(progress bar),杂项(Miscellaneous).