当前位置:   article > 正文

ES6中class类、类的继承extends、多态、字面量的增强、解构、let/const、字符串模板、函数的默认参数、展开语法、数值、Symbol使用、Set、Map、es7-13总结_class extends

class extends

文章根据codewhy老师的课程学习整理深入JavaScript高级语法-coderwhy大神新课-学习视频教程-腾讯课堂

一、认识class定义类

我们会发现,按照前面的构造函数形式创建 类,不仅仅和编写普通的函数过于相似,而且代码并不容易理解。

ES6(ECMAScript2015)新的标准中使用了class关键字来直接定义类;

但是类本质上依然是前面所讲的构造函数、原型链的语法糖而已;

可以使用两种方式来声明类:类声明和类表达式

  1. // 类的声明
  2. class Person {
  3. }
  4. // 类的表达式
  5. var Animal = class {
  6. }

类和构造函数的异同

类的一些特性和我们的构造函数的特性其实是一致的

  1. // 研究一下类的特性
  2. console.log(Person) //[class Person]
  3. console.log(Person.prototype) //{}
  4. console.log(Person.prototype.__proto__) //[Object: null prototype] {}
  5. console.log(Person.prototype.constructor) //[class Person]
  6. console.log(typeof Person) // function
  7. var p = new Person()
  8. console.log(p.__proto__ === Person.prototype) // true

1. 类的构造函数

如果我们希望在创建对象的时候给类传递一些参数,这个时候应该如何做呢?

        每个类都可以有一个自己的构造函数(方法),这个方法的名称是固定的constructor;

        当我们通过new操作符,操作一个类的时候会调用这个类的构造函数constructor;

        每个类只能有一个构造函数,如果包含多个构造函数,那么会抛出异常;

当我们通过new关键字操作类的时候,会调用这个constructor函数,并且执行如下操作:

        1.在内存中创建一个新的对象(空对象);

        2.这个对象内部的[[prototype]]属性会被赋值为该类的prototype属性;

        3.构造函数内部的this,会指向创建出来的新对象;

        4.执行构造函数的内部代码(函数体代码);

        5.如果构造函数没有返回非空对象,则返回创建出来的新对象;

2. 类的实例方法

在上面我们定义的属性都是直接放到了this上,也就意味着它是放到了创建出来的新对象中:

        在前面我们说过对于实例的方法,我们是希望放到原型上的,这样可以被多个实例来共享;

        这个时候我们可以直接在类中定义

  1. // 类的声明
  2. class Person {
  3. // 类的构造方法
  4. // 注意: 一个类只能有一个构造函数
  5. // 1.在内存中创建一个对象 moni = {}
  6. // 2.将类的原型prototype赋值给创建出来的对象 moni.__proto__ = Person.prototype
  7. // 3.将对象赋值给函数的this: new绑定 this = moni
  8. // 4.执行函数体中的代码
  9. // 5.自动返回创建出来的对象
  10. constructor(name, age) {
  11. this.name = name
  12. this.age = age
  13. }
  14. eating() {
  15. console.log(this.name + " eating~")
  16. }
  17. running() {
  18. console.log(this.name + " running~")
  19. }
  20. }
  21. var p1 = new Person("why", 18)
  22. var p2 = new Person("kobe", 30)
  23. p.eating()
  24. p.running()
  25. console.log(p1, p2)

3. 类的访问器方法

我们之前讲对象的属性描述符时有讲过对象可以添加setter和getter函数的,那么类也是可以的:

4. 类的静态方法

静态方法通常用于定义直接使用类来执行的方法,不需要有类的实例,使用static关键字来定义

  1. var names = ["abc", "cba", "nba"]
  2. class Person {
  3. constructor(name, age) {
  4. this.name = name
  5. this.age = age
  6. this._address = "广州市"
  7. }
  8. // 普通的实例方法
  9. // 创建出来的对象进行访问
  10. // var p = new Person()
  11. // p.eating()
  12. eating() {
  13. console.log(this.name + " eating~")
  14. }
  15. running() {
  16. console.log(this.name + " running~")
  17. }
  18. // 类的访问器方法
  19. get address() {
  20. console.log("拦截访问操作")
  21. return this._address
  22. }
  23. set address(newAddress) {
  24. console.log("拦截设置操作")
  25. this._address = newAddress
  26. }
  27. // 类的静态方法(类方法)
  28. // Person.createPerson()
  29. static randomPerson() {
  30. var nameIndex = Math.floor(Math.random() * names.length)
  31. var name = names[nameIndex]
  32. var age = Math.floor(Math.random() * 100)
  33. return new Person(name, age)
  34. }
  35. }
  36. var p = new Person("why", 18)
  37. p.eating()
  38. p.running()
  39. console.log(p.address)
  40. p.address = "北京市"
  41. console.log(p.address)
  42. // console.log(Object.getOwnPropertyDescriptors(Person.prototype))
  43. for (var i = 0; i < 50; i++) {
  44. console.log(Person.randomPerson())
  45. }

二、ES6

1. 类的继承 - extends

在ES6中新增了使用extends关键字,可以方便的帮助我们实现继承:

super关键字

在子(派生)类的构造函数中使用this或者返回默认对象之前,必须先通过super调用父类的构造函数!

super的使用位置有三个:子类的构造函数、实例方法、静态方法

  1. class Person {
  2. constructor(name, age) {
  3. this.name = name
  4. this.age = age
  5. }
  6. running() {
  7. console.log(this.name + " running~")
  8. }
  9. eating() {
  10. console.log(this.name + " eating~")
  11. }
  12. personMethod() {
  13. console.log("处理逻辑1")
  14. console.log("处理逻辑2")
  15. console.log("处理逻辑3")
  16. }
  17. static staticMethod() {
  18. console.log("PersonStaticMethod")
  19. }
  20. }
  21. // Student称之为子类(派生类)
  22. class Student extends Person {
  23. // JS引擎在解析子类的时候就有要求, 如果我们有实现继承
  24. // 那么子类的构造方法中, 在使用this之前
  25. constructor(name, age, sno) {
  26. super(name, age)
  27. this.sno = sno
  28. }
  29. studying() {
  30. console.log(this.name + " studying~")
  31. }
  32. // 类对父类的方法的重写
  33. running() {
  34. console.log("student " + this.name + " running")
  35. }
  36. // 重写personMethod方法
  37. personMethod() {
  38. // 复用父类中的处理逻辑
  39. super.personMethod()
  40. console.log("处理逻辑4")
  41. console.log("处理逻辑5")
  42. console.log("处理逻辑6")
  43. }
  44. // 重写静态方法
  45. static staticMethod() {
  46. super.staticMethod()
  47. console.log("StudentStaticMethod")
  48. }
  49. }
  50. var stu = new Student("why", 18, 111)
  51. console.log(stu)

继承内置类

我们也可以让我们的类继承自内置类,比如Array

  1. class HYArray extends Array {
  2. firstItem() {
  3. return this[0]
  4. }
  5. lastItem() {
  6. return this[this.length-1]
  7. }
  8. }
  9. var arr = new HYArray(1, 2, 3)
  10. console.log(arr.firstItem())
  11. console.log(arr.lastItem())

类的混入mixin

JavaScript的类只支持单继承:也就是只能有一个父类

        那么在开发中我们我们需要在一个类中添加更多相似的功能时,应该如何来做呢?

        这个时候我们可以使用混入(mixin);

  1. class Person {
  2. }
  3. function mixinRunner(BaseClass) {
  4. class NewClass extends BaseClass {
  5. running() {
  6. console.log("running~")
  7. }
  8. }
  9. return NewClass
  10. }
  11. function mixinEater(BaseClass) {
  12. return class extends BaseClass {
  13. eating() {
  14. console.log("eating~")
  15. }
  16. }
  17. }
  18. // 在JS中类只能有一个父类: 单继承
  19. class Student extends Person {
  20. }
  21. var NewStudent = mixinEater(mixinRunner(Student))
  22. var ns = new NewStudent()
  23. ns.running()
  24. ns.eating()

2. JavaScript中的多态

不同的数据类型进行同一个操作,表现出不同的行为,就是多态的体现

那么从上面的定义来看,JavaScript是一定存在多态的

  1. // 传统的面向对象多态是有三个前提:
  2. // 1> 必须有继承(是多态的前提)
  3. // 2> 必须有重写(子类重写父类的方法)
  4. // 3> 必须有父类引用指向子类对象
  5. // Shape形状
  6. class Shape {
  7. getArea() {}
  8. }
  9. class Rectangle extends Shape {
  10. getArea() {
  11. return 100
  12. }
  13. }
  14. class Circle extends Shape {
  15. getArea() {
  16. return 200
  17. }
  18. }
  19. var r = new Rectangle()
  20. var c = new Circle()
  21. // 多态: 当对不同的数据类型执行同一个操作时, 如果表现出来的行为(形态)不一样, 那么就是多态的体现.
  22. function calcArea(shape: Shape) {
  23. console.log(shape.getArea())
  24. }
  25. calcArea(r)
  26. calcArea(c)

3.字面量的增强

ES6中对 对象字面量 进行了增强,称之为 Enhanced object literals(增强对象字面量)

字面量的增强主要包括下面几部分:

属性的简写:Property Shorthand

方法的简写:Method Shorthand

计算属性名:Computed Property Names

  1. var name = "why"
  2. var age = 18
  3. var obj = {
  4. // 1.property shorthand(属性的简写)
  5. name,
  6. age,
  7. // 2.method shorthand(方法的简写)
  8. foo: function() {
  9. console.log(this)
  10. },
  11. bar() {
  12. console.log(this)
  13. },
  14. baz: () => {
  15. console.log(this)
  16. },
  17. // 3.computed property name(计算属性名)
  18. [name + 123]: 'hehehehe'
  19. }
  20. obj.baz()
  21. obj.bar()
  22. obj.foo()
  23. // obj[name + 123] = "hahaha"
  24. console.log(obj)
  25. // {
  26. // name: 'why',
  27. // age: 18,
  28. // foo: [Function: foo],
  29. // bar: [Function: bar],
  30. // baz: [Function: baz],
  31. // why123: 'hehehehe'
  32. // }

4. 解构Destructuring

ES6中新增了一个从数组或对象中方便获取数据的方法,称之为解构Destructuring。 n

我们可以划分为:数组的解构和对象的解构

数组的解构: 

  • 基本解构过程 
  • 顺序解构
  • 解构出数组
  • 默认值

对象的解构:

  • 基本解构过程
  •  任意顺序
  •  重命名
  • 默认值
  1. var names = ["abc", "cba", "nba"]
  2. // 对数组的解构: []
  3. var [item1, item2, item3] = names
  4. console.log(item1, item2, item3) //abc cba nba
  5. // 解构后面的元素
  6. var [, , itemz] = names
  7. console.log(itemz) //nba
  8. // 解构出一个元素,后面的元素放到一个新数组中
  9. var [itemx, ...newNames] = names
  10. console.log(itemx, newNames) //abc [ 'cba', 'nba' ]
  11. // 解构的默认值
  12. var [itema, itemb, itemc, itemd = "aaa"] = names
  13. console.log(itemd) //aaa
  1. var obj = {
  2. name: "why",
  3. age: 18,
  4. height: 1.88
  5. }
  6. // 对象的解构: {}
  7. var { name, age, height } = obj
  8. console.log(name, age, height) //why 18 1.88
  9. var { age } = obj
  10. console.log(age) //18
  11. //重命名成newName
  12. var { name: newName } = obj
  13. console.log(newName) //why
  14. var { address: newAddress = "广州市" } = obj
  15. console.log(newAddress) //广州市
  16. function foo(info) {
  17. console.log(info.name, info.age)
  18. }
  19. foo(obj) //why 18
  20. function bar({name, age}) {
  21. console.log(name, age)
  22. }
  23. bar(obj) //why 18

解构目前在开发中使用是非常多的:

  • 比如在开发中拿到一个变量时,自动对其进行解构使用;
  • 比如对函数的参数进行解构; 解构的应用场景

5. let/const基本使用

在ES5中我们声明变量都是使用的var关键字,从ES6开始新增了两个关键字可以声明变量:let、const

注意事项一: const本质上是传递的值不可以修改

但是如果传递的是一个引用类型(内存地址), 可以通过引用找到对应的对象, 去修改对象内部的属性, 这个是可以的

let/const和var的区别

1. 通过let/const定义的变量名是不可以重复定义

2.  let、const没有进行作用域提升,但是会在解析阶段被创建出来

3. Window对象添加属性

  • 全局通过var来声明一个变量,事实上会在window上添加一个属性:
  • 但是let、const是不会给window上添加任何属性的。
  • 变量被保存到VariableMap中

也就是说我们声明的变量和环境记录是被添加到变量环境中的

  • v8中其实是通过VariableMap的一个hashmap来实现它们的存储的。
  • 那么window对象呢?而window对象是早期的GO对象,在最新的实现中其实是浏览器添加的全局对象,并且 一直保持了window和var之间值的相等性

4.块级作用域区别

ES5中没有块级作用域,只有两个东西会形成作用域

  • 全局作用域
  • 函数作用域

在ES6中新增了块级作用域,并且通过let、const、function、class声明的标识符是具备块级作用域的限制的

但是我们会发现函数拥有块级作用域,但是外面依然是可以访问的: p这是因为引擎会对函数的声明进行特殊的处理,允许像var那样进行提升

var、let、const的选择

var所表现出来的特殊性:比如作用域提升、window全局对象、没有块级作用域等都是一些 历史遗留问题

在实际工作中,我们可以使用最新的规范来编写,也就是不再使用var来定义变量了;

对于let、const:

  • 我们会有限推荐使用const,这样可以保证数据的安全性不会被随意的篡改;
  •  只有当我们明确知道一个变量后续会需要被重新赋值时,这个时候再使用let

6.字符串模板基本使用

ES6允许我们使用字符串模板来嵌入JS的变量或者表达式来进行拼接:

  •  首先,我们会使用 `` 符号来编写字符串,称之为模板字符串;
  •  其次,在模板字符串中,我们可以通过 ${expression} 来嵌入动态的内容
  1. // ES6之前拼接字符串和其他标识符
  2. const name = "why"
  3. const age = 18
  4. const height = 1.88
  5. // console.log("my name is " + name + ", age is " + age + ", height is " + height)
  6. // ES6提供模板字符串 ``
  7. const message = `my name is ${name}, age is ${age}, height is ${height}`
  8. console.log(message) //my name is why, age is 18, height is 1.88
  9. const info = `age double is ${age * 2}`
  10. console.log(info) //age double is 36
  11. function doubleAge() {
  12. return age * 2
  13. }
  14. const info2 = `double age is ${doubleAge()}`
  15. console.log(info2) //double age is 36

标签模板字符串使用

如果我们使用标签模板字符串,并且在调用的时候插入其他的变量:

  • 模板字符串被拆分了; 
  • 第一个元素是数组,是被模块字符串拆分的字符串组合;
  • 后面的元素是一个个模块字符串传入的内容
  1. // 第一个参数依然是模块字符串中整个字符串, 只是被切成多块,放到了一个数组中
  2. // 第二个参数是模块字符串中, 第一个 ${}
  3. function foo(m, n, x) {
  4. console.log(m, n, x, '---------')
  5. }
  6. // foo("Hello", "World")
  7. // 另外调用函数的方式: 标签模块字符串
  8. // foo``
  9. // foo`Hello World`
  10. const name = "why"
  11. const age = 18
  12. // ['Hello', 'Wo', 'rld']
  13. foo`Hello${name}Wo${age}rld`

7.函数增强

函数的默认参数

在ES6之前,我们编写的函数参数是没有默认值的,所以我们在编写函数时,如果有下面的需求:

  • 传入了参数,那么使用传入的参数;
  • 没有传入参数,那么使用一个默认值;

而在ES6中,我们允许给函数一个默认值:

函数默认值的补充

默认值也可以和解构一起来使用 

另外参数的默认值我们通常会将其放到最后(在很多语言中,如果不放到最后其实会报错的)

  • 但是JavaScript允许不将其放到最后,但是意味着还是会按照顺序来匹配;

另外默认值会改变函数的length的个数,默认值以及后面的参数都不计算在length之内了、

函数的剩余参数

ES6中引用了rest parameter,可以将不定数量的参数放入到一个数组中:

  • 如果最后一个参数是 ... 为前缀的,那么它会将剩余的参数放到该参数中,并且作为一个数组;

那么剩余参数和arguments有什么区别呢?

  • 剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参
  • arguments对象不是一个真正的数组,而rest参数是一个真正的数组,可以进行数组的所有操作;
  • arguments是早期的ECMAScript中为了方便去获取所有的参数提供的一个数据结构,而rest参数是ES6中提供 并且希望以此来替代arguments的;

剩余参数必须放到最后一个位置,否则会报错

  1. // 1.ES6可以给函数参数提供默认值
  2. function foo(m = "aaa", n = "bbb") {
  3. console.log(m, n)
  4. }
  5. // foo()
  6. foo(0, "") //0
  7. // 2.对象参数和默认值以及解构
  8. function printInfo({name, age} = {name: "why", age: 18}) {
  9. console.log(name, age)
  10. }
  11. printInfo({name: "kobe", age: 40}) //kobe 40
  12. // 另外一种写法
  13. function printInfo1({name = "why", age = 18} = {}) {
  14. console.log(name, age)
  15. }
  16. printInfo1()// why 18
  17. // 3.有默认值的形参最好放到最后
  18. function bar(x, y, z = 30) {
  19. console.log(x, y, z)
  20. }
  21. bar(10, 20) //10 20 30
  22. bar(undefined, 10, 20) //undefined 10 20
  23. // 4.有默认值的函数的length属性
  24. function baz(x, y, z, m, n = 30) {
  25. console.log(x, y, z, m, n)
  26. }
  27. console.log(baz.length) //4

 剪头函数补充

8. ES6中展开语法的使用

  1. const names = ["abc", "cba", "nba"]
  2. const name = "why"
  3. const info = {name: "why", age: 18}
  4. // 1.函数调用时
  5. function foo(x, y, z) {
  6. console.log(x, y, z)
  7. }
  8. // foo.apply(null, names)
  9. foo(...names) //abc cba nba
  10. foo(...name) //w h y
  11. // 2.构造数组时
  12. const newNames = [...names, ...name]
  13. console.log(newNames) //[ 'abc', 'cba', 'nba', 'w', 'h', 'y' ]
  14. // 3.构建对象字面量时ES2018(ES9)
  15. const obj = { ...info, address: "广州市", ...names }
  16. console.log(obj)
  17. // {
  18. // '0': 'abc',
  19. // '1': 'cba',
  20. // '2': 'nba',
  21. // name: 'why',
  22. // age: 18,
  23. // address: '广州市'
  24. // }

 展开运算符是浅拷贝

展开运算符是浅拷贝,他第一层是深拷贝,互不影响,如果有对象,里面的对象是相同的内存地址,是浅拷贝,所以总体是浅拷贝

引用赋值

在ES6中,引用赋值是指将一个变量的值赋给另一个变量时,两个变量实际上是指向同一个内存地址,即它们引用的是同一个对象或值。

在JavaScript中,基本类型(如数字、字符串、布尔值等)是按值传递的,而对象类型(如数组、对象、函数等)是按引用传递的。这意味着,当你将一个对象赋值给另一个变量时,实际上是将对象的引用赋值给另一个变量,而不是创建一个新的对象副本。

  1. let obj1 = { name: "John" };
  2. let obj2 = obj1; // 引用赋值
  3. obj2.name = "Jane";
  4. console.log(obj1.name); // 输出 "Jane"

在这个例子中,obj1 和 obj2 指向同一个对象,修改 obj2 的属性也会影响到 obj1

需要注意的是,对于基本类型,赋值操作会创建一个新的值副本,修改其中一个变量不会影响另一个变量。

浅拷贝、深拷贝

  1. 浅拷贝(Shallow Copy):当复制一个对象时,如果只对对象的第一层属性进行复制,而对内部的子对象或数组仍然保持引用关系,这种复制方式称为浅拷贝。换句话说,浅拷贝只会复制对象的顶层属性,而不会复制嵌套的对象或数组。这意味着,修改复制后的对象中的嵌套对象或数组,会影响到原始对象。
  1. let obj1 = { name: "John", age: 25, address: { city: "New York" } };
  2. let obj2 = Object.assign({}, obj1); // 浅拷贝
  3. obj2.address.city = "Los Angeles";
  4. console.log(obj1.address.city); // 输出 "Los Angeles"
  1. 深拷贝(Deep Copy):当复制一个对象时,不仅对对象的第一层属性进行复制,还会递归地复制内部的所有子对象和数组,这种复制方式称为深拷贝。换句话说,深拷贝会创建一个新的对象,并复制原始对象的所有层级和数据,而不仅仅是顶层属性。这意味着,修改复制后的对象中的任何属性,都不会影响到原始对象。
  1. let obj1 = { name: "John", age: 25, address: { city: "New York" } };
  2. let obj2 = JSON.parse(JSON.stringify(obj1)); // 深拷贝
  3. obj2.address.city = "Los Angeles";
  4. console.log(obj1.address.city); // 输出 "New York"

9.ES6中的数值表示:大的数值的连接符_

  1. const num1 = 100 // 十进制
  2. // b -> binary
  3. const num2 = 0b100 // 二进制
  4. // o -> octonary
  5. const num3 = 0o100 // 八进制
  6. // x -> hexadecimal
  7. const num4 = 0x100 // 十六进制
  8. console.log(num1, num2, num3, num4)
  9. // 大的数值的连接符(ES2021 ES12)
  10. const num = 10_000_000_000_000_000
  11. console.log(num)

10.Symbol的基本使用方式

在ES6中,Symbol是一种新的数据类型,用于创建独一无二的标识符。它的基本使用方式如下

创建Symbol类型:可以使用Symbol()函数来创建一个Symbol类型的值。

作为属性名:由于Symbol值是独一无二的,它们经常用作对象的属性名,以避免属性名的冲突。

  1. // 1.ES6之前, 对象的属性名(key)
  2. var obj1 = {
  3. name: "why",
  4. friend: { name: "kobe" },
  5. age: 18
  6. }
  7. obj1['newName'] = "james"
  8. console.log(obj1) //{ name: 'why', friend: { name: 'kobe' }, age: 18, newName: 'james' }
  9. // 2.ES6中Symbol的基本使用:生成的值都是唯一的
  10. const s1 = Symbol()
  11. const s2 = Symbol()
  12. console.log(s1 === s2) //false
  13. // ES2019(ES10)中, Symbol还有一个描述(description)
  14. const s3 = Symbol("aaa")
  15. console.log(s3.description) //aaa
  16. // 3.Symbol值作为key
  17. // 3.1.在定义对象字面量时使用
  18. const obj = {
  19. [s1]: "abc",
  20. [s2]: "cba"
  21. }
  22. // 3.2.新增属性
  23. obj[s3] = "nba"
  24. // 3.3.Object.defineProperty方式
  25. const s4 = Symbol()
  26. Object.defineProperty(obj, s4, {
  27. enumerable: true,
  28. configurable: true,
  29. writable: true,
  30. value: "mba"
  31. })
  32. console.log(obj[s1], obj[s2], obj[s3], obj[s4]) //abc cba nba mba
  33. // 注意: 不能通过.语法获取
  34. // console.log(obj.s1)
  35. // 4.使用Symbol作为key的属性名,在遍历/Object.keys等中是获取不到这些Symbol值
  36. // 需要Object.getOwnPropertySymbols来获取所有Symbol的key
  37. console.log(Object.keys(obj)) //[]
  38. console.log(Object.getOwnPropertyNames(obj)) //[]
  39. console.log(Object.getOwnPropertySymbols(obj)) //[ Symbol(), Symbol(), Symbol(aaa), Symbol() ]
  40. const sKeys = Object.getOwnPropertySymbols(obj)
  41. for (const sKey of sKeys) {
  42. console.log(obj[sKey]) //abc cba nba mba
  43. }
  44. // 5.Symbol.for(key)/Symbol.keyFor(symbol)
  45. const sa = Symbol.for("aaa")
  46. const sb = Symbol.for("aaa")
  47. console.log(sa === sb) //true
  48. console.log(sa) //Symbol(aaa)
  49. const key = Symbol.keyFor(sa)
  50. console.log(key) //aaa
  51. const sc = Symbol.for(key)
  52. console.log(sa === sc) //true

11.Set的基本使用

在ES6之前,我们存储数据的结构主要有两种:数组、对象

  • 在ES6中新增了另外两种数据结构:Set、Map,以及它们的另外形式WeakSet、WeakMap

Set是一个新增的数据结构,可以用来保存数据,类似于数组,但是和数组的区别是元素不能重复。

  • 创建Set我们需要通过Set构造函数(暂时没有字面量创建的方式): 

我们可以发现Set中存放的元素是不会重复的,那么Set有一个非常常用的功能就是给数组去重

Set常见的属性:

  • size:返回Set中元素的个数; 

Set常用的方法:

  • add(value):添加某个元素,返回Set对象本身;
  • delete(value):从set中删除和这个值相等的元素,返回boolean类型;
  • has(value):判断set中是否存在某个元素,返回boolean类型;
  • clear():清空set中所有的元素,没有返回值;
  • forEach(callback, [, thisArg]):通过forEach遍历set;

另外Set是支持for of的遍历的。

  1. // 10, 20, 40, 333
  2. // 1.创建Set结构
  3. const set = new Set()
  4. set.add(10)
  5. set.add(20)
  6. set.add(40)
  7. set.add(333)
  8. set.add(10)
  9. // 2.添加对象时特别注意:
  10. set.add({})
  11. set.add({})
  12. const obj = {}
  13. set.add(obj)
  14. set.add(obj)
  15. // console.log(set)
  16. // 3.对数组去重(去除重复的元素)
  17. const arr = [33, 10, 26, 30, 33, 26]
  18. // const newArr = []
  19. // for (const item of arr) {
  20. // if (newArr.indexOf(item) !== -1) {
  21. // newArr.push(item)
  22. // }
  23. // }
  24. const arrSet = new Set(arr)
  25. const newArr = Array.from(arrSet)
  26. // const newArr = [...arrSet]
  27. console.log(newArr) //[ 33, 10, 26, 30 ]
  28. // 4.size属性
  29. console.log(arrSet.size) //4
  30. // 5.Set的方法
  31. // add
  32. arrSet.add(100) //Set(5) { 33, 10, 26, 30, 100 }
  33. console.log(arrSet)
  34. // delete
  35. arrSet.delete(33)
  36. console.log(arrSet)
  37. // has
  38. console.log(arrSet.has(100)) //true
  39. // clear
  40. // arrSet.clear()
  41. console.log(arrSet)
  42. // 6.对Set进行遍历
  43. arrSet.forEach(item => {
  44. console.log(item)
  45. })
  46. for (const item of arrSet) {
  47. console.log(item)
  48. }

12.WeakSet使用

和Set类似的另外一个数据结构称之为WeakSet,也是内部元素不能重复的数据结构。

那么和Set有什么区别呢?

 区别一:WeakSet中只能存放对象类型,不能存放基本数据类型;

区别二:WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收;

WeakSet常见的方法:

  • add(value):添加某个元素,返回WeakSet对象本身;
  • delete(value):从WeakSet中删除和这个值相等的元素,返回boolean类型;
  • has(value):判断WeakSet中是否存在某个元素,返回boolean类型;

WeakSet不能遍历

  • 因为WeakSet只是对对象的弱引用,如果我们遍历获取到其中的元素,那么有可能造成对象不能正常的销毁。
  • 所以存储到WeakSet中的对象是没办法获取的

13.Map的基本使用

另外一个新增的数据结构是Map,用于存储映射关系。 

但是我们可能会想,在之前我们可以使用对象来存储映射关系,他们有什么区别呢?

  • 事实上我们对象存储映射关系只能用字符串(ES6新增了Symbol)作为属性名(key);
  • 某些情况下我们可能希望通过其他类型作为key,比如对象,这个时候会自动将对象转成字符串来作为key; 

那么我们就可以使用Map

  1. JavaScript中对象中是不能使用对象来作为key的
  2. .Map就是允许我们对象类型来作为key的

Map的常用方法

Map常见的属性

  •  size:返回Map中元素的个数;

Map常见的方法:

  • set(key, value):在Map中添加key、value,并且返回整个Map对象;
  • get(key):根据key获取Map中的value;
  • has(key):判断是否包括某一个key,返回Boolean类型;
  • delete(key):根据key删除一个键值对,返回Boolean类型;
  • clear():清空所有的元素;
  • forEach(callback, [, thisArg]):通过forEach遍历Map;

Map也可以通过for of进行遍历

  1. // 1.JavaScript中对象中是不能使用对象来作为key
  2. const obj1 = { name: "why" }
  3. const obj2 = { name: "kobe" }
  4. // const info = {
  5. // [obj1]: "aaa",
  6. // [obj2]: "bbb"
  7. // }
  8. // console.log(info)
  9. // 2.Map就是允许我们对象类型来作为key
  10. // 构造方法的使用
  11. const map = new Map()
  12. map.set(obj1, "aaa")
  13. map.set(obj2, "bbb")
  14. map.set(1, "ccc")
  15. console.log(map)
  16. const map2 = new Map([[obj1, "aaa"], [obj2, "bbb"], [2, "ddd"]])
  17. console.log(map2)
  18. // 3.常见的属性和方法
  19. console.log(map2.size)
  20. // set
  21. map2.set("why", "eee")
  22. console.log(map2)
  23. // get(key)
  24. console.log(map2.get("why"))
  25. // has(key)
  26. console.log(map2.has("why"))
  27. // delete(key)
  28. map2.delete("why")
  29. console.log(map2)
  30. // clear
  31. // map2.clear()
  32. // console.log(map2)
  33. // 4.遍历map
  34. map2.forEach((item, key) => {
  35. console.log(item, key)
  36. })
  37. for (const item of map2) {
  38. console.log(item[0], item[1])
  39. }
  40. for (const [key, value] of map2) {
  41. console.log(key, value)
  42. }

WeakMap的使用

和Map类型相似的另外一个数据结构称之为WeakMap,也是以键值对的形式存在的。 

那么和Map有什么区别呢? 

区别一:WeakMap的key不能使用基本数据类型,只能使用对象,不接受其他的类型作为key;

 区别二:WeakMap的key对对象想的引用是弱引用,如果没有其他引用引用这个对象,那么GC可以回收该对象;

WeakMap常见的方法有四个

  • set(key, value):在Map中添加key、value,并且返回整个Map对象;
  • get(key):根据key获取Map中的value;
  •  has(key):判断是否包括某一个key,返回Boolean类型;
  • delete(key):根据key删除一个键值对,返回Boolean类型

WeakMap也是不能遍历的

  • 因为没有forEach方法,也不支持通过for of的方式进行遍历

!!总结!!

ES11:globalThis

ES11: for...in标准化

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/78714
推荐阅读
相关标签
  

闽ICP备14008679号