使用 Symbol,表示独一无二的值
每个 Symbol 是不一样的
不能进行运算
可以显式调用 toString()
可以隐式转换 boolean
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Symboltitle>
head>
<body>
<script>
let obj = {
name: "ich",
getName() {
console.log(this.name);
}
}
obj.name = "du";
// 设置的对象属性值被随意改动
obj.getName(); // du
// 使用 Symbol,表示独一无二的值
let s1 = Symbol(); // 生成一个 Symbol 类型数据
let s2 = Symbol();
console.log(typeof s1); // symbol
// 每个 Symbol 是不一样的
console.log(s1 == s2); // false
console.log(s1 === s2); // false
// 不能进行运算
// console.log(s1 + "aaaa"); // Uncaught TypeError: Cannot convert a Symbol value to a string
// console.log(s1 > "aaaa"); // Uncaught TypeError: Cannot convert a Symbol value to a number
// 可以显式调用 toString()
console.log(s1.toString()); // Symbol
console.log(s1.toString() + "aaa"); // Symbolaaa
// 可以隐式转换 boolean
// s1 被转换成 true
if (s1) {
console.log("执行");
}
script>
body>
html>
用法:由于每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>使用Symbol作为对象属性名title>
head>
<body>
<script>
let obj = {
name: "ich",
getName() {
console.log(this.name);
}
}
let name = Symbol();
obj[name] = "du";
console.log(obj[name]); // du
// 定义 symbol 变量,添加到 对象 作为对象的属性
// 作为新的属性,不会覆盖重名的普通属性
console.log(obj.name); // ich
// 不想对象属性被随意更改,使用symbol
let name1 = Symbol();
let age1 = Symbol();
let obj1 = {
[name1]: "ich",
[age1]: 100
}
console.log(obj1[name1]);
console.log(obj1[age1]);
// 不可以直接在里面这样定义,外面访问不到
let obj2 = {
[Symbol()]: "no",
}
console.log(obj2[Symbol()]); // 找的是另一个新创建的 Symbol 变量,所以是 undefined
// 使用Symbol作为对象属性名
let keys = {
name: Symbol(),
age: Symbol(),
location: Symbol(),
test: Symbol()
}
let obj3 = {
[keys.name]: "ich",
[keys.age]: 100,
[keys.location]: "cn",
[keys.test]() {
console.log("test");
}
}
script>
body>
html>
问题:都是Symbol,分不清是哪个对象属性
解决:
Symbol()函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述
这主要是为了在控制台显示,比较容易区分
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Symbol()函数的参数title>
head>
<body>
<script>
let keys = {
name: Symbol("name"),
age: Symbol("age"),
location: Symbol("location"),
test: Symbol("test")
}
let obj = {
[keys.name]: "ich",
[keys.age]: 100,
[keys.location]: "cn",
[keys.test]() {
console.log("test");
}
}
console.log(obj);
script>
body>
html>
Symbol 值作为属性名时,不会出现在 for…in 、 for…of 的循环中,也不会被 Object.keys() 、 Object.getOwnPropertyNames() 返回
如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols() 和 Reflect.ownKeys() 取到
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Symbol 的遍历问题title>
head>
<body>
<script>
let keys = {
name: Symbol("name"),
age: Symbol("age"),
location: Symbol("location"),
test: Symbol("test")
}
let obj = {
[keys.name]: "ich",
[keys.age]: 100,
[keys.location]: "cn",
[keys.test]() {
console.log("test");
}
}
// 设置对象普通属性
obj.name = "du";
obj.age = 20;
// for in 遍历打印出来的都是普通属性,并没有打印symbol属性
for (let i in obj) {
console.log(i);
}
// 遍历 symbol 要使用 Object.getOwnPropertySymbols() 方法
console.log(Object.getOwnPropertySymbols(obj));
// 普通属性和symbol属性全部遍历
console.log(Reflect.ownKeys(obj));
// 每个遍历对象属性和属性对应的值
Reflect.ownKeys(obj).forEach(item => {
console.log(item, obj[item]);
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Symbol作为常量title>
head>
<body>
<script>
// Symbol 作为常量
// const VIDEO = 1;
// const AUDIO = 1;
// const IMAGE = 1;
// 不用赋值,固定用变量名来判断
const VIDEO = Symbol();
const AUDIO = Symbol();
const IMAGE = Symbol();
function play(type) {
switch (type) {
case VIDEO:
console.log("视频播放");
break;
case AUDIO:
console.log("音频播放");
break;
case IMAGE:
console.log("图片播放");
break;
default:
break;
}
}
// 参数不一样也可以执行
play(VIDEO);
// play(1); // 没执行
script>
body>
html>
Symbol.for()可以重新使用同一个 Symbol 值
Symbol.for() 是 JavaScript 中的内置函数,用于将给定符号搜索到 runtime-wide 符号注册表中,如果找到该符号,则返回相同符号,否则将在全局变量中创建与该符号相同名称的新符号符号注册表并返回它们
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Symbol.fortitle>
head>
<body>
<script>
var obj = {
[Symbol.for("name")]: "kerwin",
[Symbol.for("age")]: 100
}
console.log(obj[Symbol.for("name")]);
script>
body>
html>
Iterator 的遍历过程是这样的
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>介绍迭代器title>
head>
<body>
<script>
let arr = ["aaa", "bbb", "ccc"];
console.log(arr);
// 获得的是数组元素的索引值
for (let i in arr) {
console.log(i);
}
// 获得的是数组元素的内容
for (let i of arr) {
console.log(i);
}
let iter = arr[Symbol.iterator]();
// 返回的是遍历器对象/迭代器对象
console.log(iter);
console.log(iter.next()); // Object { value: "aaa", done: false }
console.log(iter.next()); // Object { value: "bbb", done: false }
console.log(iter.next()); // Object { value: "ccc", done: false }
console.log(iter.next()); // Object { value: undefined, done: true } - true表示数组已经没有元素可以遍历
// Iterator 的遍历过程是这样的。
// (1)创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象
// (2)第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
// (3)第二次调用指针对象的next方法,指针就指向数据结构的第二个成员
// (4)不断调用指针对象的next方法,直到它指向数据结构的结束位置
script>
body>
html>
ES6 规定,默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,或者说,一个数据结构只要具有 Symbol.iterator 属性,就可以认为是“可遍历的”(iterable)。Symbol.iterator 属性本身是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器
原生默认具备 Iterator 接口的数据结构如下
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>具备 Iterator 接口的数据结构title>
head>
<body>
<script>
// 字符串数组
let str = "ichdu";
let iter1 = str[Symbol.iterator]();
console.log(iter1.next());
console.log(iter1.next());
console.log(iter1.next());
// arguments 对象
function test() {
for (let i of arguments) {
console.log(i);
}
}
test(1, 2, 3, 4);
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>对象遍历title>
head>
<body>
<script>
// 对象 非线性
// let obj = {
// 0: "ich",
// 1: "du",
// 2: "ichdu"
// }
// for (let i of obj) {
// console.log(i);
// // Uncaught TypeError: obj is not iterable
// // 报错,不是一个可以遍历的结构
// }
let obj = {
0: "ich",
1: "du",
2: "ichdu",
// 数组是有长度的,不然不知道结束
length: 3,
// 将数组的原型赋值给 对象的 [Symbol.iterator]
[Symbol.iterator]: Array.prototype[Symbol.iterator]
}
// 因为加了迭代器,对象可遍历
for (let i of obj) {
console.log(i);
}
// 应用:在对象中获取遍历 list 属性
let obj2 = {
code: 200,
name: "obj2",
list: ["ich", "du", "ichdu"],
// 迭代器
[Symbol.iterator]() {
// 设置一个获得 list 索引的参数
let index = 0;
// 返回
return {
// 设置箭头函数是为了 this 指向 obj2
next: () => {
return {
// 获得对象属性 list 的值
value: this.list[index++],
// 判断是否超过 list 长度,超过返回 true,否则返回 false 可以继续执行遍历
// 因为 index 在上面做了加加自增操作,所以
done: index === (this.list.length + 1) ? true : false
}
}
}
}
}
let iter = obj2[Symbol.iterator]();
console.log(iter);
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
// 给对象加了迭代器,obj2 对象可遍历
for (let i of obj2) {
console.log(i);
}
script>
body>
html>
它类似于数组,但成员的值都是唯一的,没有重复的值
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>set 结构title>
head>
<body>
<script>
let s1 = new Set([1, 2, 3, 4, 2, 2, 3, 3, 3, 3, 3]);
console.log(s1);
// 满足 iterator
// 可以使用 ... 转换成数组
console.log([...s1]);
// Array.from 也可以转换数组
console.log(Array.from(s1));
// 初始化 set 结构的空数组,然后使用 add 函数添加元素
let s2 = new Set();
s2.add(1);
s2.add(2);
s2.add(2);
s2.add(3);
console.log(s2);
// 遍历 set 结构数组
for (let i of s1) {
console.log(i);
}
script>
body>
html>
打印 set 结构,发现不是数组,而是 Set 对象是值的集合,但是有迭代器,可以转换成数组
Set.prototype.add(value)
:添加某个valueSet.prototype.delete(value)
:删除某个value,返回一个布尔值,表示删除是否成功。Set.prototype.has(value)
:返回一个布尔值,表示该值是否为Set
的成员Set.prototype.clear()
:清除所有成员,没有返回值DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>实例的属性和方法title>
head>
<body>
<script>
let s1 = new Set([1, 2, 3, 4]);
// 实例的属性和方法
// size:返回Set实例的成员总数
console.log(s1.size);
// add
// Set.prototype.add(value):添加某个value
s1.add(5);
s1.add(6).add(7);
console.log(s1); // Set(7) [ 1, 2, 3, 4, 5, 6, 7 ]
// has
// Set.prototype.has(value):返回一个布尔值,表示该值是否为`Set`的成员
console.log(s1.has(8)); // false
console.log(s1.has(5)); // true
// delete
// Set.prototype.delete(value):删除某个value,返回一个布尔值,表示删除是否成功
s1.delete(5);
console.log(s1.has(5)); // false
// clear
// Set.prototype.clear():清除所有成员,没有返回值
s1.clear();
console.log(s1); // Set []
script>
body>
html>
Set.prototype.keys()
:返回键名的遍历器Set.prototype.values()
:返回键值的遍历器Set.prototype.entries()
:返回键值对的遍历器Set.prototype.forEach()
:遍历每个成员DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Set结构遍历title>
head>
<body>
<script>
let s1 = new Set([1, 2, 3]);
// 遍历
console.log("for of 普通遍历");
for (let i of s1) {
console.log(i);
}
console.log("== Set.prototype.keys():返回键名的遍历器 ==");
for (let i of s1.keys()) {
console.log(i);
}
console.log("== Set.prototype.values():返回键值的遍历器 ==");
for (let i of s1.values()) {
console.log(i);
}
console.log("== Set.prototype.entries():返回键值对的遍历器 ==");
for (let i of s1.entries()) {
console.log(i);
}
console.log("== entries 与数组结合 ==");
let arr = ["aaa", "bbb", "ccc"];
for (let i of arr.entries()) {
console.log(i);
}
console.log("== 打印 索引值 和 对应的内容 ==");
for (let [index, item] of arr.entries()) {
console.log(index, item);
}
console.log("== Set.prototype.forEach():遍历每个成员 ==");
s1.forEach((item, index) => {
console.log(item, index);
})
script>
body>
html>
定义函数,设置传入的数组的参数
定义 Set 结构的数组,将传入的数组的元素逐个转换成字符串,
再进行 Set 的 has 方法对各个字符串进行判断是否相同,
相同则不进行 add 添加元素
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>复杂数据结构去重title>
head>
<body>
<script>
let arr = [1, 2, 2, "ich", "ich", "du",
[1, 2], [3, 4], [1, 2],
{ name: "ich" }, { age: 100 }, { name: "ich" }];
console.log(arr);
function uni(arr) {
let res = new Set();
return arr.filter((item) => {
// 判断是否有相同的内容 has true false
// 没有就 return true
// JSON.stringify()的作用是将 JavaScript 对象转换为 JSON 字符串
let id = JSON.stringify(item);
if (res.has(id)) {
return false;
} else {
res.add(id);
return true;
}
})
}
console.log(uni(arr));
script>
body>
html>
类似于对象,也是键值对的集合,但是 “键” 的范围不限于字符串,各种类型的值(包括对象)都可以当作键
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Map 结构title>
head>
<body>
<script>
let m1 = new Map([
["name", "ich"],
["age", 100],
[{ a: 1 }, "广东"]
])
console.log(m1);
// 定义空 Map
let m2 = new Map();
m2.set("name", "ich");
m2.set("age", 100);
m2.set({ a: 1 }, "广东");
console.log(m2);
// 遍历
for (let i of m2) {
console.log(i);
}
// 将 Map 结构转换成数组
console.log([...m2]);
script>
body>
html>
Map.prototype.set(key,value)
:添加key对应得value,返回 Map 结构本身Map.prototype.get(key)
:获取key对应的valueMap.prototype.delete(key)
:删除某个键(键名+键值)Map.prototype.has(key)
:某个键是否在当前 Map 对象之中Map.prototype.clear()
:清除所有成员,没有返回值DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>实例的属性和方法title>
head>
<body>
<script>
let m2 = new Map();
// Map.prototype.set(key,value):添加key对应得value,返回 Map 结构本身
m2.set("name", "ich");
m2.set("age", 100);
// 用 get 获得相应的内容
// Map.prototype.get(key):获取key对应的value
// m2.set({ a: 1 }, "广东");
// 这样获取不到对象,获取的时候会判断不相等
let o = { a: 1 };
m2.set(o, "广东");
console.log(m2.get(o));
console.log(m2.get("name"));
// Map.prototype.has(key):某个键是否在当前 Map 对象之中
console.log(m2.has("age")); // true
// Map.prototype.delete(key):删除某个键(键名+键值)
m2.delete("age");
console.log(m2.has("age")); // false
// size:返回 Map 结构的成员总数
console.log(m2.size); // 2
// Map.prototype.clear():清除所有成员,没有返回值
m2.clear();
console.log(m2); // Map(0) {size: 0}
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Map 遍历title>
head>
<body>
<script>
let m2 = new Map();
m2.set("name", "ich");
m2.set("age", 100);
let o = { a: 1 };
m2.set(o, "广东");
// keys()
console.log("== Map.prototype.keys():返回键名的遍历器 ==");
for (let i of m2.keys()) {
console.log(i);
}
// values()
console.log("== Map.prototype.values():返回键值的遍历器 ==");
for (let i of m2.values()) {
console.log(i);
}
// entries()
console.log("== Map.prototype.entries():返回所有成员的遍历器 ==");
for (let [index, item] of m2.entries()) {
console.log(index, item);
}
// 和上一个一样的,因为迭代器都是相同的
for (let [index, item] of m2) {
console.log(index, item);
}
// forEach()
console.log("== Map.prototype.forEach():遍历 Map 的所有成员 ==");
m2.forEach((item, index) => {
console.log(item, index);
})
script>
body>
html>
GitHub代码
gitee代码