博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
12.3 ES6 新特性- Set、Map、class 类和模块化
阅读量:3933 次
发布时间:2019-05-23

本文共 12921 字,大约阅读时间需要 43 分钟。

文章目录


1. Set

ES6 提供了新的数据结构Set(集合)。类似于数组,但Set 中元素值都是唯一的Set 对象允许你存储任何类型的唯一值,无论是或者是对象引用。

集合实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历,集合的属性和方法:

  1. size 返回集合的元素个数

  2. add 增加一个新元素,返回当前集合

  3. delete 删除元素,返回boolean 值

  4. has 检测集合中是否包含某个元素,返回boolean 值

  5. clear 清空集合,返回undefined

Set相关属性和方法的使用

let mySet = new Set();mySet.add(1); // Set [ 1 ]mySet.add(5); // Set [ 1, 5 ]mySet.add(5); // 自动去重:Set [ 1, 5 ]mySet.add("some text"); // Set [ 1, 5, "some text" ]let o = {
a: 1, b: 2};mySet.add(o);mySet.add({
a: 1, b: 2}); // o 指向的是不同的对象,所以没问题mySet.size; // 5mySet.has(1); // truemySet.has(3); // falsemySet.has(5); // truemySet.has(Math.sqrt(25)); // truemySet.has("Some Text".toLowerCase()); // truemySet.has(o); // truemySet.delete(5); // true, 从set中移除5mySet.has(5); // false, 5已经被移除mySet.size; // 4, 刚刚移除一个值console.log(mySet);// logs Set(4) [ 1, "some text", {…}, {…} ] in Firefox// logs Set(4) { 1, "some text", {…}, {…} } in Chrome

迭代Set

// 迭代整个set// 按顺序输出:1, "some text", {"a": 1, "b": 2}, {"a": 1, "b": 2}for (let item of mySet) console.log(item);// 按顺序输出:1, "some text", {"a": 1, "b": 2}, {"a": 1, "b": 2}for (let item of mySet.keys()) console.log(item);// 按顺序输出:1, "some text", {"a": 1, "b": 2}, {"a": 1, "b": 2}for (let item of mySet.values()) console.log(item);// 按顺序输出:1, "some text", {"a": 1, "b": 2}, {"a": 1, "b": 2}//(键与值相等)for (let [key, value] of mySet.entries()) console.log(key);// 用forEach迭代mySet.forEach(function(value) {
console.log(value);});

Set 和 Array互换

let myArray = ["value1", "value2", "value3"];// 用Set构造器将Array转换为Setlet mySet = new Set(myArray);mySet.has("value1"); // returns true// 用...(展开操作符)操作符将Set转换为Array[...mySet]; // 与myArray完全一致// 使用 Array.from 转换Set为Arrayvar myArr = Array.from(mySet); //数组去重const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]console.log([...new Set(numbers)])// [2, 3, 4, 5, 6, 7, 32]

字符串相关

let text = 'India';let mySet = new Set(text);  // Set {'I', 'n', 'd', 'i', 'a'}mySet.size;  // 5// 大小写敏感 & duplicate ommisionnew Set("Firefox")  // Set(7) [ "F", "i", "r", "e", "f", "o", "x" ]new Set("firefox")  // Set(6) [ "f", "i", "r", "e", "o", "x" ]

2. Map

ES6 提供了Map 数据结构。它类似于对象,也是键值对的集合,并且能够记住键的原始插入顺序。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。

1. Objects 和 maps 的比较

Maps 类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此过去我们一直都把对象当成 Maps 使用。不过 MapsObjects 有一些重要的区别,在下列情况里使用 Map 会是更好的选择

。。。。 Map Object
意外的键 Map 默认情况不包含任何键。只包含显式插入的键。 一个 Object 有一个原型, 原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。注意: 虽然 ES5 开始可以用 Object.create(null) 来创建一个没有原型的对象,但是这种用法不太常见。
键的类型 一个 Map的键可以是任意值,包括函数、对象或任意基本类型。 一个Object 的键必须是一个 或是。
键的顺序 Map 中的 key 是有序的。因此,当迭代的时候,一个 Map 对象以插入的顺序返回键值。 一个 Object 的键是无序的注意:自ECMAScript 2015规范以来,对象确实保留了字符串和Symbol键的创建顺序; 因此,在只有字符串键的对象上进行迭代将按插入顺序产生键。
Size Map 的键值对个数可以轻易地通过 属性获取 Object 的键值对个数只能手动计算
迭代 Map 是 的,所以可以直接被迭代。 迭代一个Object需要以某种方式获取它的键然后才能迭代。
性能 在频繁增删键值对的场景下表现更好。 在频繁添加和删除键值对的场景下未作出优化。

2. Map 的属性和方法

  1. size 返回Map 的元素个数

  2. set 增加一个新元素,返回当前Map

  3. get 返回键名对象的键值

  4. delete 如果 Map 对象中存在该元素,则移除它并返回 true;否则如果该元素不存在则返回 false

  5. has 检测Map 中是否包含某个元素,返回boolean 值

  6. clear 清空集合,返回undefined

使用Map对象

let myMap = new Map();let keyObj = {
};let keyFunc = function() {
};let keyString = 'a string';// 添加键myMap.set(keyString, "和键'a string'关联的值");myMap.set(keyObj, "和键keyObj关联的值");myMap.set(keyFunc, "和键keyFunc关联的值");myMap.size; // 3// 读取值myMap.get(keyString); // "和键'a string'关联的值"myMap.get(keyObj); // "和键keyObj关联的值"myMap.get(keyFunc); // "和键keyFunc关联的值"myMap.get('a string'); // "和键'a string'关联的值" // 因为keyString === 'a string'myMap.get({
}); // undefined, 因为keyObj !== {}myMap.get(function() {
}); // undefined, 因为keyFunc !== function () {}

迭代Map

// 使用for..of循环来实现迭代:let myMap = new Map();myMap.set(0, "zero");myMap.set(1, "one");for (let [key, value] of myMap) {
console.log(key + " = " + value); // 将会显示两个log。一个是"0 = zero"另一个是"1 = one"}for (let key of myMap.keys()) {
console.log(key); // 将会显示两个log。 一个是 "0" 另一个是 "1"}for (let value of myMap.values()) {
console.log(value); // 将会显示两个log。 一个是 "zero" 另一个是 "one"}//通过forEach()方法迭代:myMap.forEach(function(value, key) {
console.log(key + " = " + value);})// 将会显示两个logs。 一个是 "0 = zero" 另一个是 "1 = one"

复制或合并Maps

//Map 能像数组一样被复制:let original = new Map([  [1, 'one']]);let clone = new Map(original);console.log(clone.get(1)); // oneconsole.log(original === clone); // false. 浅比较 不为同一个对象的引用//Map对象间可以进行合并,但是会保持键的唯一性。let first = new Map([  [1, 'one'],  [2, 'two'],  [3, 'three'],]);let second = new Map([  [1, 'uno'],  [2, 'dos']]);// 合并两个Map对象时,如果有重复的键值,则后面的会覆盖前面的。// 展开运算符本质上是将Map对象转换成数组。let merged = new Map([...first, ...second]);console.log(merged.get(1)); // unoconsole.log(merged.get(2)); // dosconsole.log(merged.get(3)); // three

3. class 类

在ES6中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。class 的本质是 function。类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。

它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。

3.1 类的定义与声明

// 匿名类let Example = class {
constructor(a) {
this.a = a; }}// 命名类let Example = class Example {
constructor(a) {
this.a = a; }}//类的声明class Example {
constructor(a) {
this.a = a; }}

注意要点

  1. 不可重复声明。

  2. 类定义不会被提升,这意味着,必须在访问前对类进行定义,否则就会报错。

  3. 类中方法不需要 function 关键字。

  4. 方法间不能加分号。

3.2 类的属性

1. prototype:ES6 中,prototype 仍旧存在,虽然可以直接自类中定义方法,但是其实方法还是定义在 prototype 上的。 覆盖方法 / 初始化时添加方法

Example.prototype={
//methods}//添加方法Object.assign(Example.prototype,{
//methods})

2. 静态属性:class 本身的属性,即直接定义在类内部的属性( Class.propname ),不需要实例化。 ES6 中规定,Class 内部只有静态方法,没有静态属性。

class Example {
// 新提案 static a = 2;}// 目前可行写法Example.b = 2;

3. 公共属性

class Example{
}Example.prototype.a = 2;

4. 实例属性:定义在实例对象( this )上的属性。

//实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层。class Example {
a = 2; constructor () {
this._count = 0; console.log(this.a); }}//上面代码中,a 就是Example的实例属性。在Example的实例上,可以读取这个属性。

5. name 属性:返回跟在 class 后的类名(存在时)。

let Example = class Exam {
constructor(a) {
this.a = a; }}console.log(Example.name); // Exam let Example=class {
constructor(a) {
this.a = a; }}console.log(Example.name); // Example

3.3 类的方法

类的所有方法都定义在类的prototype属性上面。

在类的实例上面调用方法,其实就是调用原型上的方法。bB类的实例,它的constructor方法就是B类原型的constructor方法。

class B {
}let b = new B();b.constructor === B.prototype.constructor // true

类的所有实例共享一个原型对象。p1p2都是Point的实例,它们的原型都是Point.prototype,所以__proto__属性是相等的。

var p1 = new Point(2,3);var p2 = new Point(3,2); p1.__proto__ === p2.__proto__ //true

1. constructor 方法:constructor 方法是类的默认方法,创建类的实例化对象时被调用

  • 在使用new关键字生成对象时,constructor方法会被执行,最终return的结果就是生成的对象实例
  • 当一个类没有constructor方法时会自动生成一个空的constructor方法,返回结果为空。
  • 用new关键字实例化对象时传入的参数会做为constructor构造函数的参数传入
class Example{
constructor(){
console.log('我是constructor'); }}new Example(); // 我是constructor

2. 静态方法该方法不会实例被继承,而是直接通过类来调用

静态方法只能在当前类上调用,不能被该类的实例对象调用。父类的静态方法可以被子类继承。

因此静态方法被调用的方式一共有三种(三种调用方式都在下面一段代码中使用到了,请耐心阅读):

  • 父类直接调用
  • 子类继承父类后调用
  • 子类通过super对象调用
class Foo {
static classMethod() {
return 'hello'; }}//父类直接调用Foo.classMethod(); //hello//子类继承父类后调用class Bar extends Foo {
}Bar.classMethod(); //hell//子类通过super对象调用class Cla extends Foo {
return super.classMethod(); //hello}

3. 原型方法

class Example {
sum(a, b) {
console.log(a + b); }}let exam = new Example();exam.sum(1, 2); // 3

4. 实例方法

class Example {
constructor() {
this.sum = (a, b) => {
console.log(a + b); } }}

3.4 类的实例化

new:class 的实例化必须通过 new 关键字。

lass Example {
constructor(a, b) {
this.a = a; this.b = b; console.log('Example'); } sum() {
return this.a + this.b; }}//共享原型对象let exam1 = new Example(2, 1);let exam2 = new Example(3, 1);console.log(exam1._proto_ == exam2._proto_); // true exam1._proto_.sub = function() {
return this.a - this.b;}console.log(exam1.sub()); // 1console.log(exam2.sub()); // 2

3.5 继承

通过 extends 实现类的继承。

class Calculator {
constructor(a,b){
this.a = a; this.b = b; } add(a,b){
return ("相加結果:"+ (a+b)) }}class Son extends Calculator{
add(a,b){
console.log(super.add(a,b)) //super.add(a,b)就是调用父类中的普通函数 }}var rt = new Son()rt.add(3, 4)

子类 constructor 方法中必须有 super且必须出现在 this 之前

class Father {
constructor() {
}}class Child extends Father {
constructor() {
} // or // constructor(a) {
// this.a = a; // super(); // }}let test = new Child(); // Uncaught ReferenceError: Must call super // constructor in derived class before accessing 'this' or returning // from derived constructor

调用父类构造函数,只能出现在子类的构造函数。

class Father {
test(){
return 0; } static test1(){
return 1; }}class Child extends Father {
constructor(){
super(); }}class Child1 extends Father {
test2() {
super(); // Uncaught SyntaxError: 'super' keyword unexpected // here }}

调用父类方法, super 作为对象,在普通方法中,指向父类的原型对象,在静态方法中,指向父类

class Child2 extends Father {
constructor(){
super(); // 调用父类普通方法 console.log(super.test()); // 0 } static test3(){
// 调用父类静态方法 return super.test1+2; }}Child2.test3(); // 3

总结:

ES5中:利用借用构造函数实现实例属性和方法的继承 ; 利用原型链或者寄生式继承实现 共享的原型属性和方法的继承 。

ES6中:

利用class定义类,extends实现类的继承;

子类constructor里调用super()(父类构造函数)实现 实例属性和方法的继承;

子类原型继承父类原型,实现原型对象上方法的继承。

4. 模块化

模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件组合起来。ES6 引入了模块化,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。

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

  • export 命令用于规定模块的对外接口
  • import 命令用于输入其他模块提供的功能

4.1 特点

ES6 的模块自动开启严格模式,不管你有没有在模块头部加上 use strict;

模块中可以导入和导出各种类型的变量,如函数,对象,字符串,数字,布尔值,类等。

每个模块都有自己的上下文,每一个模块内声明的变量都是局部变量,不会污染全局作用域。

每一个模块只加载一次(是单例的), 若再去加载同目录下同文件,直接从内存中读取。

4.2 export 与 import

模块导入导出各种类型的变量,如字符串,数值,函数,类。

  • 导出的函数声明与类声明必须要有名称(export default 命令另外考虑)。
  • 不仅能导出声明还能导出引用(例如函数)。
  • export 命令可以出现在模块的任何位置,但必需处于模块顶层。
  • import 命令会提升到整个模块的头部,首先执行。
/*-----export [test.js]-----*/let myName = "Tom";let myAge = 20;let myfn = function(){
return "My name is" + myName + "! I'm '" + myAge + "years old."}let myClass = class myClass {
static a = "yeah!";}export {
myName, myAge, myfn, myClass } /*-----import [xxx.js]-----*/import {
myName, myAge, myfn, myClass } from "./test.js";console.log(myfn());// My name is Tom! I'm 20 years old.console.log(myAge);// 20console.log(myName);// Tomconsole.log(myClass.a );// yeah!

建议使用大括号指定所要输出的一组变量写在文档尾部,明确导出的接口。

函数与类都需要有对应的名称,导出文档尾部也避免了无对应名称。

4.3 import 命令的特点

只读属性:不允许在加载模块的脚本里面,改写接口的引用指向,即可以改写 import 变量类型为对象的属性值,不能改写 import 变量类型为基本类型的值。

import {
a} from "./xxx.js"a = {
}; // error import {
a} from "./xxx.js"a.foo = "hello"; // a = { foo : 'hello' }

单例模式:多次重复执行同一句 import 语句,那么只会执行一次,而不会执行多次。import 同一模块,声明不同接口引用,会声明对应变量,但只执行一次 import 。

import {
a } "./xxx.js";import {
a } "./xxx.js";// 相当于 import { a } "./xxx.js"; import {
a } from "./xxx.js";import {
b } from "./xxx.js";// 相当于 import { a, b } from "./xxx.js";

静态执行特性:import 是静态执行,所以不能使用表达式和变量。

import {
"f" + "oo" } from "methods";// errorlet module = "methods";import {
foo } from module;// errorif (true) {
import {
foo } from "method1";} else {
import {
foo } from "method2";}// error

4.4 as 的用法

export 命令导出的接口名称,须和模块内部的变量有一一对应关系。

导入的变量名,须和导出的接口名称相同,即顺序可以不一致。

使用 as 重新定义导出的接口名称,隐藏模块内部的变量/*-----export [test.js]-----*/let myName = "Tom";export {
myName as exportName } /*-----import [xxx.js]-----*/import {
exportName } from "./test.js";console.log(exportName);// Tom//不同模块导出接口名称命名重复, 使用 as 重新定义变量名。/*-----export [test1.js]-----*/let myName = "Tom";export {
myName }/*-----export [test2.js]-----*/let myName = "Jerry";export {
myName }/*-----import [xxx.js]-----*/import {
myName as name1 } from "./test1.js";import {
myName as name2 } from "./test2.js";console.log(name1);// Tomconsole.log(name2);// Jerry

5. 数值扩展

ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b 和0o 表示。

console.log(0b1111);//15console.log(0o10);//16

Number.isFinite() 用来检查一个数值是否为有限的

console.log(Number.isFinite(15));//trueconsole.log(Number.isFinite(NaN));//falseconsole.log(Number.isFinite(10/0));//false

Number.isNaN() 用来检查一个值是否为NaN

console.log(Number.isNaN(NaN));//trueconsole.log(Number.isNaN(5));//true

Number.isInteger() 判断一个数是不是整数

console.log(Number.isInteger(25));//trueconsole.log(Number.isInteger(25.0));//trueconsole.log(Number.isInteger(25.1));//false

Number.parseInt 转为整数 Number.parseFloat 转为带小数的(字符串转为数字

console.log(Number.parseInt('5211314love')); //5211314console.log(Number.parseFloat('3.1415926hh')); //3.1415926

**Math.trunc()**用于去除一个数的小数部分,返回整数部分。

console.log(Math.trunc(4.1));//4console.log(Math.trunc(-4.1));//-4

Math.sign 判断一个数是正数还是负数还是0

console.log(Math.sign(100));  //1console.log(Math.sign(0));     // 0console.log(Math.sign(-100)); //-1

ES6 新增了一些Object 对象的方法

  1. Object.is 比较两个值是否严格相等,与『===』行为基本一致(+0 与NaN)

  2. Object.assign 对象的合并,将源对象的所有可枚举属性,复制到目标对象

  3. proto、setPrototypeOf、setPrototypeOf 可以直接设置对象的原型

转载地址:http://bkqgn.baihongyu.com/

你可能感兴趣的文章
一:Lua 数据类型及表达示
查看>>
二:Lua 基本语法
查看>>
Ubuntu 18.04 界面美化之windows任务栏
查看>>
QT 5.9.0 移植
查看>>
objdump 反汇编 vmlinux详解
查看>>
sudo命令无法读取环境变量的解决方法
查看>>
Qt中configure参数配置说明
查看>>
Ubuntu 添加右键打开终端
查看>>
Linux 内核开机logo制作
查看>>
WIN10 + Ubuntu 16.04 双系统安装教程
查看>>
C 链接 C++静态库的方法
查看>>
Ubuntu16.04安装tftpd服务器程序
查看>>
Ubuntu16.04安装vsftpd服务器程序
查看>>
Ubuntu16.04安装nfs网络文件系统服务器
查看>>
安装完Ubuntu 16.04之后要做的一些事
查看>>
嵌入式开发 CMake的使用和交叉编译器的配置方法
查看>>
eclipse导入Cmake工程
查看>>
VMware 虚拟机安装Ubuntu 16.04
查看>>
Ubuntu虚拟机安装VMware Tools,实现主机和虚拟机之间自由复制
查看>>
Ubuntu清理旧内核
查看>>