💻【ES6】新特性详解🏠专栏:JavaScript
👀个人主页:繁星学编程🍁
🧑个人简介:一个不断提高自我的平凡人🚀
🔊分享方向:目前主攻前端,其他知识也会阶段性分享🍀
👊格言:☀️没有走不通的路,只有不敢走的人!☀️
👉让我们一起进步,一起成为更好的自己!!!🎁
文章目录
【ES6】新特性详解
一. 模块化开发(js文件之间的导入和导出)
JavaScript中的导入导出方式有两对,并且是对应着使用的。
import:静态的
import
语句用于导入由另一个模块导出的绑定。无论是否声明了 strict mode,导入的模块都运行在严格模式下。在浏览器中,import
语句只能在声明了type="module"
的script
的标签中使用。
<script src="./index.js" type="module"></script> <!-- 导入文件中引入导出文件 -->
(1) 第一组导入导出
导出方式一:
export default 要导出的数据 // export default 导入模块的默认导出接口的引用名,一个页面只能写一个
export default {数据1,数据2...} // 批量导出
导入方式一:
import 变量 from "来源的文件"
// eg:
// 导出文件:
let a
let b = 200
let c = 300
var obj = {
a: a,
b: b
}
export default a = 100 // 对外暴露变量a的值
// 导入文件:
import headerModules from './header.js' // 引入导出文件
console.log(headerModules); // 100
(2) 第二组导入导出
导出方式二:
export 要导出的数据 // 可以同时使用多个export导出
导入方式二:
import {变量1,变量2...} from "来源的文件";
// 或
import * as 变量 from "来源文件"
// eg:
// 导出文件:
export const a = 3;
export const b = [1, 45, 'zs'];
export const c = {
name: 'zs',
age: 18
}
// 导入文件:
import { b } from './two.js'
console.log(b) // [1, 45, 'zs']
二. 新的数据类型
JavaScript中原来的数据类型:Number、Boolean、Unll、Undefined、String、object
ES6新增的数据类型:Symbol、BigInt
(1) Symbol
symbol 是一种基本数据类型。Symbol()
函数会返回 symbol 类型的值,该类型具有静态属性和静态方法。
每个从 Symbol()
返回的 symbol 值都是唯一的。一个 symbol 值能作为对象属性的标识符;这是该数据类型仅有的目的。
-
创建Symbol数据类型
语法:
var 变量名 = Symbol(数据)
// eg: var a = Symbol('1'); var b = Symbol('1'); console.log(a, b); // Symbol(1) Symbol(1) console.log(a === b); // false console.log(a == b); // false // 独一无二 的,无法比较
-
Symbol作为对象的属性
不会覆盖
不能通过对象语法获取,只能通过遍历的方式拿到
Object.getOwnPropertySymbols()
方式,可以获取到对象的所有Symbol属性名const obj = { [Symbol('tom')]:1, [Symbol('jerry')]:2, } obj[Symbol('tom')] = 3 console.log(obj); // 不会覆盖,可以添加 // {Symbol(tom): 1, Symbol(jerry): 2, Symbol(tom): 3} console.log(obj[Symbol('tom')]); // undefined , Symbol('tom') 表示独一无二的值,获取的时候的Symbol('tom'),和设置的时候的Symbol('tom'), 不是同一个 // 无法通过对象语法获取symbol, 只能遍历
const obj = { [Symbol('tom')]: 1, [Symbol('jerry')]: 2, } obj[Symbol('tom')] = 3; console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(tom), Symbol(jerry), Symbol(tom)] for (let i = 0; i < Object.getOwnPropertySymbols(obj).length; i++) { // 获取对象的symbol属性名对应的属性值 console.log(Object.getOwnPropertySymbols(obj)[i], obj[Object.getOwnPropertySymbols(obj)[i]]); }
(2) BigInt
BigInt
是一种内置对象,它提供了一种方法来表示大于 2^53 - 1
的整数。这原本是 Javascript 中可以用Number
表示的最大数字。BigInt
可以表示任意大的整数。
新增加这个数据类型的目的:js存储16位以上的数据会出现精度丢失的问题
var num = 100;
num = 100n; // 转为BigInt
console.log(num); // 100n
console.log(typeof num); // bigint
console.log(100n + 100n); // 200n
console.log(100n + 100); // Uncaught TypeError: Cannot mix BigInt and other types, use explicit conversions
注:
-
将任意数字转为BigInt , 在数字后面添加n
-
bigInt只能和bigInt一起操作
-
BigInt
和Number
不是严格相等的,但是宽松相等的。10n == 10; // true 10n === 10; // false
三. class类
(1) 在之前的js中,我们会通过定义函数的方式进行构造函数的创建,在通过new 一个构造函数的类来实现一种独立的数据类型(Class)。
function Person (name) {
this.name = name;
this.say = function (){
console.log('这是一个构造函数方法', this)
}
}
// 通过定义在原型链上的方式来进行类之间数据共享
const person = new Person('df');
person.say();
person.property.action = function () {console.log('原型链上的数据共享')}
现在,ES6中,定义了一个class关键字来定义类,和java、php这些面向对象语言一样中类的功能类似(强调,JavaScript是面向函数式编程)。
class Dog {
constructor (name,age) { // 这是构造器,对象一经创建就立即执行的类,里面的参数就是new对象时候传入的参数
this.name = name
this.age = age
}
say () { // 之前都是将方法放在原型上或者属性上,不能直接定义,现在可以了
console.log('这是一个calss创建的类', this)
}
}
(2) 通过静态方法来创建对象,静态方法只能函数自己来调用,它的实例对象不能调用,而实例方法只能通过它的实例对象来调用,它本身不能调用。实例方法都是定义在类原型上的,而通过关键字static修饰后,这个方法就变成了静态方法,只能通过类名去调用了。
class Dog {
constructor (name,age) { // 这是构造器,对象一经创建就立即执行的类,里面的参数就是new对象时候传入的参数
this.name = name
this.age = age
}
say () { // 之前都是将方法放在原型上或者属性上,不能直接定义,现在可以了
console.log('这是一个calss创建的类', this)
}
static action (name,age) {
console.log('这是Dog类的静态方法')
return new Dog(name, age)
}
}
const ha = Dog.action('哈士奇', 3)
console.log(ha); // 这是Dog类的静态方法 Dog { name: '哈士奇', age: 3 }
3、 静态方法中的this是是指向当前类型,而不是当前对象。
4、使用extends关键字来实现继承一个父类,通过super关键字来调用继承的父类的属性和方法
class Dog {
constructor (name,age) { // 这是构造器,对象一经创建就立即执行的类,里面的参数就是new对象时候传入的参数
this.name = name
this.age = age
}
say () { // 之前都是将方法放在原型上或者属性上,不能直接定义,现在可以了
console.log('这是一个calss创建的类', this)
}
static action (name,age) {
console.log('这是Dog类的静态方法')
return new Dog(name, age)
}
}
class MinDog extends Dog {
constructor (name,age,type) {
super(name,age) // super关键字是用来调用父类 的,这里相当于在调用父类的构造方法
this._type = type
}
hello () {
super.say()
console.log('上一句是调用父类super打印出来的');
}
}
const ha = new MinDog('哈士奇', 3, 'man')
ha.hello() // 这是一个calss创建的类 MinDog { name: '哈士奇', age: 3, _type: 'man' } // 上一句是调用父类super打印出来的
四. ES6新增数据结构
数据结构 Set
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set
本身是一个构造函数,用来生成 Set 数据结构。
由于Set是伪数组,并且伪数组里面的值都是唯一的,所以可以用在数组去重中
const s = new Set()
const arr = [7, 2, 3, 4, 2, 5, 5];
arr.forEach(item => { s.add(item) });
console.log(s); // Set(5) {7, 2, 3, 4, 5}
console.log([...s]); // (5) [7, 2, 3, 4, 5]
// 简化为
const set = new Set([7, 2, 3, 4, 2, 5, 5]);
[...set]// [7, 2, 3, 4, 5]
(1) 创建 Set 数据结构
语法:
var s = new Set([数据1, 数据2, 数据3....])
(2) Set 数据结构的属性和方法
属性:size
方法:add()、has()、delete()、clear()、forEach()
-
size 属性
该数据结构中有多少个数据
语法:数据结构.size
// eg: const s = new Set([100, 200, 300, 200]); console.log(s.size); // 3
-
add() 方法
向该数据结构添加内容
语法:数据结构.add(数据)
// eg: const s = new Set([100, 200, 300]); s.add(500) s.add(100) console.log(s); // Set(4) {100, 200, 300, 500}
-
has() 方法
查找Set中是否有该数据
语法:数据结构.has(数据)
true 该数据结构内有该数据
false 该数据结构内没有该数据// eg: const s = new Set([100, 200, 300]); console.log(s.has(100)); // true console.log(s.has(500)); // false
-
delete()方法
删除数据
语法:数据结构.delete(数据)
// eg: const s = new Set([100, 200, 300]); s.delete(100); console.log(s); // Set(2) {200, 300}
-
clear() 方法
清除该数据结构内所有内容
语法:数据结构.clear()
// eg: const s = new Set([100, 200, 300]); s.clear(); console.log(s); // Set(0) {size: 0}
-
forEach() 方法
语法 :数据结构.forEach(function(value, key, origin){})
// eg: const s = new Set([100, 200, 300]); s.forEach(function(value, key, origin){ console.log(value, key, origin); // 100 100 Set(3) {100, 200, 300} });
(3) Set中判断两个值是否不同
向 Set 加入值的时候,不会发生类型转换,所以5
和"5"
是两个不同的值。Set 内部判断两个值是否不同,使用的算法叫做“Same-value-zero equality”,它类似于精确相等运算符(===
),主要的区别是向 Set 加入值时认为NaN
等于自身,而精确相等运算符认为NaN
不等于自身。
let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
set // Set {NaN}
上面代码向 Set 实例添加了两次NaN
,但是只会加入一个。这表明,在 Set 内部,两个NaN
是相等的。
另外,两个对象总是不相等的。
let set = new Set();
set.add({});
set.size // 1
set.add({});
set.size // 2
上面代码表示,由于两个空对象不相等,所以它们被视为两个值。
数据结构 Map
Map 数据结构:类似于对象的数据结构,它的key可以是任何数据类型,可以被看做为一个 值 = 值 的数据结构
(1) Map 基本概念
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
(2) Map 特征
- Map 对象保存键值对,并且能够记住键的原始插入顺序。
- 任何值(对象或者原始值) 都可以作为一个键或一个值。
- Map 是 ES6 中引入的一种新的数据结构
(3) Maps 和 Objects 的区别
- 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
- Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
- Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
- Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
(4) 创建一个 Map数据结构
语法:
var m = new Map( [ [key, value], [key, value] ] )
(5) Map 数据结构的属性和方法
属性:size
方法:set()、get()、has()、delete()、clear()、forEach()
-
size 属性
该数据结构内有多少个数据
语法:数据结构.size
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); console.log(m.size); // 2
-
set() 方法
向该数据结构添加内容
语法:数据结构.set(key, value)
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); m.set('time', '两年半'); console.log(m); // Map(3) {'name' => 'zs', 'age' => 18, 'time' => '两年半'}
-
get() 方法
语法:数据结构.get(key)
返回值:该数据结构内key对应的value
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); console.log(m.get('name')); // zs
-
has() 方法
该数据结构中是否有该数据
语法:数据结构.has(key)
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); console.log(m.has('name')); // true
-
delete() 方法
删除该数据结构内某一个数据
语法:数据结构.delete(key)
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); m.delete('name'); console.log(m); // Map(1) {'age' => 18}
-
clear() 方法
清除该数据结构里面的所有内容
语法:数据结构.clear()
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); m.clear(); console.log(m); // Map(0) {size: 0}
-
forEach()
语法:
数据结构.forEach(function(value, key, origin){})
// eg: const m = new Map([['name', 'zs'], ['age', 18]]); m.forEach(function (value, key, origin) { console.log(value, key, origin); // zs name Map(2) {'name' => 'zs', 'age' => 18} // 18 'age' Map(2) {'name' => 'zs', 'age' => 18} })
参考文章:Set 和 Map 数据结构 - ECMAScript 6入门 (ruanyifeng.com)
五. Iterator 和 for…of
Iterator(遍历器)
- 是一个接口,为不同的数据结构提供了同一个的访问机制
- ES6中提供了Symbol.iterator接口(属性),只要数据有这个接口,就可以用for…of遍历数据
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令for...of
循环,Iterator 接口主要供for...of
消费。
Iterator 的遍历过程:
- 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。
- 第一次调用指针对象的
next
方法,可以将指针指向数据结构的第一个成员。 - 第二次调用指针对象的
next
方法,指针就指向数据结构的第二个成员。 - 不断调用指针对象的
next
方法,直到它指向数据结构的结束位置。
每一次调用next
方法,都会返回数据结构的当前成员的信息。具体来说,就是返回一个包含value
和done
两个属性的对象。其中,value
属性是当前成员的值,done
属性是一个布尔值,表示遍历是否结束。
// 这里我们创建一个数组
const arr = [1,2,3]
const t = arr[Symbol.iterator]() //调用iterator方法可以得到该方法的执行体,里面有一个next()方法,这个方法就是循环中指向下一个地址的指针
console.log(t.next()) // {value: '1', done: false} // 这里得到的对象就是每次循环的对象值(value)和是否完成循环(done)
for…of… 遍历
语法:
for(let 变量名 of 数据) {}
var arr = [100, 200, 300, 400, 500];
arr.name = 'tom';
for (let value of arr) {
console.log(value);
/*
100
200
300
400
500
*/
}
六. 生成器
生成器:允许你定义一个包含自有迭代算法的函数,同时它可以自动维护自己的状态。生成器函数使用 function*
语法编写。最初调用时,生成器函数不执行任何代码,而是返回一种称为 Generator 的迭代器。通过调用生成器的下一个方法消耗值时,Generator 函数将执行,直到遇到 yield 关键字。
// eg:
function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
for (let i = start; i < end; i += step) {
yield i;
}
}
var a = makeRangeIterator(1,10,2)
a.next() // {value: 1, done: false}
a.next() // {value: 3, done: false}
a.next() // {value: 5, done: false}
a.next() // {value: 7, done: false}
a.next() // {value: 9, done: false}
a.next() // {value: undefined, done: true}
注意:虽然自定义的迭代器是一个有用的工具,但由于需要显式地维护其内部状态,因此需要谨慎地创建。它可以根据需要多次调用该函数,并且每次都返回一个新的 Generator,但每个 Generator 只能迭代一次。
结束语:
希望对您有一点点帮助,如有错误欢迎小伙伴指正。
👍点赞:您的赞赏是我前进的动力!
⭐收藏:您的支持我是创作的源泉!
✍评论:您的建议是我改进的良药!
一起加油!!!💪💪💪