首页 > 其他分享 >复习ES(6-11)语法之ES6中篇

复习ES(6-11)语法之ES6中篇

时间:2023-07-04 23:55:06浏览次数:41  
标签:11 ES6 console log Symbol let new ES name

目录

类是对象的模版,定义了同一组对象共有的属性和方法

ES5中的类与继承

  • 定义类

ES5其实并没有类的概念,是通过function 构造函数来模拟一个类。在构造函数中,通常会将不变的方法直接定义在prototype对象上,这样所有对象实例就可以共享这些方法,节省内存。

// 类
function People(name, age) {
  this.name = name;
  this.age = age;
}
People.prototype.showName = function () {
  console.log("我的名字是" + this.name);
};
let p1 = new People("zzz", 18);
console.log(p1);
p1.showName();
let p2 = new People("小明", 20);
console.log(p2);
p2.showName();

  • 定义静态属性

静态属性就是直接在定义在类上的属性,使用时直接通过类调用它

// 类
function People(name, age) {
  this.name = name;
  this.age = age;
  People.count++;
}
People.count = 0;
let p1 = new People("zzz", 18);
let p2 = new People("小明", 20);
console.log(People.count) // 2
  • 静态方法

静态方法跟静态属性一样,也是定义在类上,使用时直接通过类调用它。在静态方法中,this指向构造函数,所以无法通过this获取实例属性

People.getCount = function () {
  console.log(this); // 指向构造函数
  console.log("当前共有" + People.count + "个人");
};
People.getCount();
  • 继承

①构造函数继承,可以继承构造函数里面的方法和属性,但是不继承原型链

// 父类
function Animal(name) {
  this.name = name;
}
Animal.prototype.showName = function () {
  console.log("名字是" + this.name);
};

// 子类
function Dog(name, color) {
  Animal.call(this, name); //继承属性
  this.color = color;
}
let d1 = new Dog("wangcai", "white");
console.log(d1); //Dog { name: 'wangcai', color: 'white' }

②原型链继承,只能继承原型链上的方法,无法继承构造函数里面的方法和属性

将子类的prototype对象指向父类的实例化对象,并且当前Dog原型的构造函数需要再指回到Dog上。

// 父类
function Animal(name) {
  this.name = name;
}
Animal.prototype.showName = function () {
  console.log("名字是" + this.name);
};

// 子类
function Dog(name, color) {
  //   Animal.call(this, name); //继承属性
  this.color = color;
}
Dog.prototype = new Animal(); // Animail.prototye
Dog.prototype.constructor = Dog;
let d1 = new Dog("wangcai", "white");
console.log(d1); //Dog {  color: 'white' }
d1.showName(); //名字是undefined

③组合式继承,就是将构造函数继承和原型链继承一起使用,既可以继承构造函数里面的方法和属性,又可以继承原型链上的方法。

// 父类
function Animal(name) {
  this.name = name;
  Animal.count++;
}
Animal.prototype.showName = function () {
  console.log("名字是" + this.name);
};

// 子类
function Dog(name, color) {
  Animal.call(this, name); //继承属性
  this.color = color;
}
Dog.prototype = new Animal(); // Animail.prototye
Dog.prototype.constructor = Dog;
let d1 = new Dog("wangcai", "white");
console.log(d1); //Dog { name: 'wangcai', color: 'white' }
d1.showName(); //名字是wangcai

ES6中的类与继承

  • 类的定义

在ES6中提供了一个关键字Class可以用来声明一个类,在类中有constructor构造方法可以初始化属性,实例方法直接写在class里

class People {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  showName() {
    console.log(this.name);
  }
}
let p1 = new People("zzz", 18);
p1.showName();
  • 继承

在ES6中可以使用extendssuper关键字实现对类的继承,其中super是用来在constructor中继承父类的属性

class Coder extends People {
  constructor(name, age, company) {
    super(name, age); // 继承父类的name和age属性
    this.company = company;
  }
  showCompany() {
    console.log(this.company);
  }
}
let c1 = new Coder("小明", 18, "路人甲公司");
console.log(c1);
c1.showName();
c1.showCompany();
  • 访问器

在类中可以使用 get xxx 或者set xxx创建访问器方法,用来访问/返回值或者设置某一个属性的值。

class Coder extends People {
  constructor(name, age, company) {
    super(name, age); // 继承父类的name和age属性
    this.company = company;
  }
  get sex() {
    return "female";
  }
  showCompany() {
    console.log(this.company);
  }
}
let c1 = new Coder("小明", 18, "路人甲公司");
console.log(c1.sex); // female

如果使用get创建了属性,那么直接修改这个属性的值是无效的,还需要定义set方法来修改,在使用set时需要创建一个额外的属性来存储属性值,否则每次使用set修改属性会一直死循环set方法。

class Coder extends People {
  constructor(name, age, company) {
    super(name, age); // 继承父类的name和age属性
    this.company = company;
    this._sex = -1;
  }
  get sex() {
    return this._sex;
  }
  set sex(val) {
    this._sex = val;
  }
  showCompany() {
    console.log(this.company);
  }
}
let c1 = new Coder("小明", 18, "路人甲公司");
c1.sex = "male";
console.log(c1.sex); // male
  • 静态方法

在ES6中使用static关键字定义静态方法,使用时直接通过类调用,子类可以继承父类的静态方法。

//在父类定义静态方法
class People {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  static getCount() {
    return 6;
  }
  showName() {
    console.log(this.name);
  }
}

console.log(People.getCount()); // 6
console.log(Coder.getCount()); // 6
  • 静态属性

ES6明确规定,class内部只能定义静态方法,不能定义静态属性。可以同ES5方式一样通过类名.xxx定义静态属性,因为类本质是构造函数的语法糖

People.count = 9;
console.log(typeof People); // function
console.log(People.count);

新的原始数据类型

ES5的原始数据类型有 undefinednullnumberstringboolean、和引用类型Object。ES6新增了一种新的原始数据类型SymbolSymbol在ES6表示独一无二的意思

  • 声明方式

无描述值,即使创建的2个Symbol都无描述值,它们依然不相等

let s1 = Symbol();
let s2 = Symbol();
console.log(s1); // Symbol()
console.log(s2); // Symbol()
console.log(s1 === s2); // false

//打印描述值
console.log(s1.description); // undefined

有描述值,把字符串作为参数传到Symbol当描述

let s1 = Symbol("s1");
let s2 = Symbol("s2");
console.log(s1); // Symbol(s1)
console.log(s2); // Symbol(s2)
console.log(s1 === s2); //false

//打印描述值
console.log(s1.description); // s1  

③如果传入的参数是一个对象,Symbol会自动调佣对象的toString方法

const obj1 = {
  name: "obj1",
};
const obj2 = {
  name: "obj2",
  toString() {
    return this.name;
  },
};
let s1 = Symbol(obj1);
let s2 = Symbol(obj2);
console.log(s1); // Symbol([object Object])
console.log(s2); // Symbol(obj2)

Symbol.for(),通过这种方式创建的Symbol值,相当于在全局环境中定义了,每次创建时都会在全局查找是否有相同的描述值的Symbol。而Symbol()每次都会创建一个新值。

let s1 = Symbol.for("foo");
let s2 = Symbol.for("foo");
console.log(s1 === s2); // true

function bar(){
    return Symbol.for('bar')
}
const x = bar()
const y = Symbol.for('bar')
console.log(x === y) // true

Symbol.keyFor方法返回一个已经登记的Symbol类型值的key。

let s1 = Symbol("foo");
let s2 = Symbol.for("foo");
console.log(Symbol.keyFor(s1)); // undefined
console.log(Symbol.keyFor(s2)); // foo
  • 应用场景

①利用Symbol来作为对象的属性名

如果 一个年级里有2个同名的同学,那么不使用Symbol的情况下无法进行区分,前一个同学的信息被后一个同学覆盖。

const grade = {
  李四: { address: "zzz", tel: "111" },
  李四: { address: "yyy", tel: "222" },
};
console.log(grade); // { '李四': { address: 'yyy', tel: '222' } }

利用Symbol来作为对象的属性名,可以进行区分,因为它形成的是独一无二的key,无法被覆盖。

const stu1 = Symbol("李四");
const stu2 = Symbol("李四");

const grade = {
  [stu1]: { address: "zzz", tel: "111" },
  [stu2]: { address: "yyy", tel: "222" },
};
console.log(grade);
console.log(grade[stu1]);
console.log(grade[stu2]);

②定义某个类的私有属性或方法

定义一个登录类,通过Symbol将密码设为类似私有属性的属性,不允许对外访问。

// a文件
const password = Symbol('pwd');
class Login {
  constructor(username, pwd) {
    this.username = username;
    this[password] = pwd;
  }
  checkPassword(pwd) {
    console.log(this[password]);
    return this[password] === pwd;
  }
}

export default Login;

// b文件
const login = new Login("admin", "123");
console.log(login.checkPassword("123"));

login.password        // 无法访问
login[password]       // 无法访问
login["password"]     // 无法访问



for (let key in login) {
  // 只能取到普通属性
  console.log(key); // username
}
for (let key of Object.keys(login)) {
  // 只能取到普通属性
  console.log(key); // username
}
for (let key of Object.getOwnPropertySymbols(login)) {
  // 只能取到Symbol属性
  console.log(key); // Symbol(pwd)
}
for (let key of Reflect.ownKeys(login)) {
  // 既取到普通属性又能取到Symbol属性
  console.log(key); // 输出username和Symbol(pwd)
}

  • 消除魔术字符串

魔术字符串指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量替代。

const shapeType = {
  triangle: Symbol(),
  circle: Symbol(),
};

function getArea(shape) {
  let area = 0;
  switch (shape) {
    case shapeType.triangle:
      area = 1;
      break;
    case shapeType.circle:
      area = 2;
      break;
  }
  return area;
}
console.log(getArea(shapeType.triangle)); // 1

新的数据结构Set

Set是一组唯一值集合,每个值只能在Set中出现一次,Set可以容纳任何数据类型的值

  • 常用方法

①使用 new 关键字和 Set 构造函数可以创建一个集合:

let s = new Set([1, 2, 3, 2, "2"]);
console.log(s); // Set(4) { 1, 2, 3, '2' }

②add(): 添加元素

s.add("4").add("zzz");

③has(): 查询Set实例是否存在某元素(返回布尔值)

console.log(s.has("zzz")); // true

④delete(): 删除Set实例中某个元素(返回布尔值)

s.delete("zzz");

⑤clear(): 清空Set实例

s.clear();
console.log(s); // Set(0) {}

⑥size: 获取Set实例的元素个数

console.log(s.size)

⑦Set实例转数组

通过扩展运算符或者Array.from可以将Set实例转数组

let s = new Set([1, 2, 3, 4]);
console.log([...s]); // 转换为数组
console.log(Array.from(s)); // 转换为数组
  • 遍历

通过遍历可知,Set这种数据结构,它的key和value都是完全一样的值。

s.forEach((item) => console.log(item));

for (let item of s) {
  console.log(item);
}

for (let item of s.keys()) {
  console.log(item);
}

for (let item of s.values()) {
  console.log(item);
}

for (let item of s.entries()) {
  console.log(item);
}


  • 应用场景

①数组去重

// 数组去重
let arr = [1, 2, 3, 4, 2, 3];
let s = new Set(arr);
console.log(s);

②合并去重

//合并去重
let arr1 = [1, 2, 3, 4];
let arr2 = [2, 3, 4, 5, 6];
let s = new Set([...arr1, ...arr2]);
console.log(s); // Set(6) { 1, 2, 3, 4, 5, 6 }

③交集

//交集
let arr1 = [1, 2, 3, 4];
let arr2 = [2, 3, 4, 5, 6];
let s1 = new Set(arr1);
let s2 = new Set(arr2);
let result = new Set(arr1.filter((item) => s2.has(item)));
console.log(result); // Set(3) { 2, 3, 4 }

④差集

// 差集
let arr1 = [1, 2, 3, 4];
let arr2 = [2, 3, 4, 5, 6];
let s1 = new Set(arr1);
let s2 = new Set(arr2);

let arr3 = new Set(arr1.filter((item) => !s2.has(item)));
let arr4 = new Set(arr2.filter((item) => !s1.has(item)));
console.log([...arr3, ...arr4]); // [ 1, 5, 6 ]
  • WeakSet

WeakSet的使用其实和Set比较类似,他们的区别主要有两个:

  1. WeakSet的成员只能是对象,而不是能是别的类型的值
  2. WeakSet的对象都是弱引用,WeakSet没有size属性,不能遍历
const ws = new WeakSet();
const obj1 = {
  name: "zzz",
};
const obj2 = {
  name: "xxx",
};
ws.add(obj1);
ws.has(obj2);
//ws.delete(obj1);

WeakSet中的对象都是弱引用:WeakSet 中对对象的引用不会被考虑进垃圾回收机制,这些值不属于正式的引用,不会阻止垃圾回收,即只要没有其他的对象引用该对象,则该对象就会被回收,而不管它在不在 WeakSet。

因此, WeakSet 适用于临时存放一组对象,以及存放和对象绑定的信息,只要这些对象在外部消失,那么它在 WeakSet 里面的引用也会自动消失。

Map

Map是ECMAScript 6 的新增特性,是一种新的集合类型,为javascript带来了真正的键/值存储机制。

①Map 对象存有键值对,其中的键可以是任何数据类型。

②Map 对象记得键的原始插入顺序。

③Map 对象具有表示映射大小的属性。

  • 常用方法

①使用 new 关键字和 Map 构造函数创建一个映射

let m1 = new Map();
//如果想在创建的同时初始化实例,可以给 Map 构造函数传入一个可迭代对象,需要包含键/值对数组。
//可迭代对象中的每个键/值对都会按照迭代顺序插入到新映射实例中
let m2 = new Map([["key1", "val1"]]);

②set():添加键/值对

let m = new Map([["key1", "val1"]]);
let obj = {
  name: "zzz",
};
m.set(obj, "es");
console.log(m); // Map(2) { 'key1' => 'val1', { name: 'zzz' } => 'es' }

③get():获取 Map 对象中键的值

console.log(m.get(obj)); // es

③has():查询键存在于 Map 中,返回 布尔值。

console.log(m.has("key1")); // true
console.log(m.has("key2")); // false

④delete():删除一个键/值对

m.delete("key1");
console.log(m); // Map(1) { { name: 'zzz' } => 'es' }

⑤clear():清除这个映射实例中的所有键/值对

console.log(m); // Map(0) {}

⑥size属性:返回 Map 元素的数量。

console.log(m.size) // 0
  • 遍历
let map = new Map([
  ["key1", "val1"],
  ["key2", "val2"],
  ["key3", "val3"],
]);
map.forEach((value, key) => console.log(value, key));
for (let [key, value] of map) {
  console.log(key, value);
}
for (let key of map.keys()) {
  console.log(key);
}
for (let value of map.values()) {
  console.log(value);
}
for (let [key, value] of map.entries()) {
  console.log(key, value);
}
  • 应用场景

Map 的大多数特性都可以通过 Object 类型实现,但二者之间还是存在一些细微的差异。

使用 Map

①储存的键不是字符串/数字/或者 Symbol 时,选择 Map,因为 Object 并不支持

②储存大量的数据时,选择 Map,因为它占用的内存更小

③需要进行许多新增/删除元素的操作时,选择 Map,因为速度更快

④需要保持插入时的顺序的话,选择 Map,因为 Object 会改变排序

⑤需要迭代/遍历的话,选择 Map,因为它默认是可迭代对象,迭代更为便捷

使用 Object

①只是简单的数据结构时,选择 Object,因为它在数据少的时候占用内存更少,且新建时更为高效

②需要用到 JSON 进行文件传输时,选择 Object,因为 JSON 不默认支持 Map

③需要对多个键值进行运算时,选择 Object,因为句法更为简洁

④需要覆盖原型上的键时,选择 Object

虽然 Map 在很多情况下会比 Object 更为高效,不过 Object 永远是 JS 中最基本的引用类型,它的作用也不仅仅是为了储存键值对。

  • WeakMap

WeakMap是一种弱映射的集合类型,它与Map最大的不同在于,WeakMap的键只能是引用数据类型。

let wm = new WeakMap();
wm.set([1], 2);
wm.set(
  {
    name: "zzz",
  },
  "es"
);
console.log(wm);

WeakMap的常见方法有四个:set()get()delete()has()

WeakMap没有size属性,不仅不能使用clear()也不能进行遍历

WeakMap的key对对象的引用是弱引用,如果没有其他引用引用这个对象,那么垃圾回收机制(GC)可以将这个对象回收。

字符串的扩展

  • 字符的Unicode表示法

在ES6中可以采用\uxxxx的形式表示一个字符,其中xxxx表示字符的 Unicode 码点,码点范围为0000~ffff

例:

标签:11,ES6,console,log,Symbol,let,new,ES,name
From: https://www.cnblogs.com/Small-Windmill/p/17527419.html

相关文章

  • pytest + yaml 框架 -46.支持模块级别和用例级别参数化
    前言对parameters功能做了优化,支持模块级别和用例级别参数化config中parameters参数化,作用域是整个模块级别用例中parameters参数化,作用域只针对单个用例v1.3.7版本优化此功能模块级别参数化config中parameters参数化,作用域是整个模块级别,test_a.yaml文件示例......
  • postgresql大表分批次删除
    [root@localhost~]#cat/root/delete_big_table.sh#!/bin/bash#$1对应表名,$2对应主键列,$3对应一次删除多少行i=`psql-h127.0.0.1-Upostgres-dtenant_1011046-c"selectceil(count(1)/${3}::float)from${1}whereplatcreatetime<'2023-04-3023:59:59'......
  • 六月学习之Haproxy Proxies配置
    5、HaproxyProxies配置代理相关配置frontend<name>:用于定义一系列监听的端口,这些端口可接受客户端请求并与之建立连接backend<name>:用于定义一系列后端服务器,代理将会将对应客户端的请求转发至这些服务器listen<name>:通过关联"前端"和"后端"定义了一个完整的代理5.1、mo......
  • 微软确认了 Windows 11 存在 CPU 占用异常的问题
    导读微软近日确认了Windows11系统中所存在的一个错误,该问题影响了运行Windows1121H2和22H2版本的设备,换句话说就是所有发布的Windows11操作系统。该问题是在用户安装了KB5026372(2023年5月补丁)后产生的,该问题破坏了文件资源管理器的一个特定部分,导致CPU......
  • CF13E Holes
    建立一个虚拟点\(p\),满足\(p\)在LCT中编号最小。如果一个点\(i\)可以弹到点\(j\)那么\(i\)到\(j\)连一条边。如果一个点\(i\)可以被弹出那么向\(p\)连一条边。然后,直接用LCT即可。\(0\)操作直接修改即可。\(1\)操作最后落在哪一个洞就是编号区间最大值,......
  • 如何实现CesiumJS的视效升级?
    CesiumJS作为一款强大的地理可视化引擎,为我们提供了丰富的地球数据可视化和交互展示的能力。然而,随着用户需求的不断增加和技术的不断进步,如何进一步提升CesiumJS的视觉效果成为了一个重要的问题。首先,为了实现CesiumJS视觉效果的升级,我们可以考虑优化地球表面的渲染和光照效果。......
  • Educational Codeforces Round 150 A~D
    c题好难。A.GamewithBoardProblem-A-Codeforces题意给定若干个数字1,Alice和Bob每回合合并两个相同的数字,Alice先手。如果谁最先不能合并数字,谁就胜利。思路通过推导可以看出\(n<5\)时先手必输,否则先手胜利的策略是取得只剩下两个数字可以合并。代码voidsolve(){......
  • 【Maven】Unknown lifecycle phase “.test.skip=true“.问题解决
    我们在运行跳过单元测试时的命令mvnpackage-Dmaven.test.skip=true时,出现Unknownlifecyclephase".test.skip=true".如下[ERROR]Unknownlifecyclephase".test.skip=true".Youmustspecifyavalidlifecyclephaseoragoalintheformat<plugin-prefix>......
  • AtCoder Beginner Contest 308 - E
    题目链接:abc308前四题简单就不放了E-MEX阿巴阿巴,比赛的时候想复杂了,一直在想怎么快速的统计27种mex的情况,啊,前面对后面的影响等等等,反正就是想复杂了现在再想想,看了官方题解,从'E'出发,统计其前后各3种数字的个数,再用mex函数判答案,\(O(n)\)即可!剩下的见代码吧,做完之后发现,没......
  • Codeforces Round 879 (Div.2) B ~ D
    D题补了一天...B.MaximumStrengthProblem-B-Codeforces题意给定两串数字,在这两串数字之间找两串数字,要求每一数位之差的绝对值之和最大,求最大值为多少。思路对较少的那串数字添加前导零,使两串数字长度一样。要使所求值最大,就要尽可能使两数字串上相同数位的值分别为0......