类与模块

一、类

一)类的声明

class Person {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
} let tom = new Person('Tom');
tom.sayName(); //Tom
console.log(tom instanceof Person); //true
console.log(tom instanceof Object); //true
console.log(typeof Person); //function

自有属性:属性只出现在实例而不是在原型上,而且只能由构造函数和方法来创建。

差异:

1. 类声明和函数定义不同,它们是不会被提升的。类声明的行为和 let 比较相似,所以当执
行流作用到类声明之前类会存在于暂存性死区(temporal dead zone) 内。
2. 类声明中的代码自动运行在严格模式下,同时没有任何办法可以手动切换到非严格模
式。
3. 所有的方法都是不可枚举的(non-enumerable) ,这和自定义类型相比是个显著的差
异,因为后者需要使用 Object.defineProperty() 才能定义不可枚举的方法。
4. 所有的方法都不能使用 new 来调用,因为它们没有内部方法 [[Construct]]。
5. 不使用 new 来调用类构造函数会抛出错误。
6. 试图在方法内部重写类名的行为会抛出错误。

二)类表达式

设计类表达式的目的主要是为了将它赋值给变量或者传参给函数。

//不会被提升
let Person = class {
constructor(name) {
this.name = name;
} sayName() {
console.log(this.name);
}
};

三)作为一等公民的类

在编程中,如果某些东西能作为值使用,那么它就被称为一等公民。ES6中类也是一等公民:

function createPerson(person) {
return new person();
}
let tom = createPerson(class {
sayHi() {
console.log('Hi');
}
});
tom.sayHi(); //Hi

类表达式另一个有趣的使用方式是通过立即调用(immediately invoking) 类构造函数来创建单例(singleton):

let tom = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(`My name is ${this.name}`);
}
}('Tom');
tom.sayName();

四)访问器属性

class Person {
constructor(name) {
this.name = name;
}
//这里不能用get phone(){}
get phone2() {
return this.phone;
}
set phone2(phoneNumber) {
this.phone = phoneNumber;
}
}
let price = new Person('Price', 112);
price.name = 'Price2';
price.phone = 119;
console.log(`His name is ${price.name} and his phone number is ${price.phone}`);

五)静态成员

//静态成员不能被实例访问。你必须通过类本身来使用它们。
class Person {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name)
}
//等同于Person.whatIs(){}
static whatIs() {
return 'I am a person!';
}
}

六)继承

class Worker extends Person {
/*如果在派生类中定义 constructor 则必须使用super(),
否则会发生错误。如果你选择不使用 constructor,
那么会自动调用 super() 和传入构造函数的参数以创建类的实例*/
constructor(name, age) {
super(name);
this.age = age;
}
//注意
syaName() {
super.sayName();
console.log(`My name is ${this.name}`);
}
sayAge (){
console.log(`I am ${this.age}`)
}
} let jimmy = new Worker('Jimmy', 2);
jimmy.sayAge(); //I am 2
jimmy.syaName(); //Jimmy My name is Jimmy

注意: 使用 super() 需要牢记以下几点:
1. 你只能在派生类中使用 super(),否则(没有使用 extends 的类或函数) 一个错误会
被抛出。
2. 你必须在构造函数的起始位置调用 super(),因为它会初始化 this。任何在 super()
之前访问 this 的行为都会造成错误。
3. 在类构造函数中,唯一能避免调用 super() 的办法是返回一个对象。

ECMAScript 6 派生类最强大的地方在于它们可以继承一个表达式。只要该表达式的计算
结果包含 [[Construct]] 的函数和一个原型,那么就可以使用 extends 来继承它。

内置对象的继承

使用ES5很难继承内置对象,ES6做法:

class MyArray extends Array {
}

二、模块

在 ECMAScript 6 之前,每个 JavaScript 文件中定义的内容都由全局作用域共享。
当 web 应用变得复杂并需要书写更多的 JavaScript 代码时,上述加载方式会出现命名冲突或安全方面的问题。

模块是指采取不同于现有加载方式的 JavaScript 文件(与 script 这种传统的加载模式相
对) 。这种方式很有必要,因为它和 script 使用不同的语义:
1. 模块中的代码自动运行在严格模式下,并无任何办法修改为非严格模式。
2. 模块中的顶级(top level) 变量不会被添加到全局作用域中。它们只存在于各自的模块中
的顶级作用域。
3. 模块顶级作用域中的 this 为 undefined 。
4. 模块不允许存在 HTML 式的注释(JavaScript 历史悠久的遗留特性) 。
5. 模块必须输出可被模块外部代码使用的相关内容。
6. 模块可能会引入其它模块中的绑定。

模块真正的好处在于可以输出和引入需要的绑定,而不是文件中的所有内容。

理解输出和引入是领悟模块与 script 之间差异的基础。

一)导出(export)

可以使用export关键字将已发布的代码部分公开给其他模块。例如:

    // 导出数据
export var color = "red";
export let name = "Nicholas";
export const magicNumber = 7;
// 导出函数
export function sum(num1, num2) {
return num1 + num1;
}
// 导出类
export class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
}
// 此函数为模块私有
function subtract(num1, num2) {
return num1 - num2;
}
// 定义一个函数……
function multiply(num1, num2) {
return num1 * num2;
}
// ……稍后将其导出
export { multiply };

二)导入

一旦你有了包含导出的模块,就能在其他模块内使用 import 关键字来访问已被导出的功能:

import { identifier1, identifier2 } from "./example.js";
// 完全导入
import * as example from "./example.js";

当从模块导入了一个绑定时,该绑定表现得就像使用了 const 的定义。这意味着你不能再定
义另一个同名变量(包括导入另一个同名绑定) ,也不能在对应的 import 语句之前使用此
标识符(也就是要受暂时性死区限制) ,更不能修改它的值。

    export var name = "Nicholas";
export function setName(newName) {
name = newName;
}
import { name, setName } from "./example.js";
console.log(name); // "Nicholas"
setName("Greg");
console.log(name); // "Greg"
name = "Nicholas"; // error

调用 setName("Greg") 会回到导出 setName() 的模块内部,并在那里执行,从而将 name 设
置为 "Greg" 。注意这个变化会自动反映到所导入的 name 绑定上,这是因为绑定的 name
是导出的 name 标识符的本地名称,二者并非同一个事物。

外部模块导入的 name 变量与在 example.js 模块内部的 name 变量对比,
前者是对于后者的只读引用,会始终反映出后者的变化。就算后者的值在负责导出的模块中发生了变化,
这种绑定关系也不会被破坏。模块导出与导入的绑定机制,与写在一个文件或模块内的代码是不同的。

三)重命名

function sum(num1, num2) {
return num1 + num2;
}
export { sum as add };

此时必须使用:

import { add } from "./example.js";

导入重命名:

import { add as sum } from "./example.js";

四)再导出

import { sum } from "./example.js";
export { sum }

五)在Web浏览器使用模块

<!-- this will execute first -->
<script type="module" src="module1.js"></script>
<!-- this will execute second -->
<script type="module">
import { sum } from "./example.js";
let result = sum(1, 2);
</script>
<!-- this will execute third -->
<script type="module" src="module2.js"></script>
<script type="module" async src="module1.js"></script>
<script type="module" async src="module2.js"></script>

ES6快速入门(三)类与模块的更多相关文章

  1. es6 快速入门 系列 —— 类 (class)

    其他章节请看: es6 快速入门 系列 类 类(class)是 javascript 新特性的一个重要组成部分,这一特性提供了一种更简洁的语法和更好的功能,可以让你通过一个安全.一致的方式来自定义对象 ...

  2. python 全栈开发,Day88(csrf_exempt,ES6 快速入门,Vue)

    BBS项目内容回顾 1. 登陆页面 1. 验证码 1. PIL(Pillow) 2. io 2. ORM 1. 增删改查 3. AJAX $.ajax({ url: '', type: '', dat ...

  3. ES6快速入门(二)数据结构

    ES6快速入门 一.解构 1. 对象解构 let person = { name: 'Tang', age: 28 }; //必须同名,必须初始化 let {name, age} = person; ...

  4. ES6快速入门(一)函数与作用域

    ES6快速入门 一.块级绑定 1.var声明与变量提升 使用var声明的变量,不论在何处都会被视为(声明)在函数级作用域顶部的位置发生. function getValue(condition) { ...

  5. es6 快速入门 —— 函数

    其他章节请看: es6 快速入门 系列 函数 函数是所有编程语言的重要组成部分,es6之前函数语法一直没什么变化,遗留了许多问题,javaScript开发者多年来不断抱怨,es6终于决定大力度更新函数 ...

  6. es6 快速入门 系列 —— promise

    其他章节请看: es6 快速入门 系列 Promise Promise 是一种异步编程的选择 初步认识Promise 用 Promise 来实现这样一个功能:发送一个 ajax,返回后输出 json ...

  7. es6 快速入门 系列

    es6 快速入门(未完结,持续更新中...) 前言 为什么要学习es6 es6对于所有javaScript开发者来说,非常重要 未来,es6将构成javaScript应用程序的基础 es6中很多特性, ...

  8. es6 快速入门 系列 —— 变量声明:let和const

    其他章节请看: es6 快速入门 系列 变量声明:let和const 试图解决的问题 经典的 var 声明让人迷惑 function demo1(v){ if(v){ var color='red' ...

  9. es6快速入门 系列 - async

    其他章节请看: es6 快速入门 系列 async 前文我们已经知道 promise 是一种异步编程的选择.而 async 是一种用于执行异步任务更简单的语法. Tip:建议学完 Promise 在看 ...

  10. es6 快速入门 系列 —— 对象

    其他章节请看: es6 快速入门 系列 对象 试图解决的问题 写法繁杂 属性初始值需要重复写 function createPeople(name, age){ // name 和 age 都写了 2 ...

随机推荐

  1. lisp : set 与setq 函数

    在Lisp中,如果我们希望对一个变量赋值,可以使用set函数,用法如下: (set ‘my-value "my string") 上面的代码是对变量my-value进行赋值,值是& ...

  2. 2017-2018-2 20165328 实验三《敏捷开发与XP实践》实验报告

    一.实践-1: 要求:参考http://www.cnblogs.com/rocedu/p/6371315.html#SECCODESTANDARD安装alibaba插件,解决代码中的规范问题. 在ID ...

  3. 新的表格展示利器 Bootstrap Table Ⅰ

     1.bootstrap table简介及特征 Bootstrap Table是国人开发的一款基于 Bootstrap 的 jQuery 表格插件,通过简单的设置,就可以拥有强大的单选.多选.排序.分 ...

  4. MySQL Windows 下的安装

    my.ini ####################配置文件开始################### # For advice on how to change settings please s ...

  5. sinoces 2013 消费电子

    转眼距离上次看消费电子(http://www.cnblogs.com/sun8134/archive/2012/07/08/2581997.html)又过了一年 也到了今年的消费电子展… 结果一天小雨 ...

  6. Oracle Client(客户端) 安装与配置

    因为工作需要,需要通过本地oracle客户端将数据导入到远程服务器上的oracle数据库中.从csdn下了很多oracle客户端,都是属于精简版,缺少imp.exe文件,造成无法导入数据.所以最终从o ...

  7. BZOJ 3745

    题解: 分治好题 首先暴力显然rmq可以做到n^2 比较容易想到是以最值分治,这样在数据随机复杂度是nlogn,不随机还是n^2的 以最值分治只有做多与较小区间复杂度相同才是nlogn的 而这题里我们 ...

  8. dos文件(夹)复制命令:copy和xcopy

    1.copy命令 将一份或多份文件复制到另一个位置. COPY [/D] [/V] [/N] [/Y | /-Y] [/Z] [/L] [/A | /B ] source [/A | /B] [+ s ...

  9. BZOJ3393 [Usaco2009 Jan]Laserphones 激光通讯 BFS

    原文链接http://www.cnblogs.com/zhouzhendong/p/8371735.html 题目传送门 - BZOJ3393 题意概括 直接看原题的翻译吧,很容易懂的. 题解 我不知 ...

  10. 不同路径II(一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。 现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?网格中的障碍物和空位置分别用 1 和 0 来表示。)

    示例 1: 输入: [   [0,0,0],   [0,1,0],   [0,0,0] ] 输出: 2 解释: 3x3 网格的正中间有一个障碍物. 从左上角到右下角一共有 2 条不同的路径: 1. 向 ...