周口网站推广,推广普通话奋进新征程海报,启博微分销官网,注册网站用什么邮箱一、简介
symbol类型是ES6新引入的一种基本数据类型#xff0c;该类型具有静态属性和静态方法。其中静态属性暴露了几个内建的成员对象#xff0c;静态方法暴露了全局的symbol注册。
symbol类型具有以下特点#xff1a;① 唯一性#xff1a;每个symbol值都是唯一的…一、简介
symbol类型是ES6新引入的一种基本数据类型该类型具有静态属性和静态方法。其中静态属性暴露了几个内建的成员对象静态方法暴露了全局的symbol注册。
symbol类型具有以下特点① 唯一性每个symbol值都是唯一的② 不可变性symbol值是不可被修改的③ 属性标识符symbol类型的值可以作为对象属性的标识符key④Symbol可以与其他数据类型进行运算但不能被强制转换为其他数据类型。利用前两个特性可以避免属性名的冲突和保证属性不会被意外覆盖。
symbol类型在许多库和框架中被广泛应用常见的应用场景有创建私有属性、定义常量、定义事件名称以及实现各种标识符相关的功能。
二、创建
1、Symbol([description])
通过Symbol([description])函数创建symbol类型的值但并不会被添加到全局symbol表中可选参数description是字符串类型的数据表示对当前symbol的描述该参数只用来作为标识并不会影响symbol的唯一性。
但该函数并不是一个构造函数因为该函数不支持new Symbol()的语法如果使用该语法将会抛出TypeError错误。每个通过Symbol()函数获取的symbol类型的值都是唯一的、独一无二的即使两个symbol拥有相同的description它们也属于两个不同的值。
// 创建symbol数据
let s Symbol();
console.log(s); // Symbol()
console.log(typeof s); // symbol
// 创建symbol数据并添加描述
let s1 Symbol(one);
console.log(s1); // Symbol(one)
console.log(typeof s1); // symbol
// 创建symbol数据并添加相同的描述
let s2 Symbol(one);
console.log(s2); // Symbol(one)
console.log(typeof s2); // symbol
// 判断symbol数据是否相等
console.log(s1 s2); // false
console.log(s1 s2); // false
// 使用new关键字创建symbol数据
let s3 new Symbol(); // Uncaught TypeError: Symbol is not a constructor2、Symbol.for(key)
第四部分常用方法章节中讲解。
三、常用属性
1、description只读
该属性是一个只读属性用于获取当前symbol值的描述字符串。
案例代码
// 创建symbol数据 不添加描述
let s Symbol();
// 创建symbol数据并添加描述
let s1 Symbol(one);// 使用description输出symbol数据的描述
console.log(s.description); // undefined
console.log(s1.description); // one2、hasInstance
该属性是 Symbol 类型的一个内置静态属性属性值是一个 Symbol 值它是不可变的用于定义对象的 hasInstance 方法的键hasInstance 方法用于判断一个对象是否为某个构造函数的实例我们可以利用该属性自定义instanceof操作符在某个类上的行为。
当一个对象被使用 instanceof 运算符检查其原型链时会调用该对象的 hasInstance 方法。换句话说obj instanceof Constructor 实际上是调用了 Constructor[Symbol.hasInstance](obj)。因此我们可以通过自定义的 hasInstance 方法来自定义判断对象是否为某个构造函数的实例。
案例代码
class MyArray {static [Symbol.hasInstance](instance) {return Array.isArray(instance);}
}
console.log([] instanceof MyArray); // true
console.log({} instanceof MyArray); // fales3、isConcatSpreadable
该属性是 Symbol 类型的一个内置静态属性属性值是一个 Symbol 值它是不可变的用于定义对象的 isConcatSpreadable 的键。isConcatSpreadable 方法是一个内部Symbol用于确定对象在调用数组的 concat() 方法时是否展开其元素。
如果isConcatSpreadable 返回true默认值则对象元素被展开合并如果方法返回false则将对象作为单个元素添加到数组中构成多维数组的形式。我们可以通过设置对象的 isConcatSpreadable 来自定义对象在 concat() 方法中的展开行为
案例代码
let arr1 [1, 2, 3]
let arr2 [a, b, c]
// 默认为true 进行展开合并
console.log(arr1.concat(arr2)); // [1, 2, 3, a, b, c]
// 设置arr2 的值为false
arr2[Symbol.isConcatSpreadable] false
// 再次合并 此时不会展开
console.log(arr1.concat(arr2)); // [1, 2, 3, [a, b, c]]4、iterator
Symbol.iterator 是 Symbol 类型的一个内置静态属性属性值是一个 Symbol 值用于定义对象的默认的迭代器iterator。 iterator 方法是一个特殊的内部方法用于返回一个迭代器对象。
当一个对象使用 for...of 循环或扩展运算符 (...)进行遍历时会调用该对象的 iterator 方法来获取一个迭代器对象。迭代器对象可以通过调用其 next() 方法来依次访问对象的每个元素。我们可以通过自定义 iterator 方法来实现自定义的迭代器行为。自定义的 iterator 方法应该返回一个具有 next() 方法的迭代器对象。每次调用 next() 方法时迭代器对象应该返回一个包含 value 和 done 属性的对象value 表示当前迭代的值done 表示迭代是否结束。
案例代码
let arr3 [1, 2, 3]
// for..of..形式遍历
console.log(for..of..形式遍历);
for (const item of arr3) {console.log(item);
}
// ... 扩展运算符形式遍历
console.log(扩展运算符形式遍历);
console.log([...arr3]);
// 自定义默认迭代器
arr3[Symbol.iterator] function () {let index 0;return {next: function () {if (index arr3.length) {return { value: arr3[index] * 3, done: false };} else {return { value: undefined, done: true };}}};
};
// 输出数组本身
console.log(输出数组本身);
console.log(arr3);
// for..of..形式遍历
console.log(for..of..形式遍历);
for (const item of arr3) {console.log(item);
}
// ... 扩展运算符形式遍历
console.log(扩展运算符形式遍历);
console.log([...arr3]);
// forEach 形式遍历
console.log( forEach 形式遍历);
arr3.forEach(item {console.log(item);
});
// for 形式遍历
console.log(for 形式遍历);
for (let i 0; i arr3.length; i) {console.log(arr3[i]);
}执行结果 5、toPrimitive
Symbol.toPrimitive 是 Symbol 类型的一个内置静态属性用于定义对象的 toPrimitive 转换方法的键。 toPrimitive 转换方法是一个内部方法用于将对象转换为一个原始值它接受一个参数 hint表示预期的转换类型。hint 参数可以是以下三个值之一
default表示该对象可以被转换为任意类型的原始值例如 x 强制转为原始值而不是字符串。number表示该对象被期望转换为数字类型的原始值例如算术运算-*/。string表示该对象被期望转换为字符串类型的原始值例如模板字符串${}、String()等。
参数 hint 的值根据上下文和操作的需要等诸多复杂因素来决定如调用对象的运算符、隐式类型转换、valueOf 和 toString 方法等等。
当一个对象被用于需要原始值的上下文中例如进行算术运算或字符串拼接时JavaScript 引擎会首先查找对象的 Symbol.toPrimitive 属性。如果该属性存在并且是一个函数引擎将调用该函数并传入相应的 hint 参数转换获取对象的原始值即字符串、数字或布尔值。我们可以通过自定义 toPrimitive 方法来自定义对象的转换行为完全控制原始转换过程并返回对象的原始值。
案例代码
// 一个没有提供 Symbol.toPrimitive 属性的对象
const obj1 {};
console.log(obj1); // NaN
console.log(${obj1}); // [object Object]
console.log(obj1 ); // [object Object]// 接下面声明一个对象手动赋予了 Symbol.toPrimitive 属性
const obj2 {};
obj2[Symbol.toPrimitive] function (hint) {// hint 参数值是 numberif (hint number) {// 返回对象有多少条属性return Object.keys(obj2).length;}// hint 参数值是 stringif (hint string) {// 返回对象转换成的JSON字符串return JSON.stringify(obj2);}// hint 参数值是 defaultreturn true;
};
console.log(obj2); // 0
console.log(${obj2}); // {}
console.log(obj2 ); // true6、match、replace、search、toStringTag等其他属性
请自行了解。。。
四、常用方法
1、for()
Symbol.for(key)方法会根据参数key从所有声明的全局symbol数据中寻找对应的值不包括通过Symbol()创建的数据如果这个值存在则返回它如果不存在则新建一个以这个key为description的全局symbol数据并将创建的数据返回。
如果先使用Symbol()创建了以这个key为description的数据然后再使用该方法进行查找则也不会被查找到因为该方法只在全局symbol数据中进行查找而Symbol()创建的是非全局的数据。
// 第一次使用for()方法 由于之前不存在以foo为key的symbol 所以创建一个 symbol 并放入 symbol 注册表中键为 foo
const a Symbol.for(aaa);
// 第二次使用for()方法 由于之前注册过 所以直接从 symbol 注册表中读取键为foo的 symbol
const b Symbol.for(aaa);
// 验证两者是否为同一个symbol
console.log(a b); // true// 如果是通过Symbol()方法创建 则会创建两个key相同的symbol 但并不是同一个symbol
const c Symbol(bbb);
const d Symbol(bbb);
// 验证两者是否为同一个symbol
console.log(c d); // false2、keyFor()
Symbol.keyFor(symbol)方法会根据参数symbol从所有声明的全局symbol数据中寻找该数据并返回该数据的key。如果从全局symbol数据中查找到该 symbol则返回该 symbol 的 key 值返回值为字符串类型如果不存在该symbol或者该symbol对应的key为空则返回 undefined。
如果参数symbol是通过Symbol()创建的数据则也不会被查找到因为该方法创建symbol数据并非全局的返回值为undefined。
// 创建一个全局 Symbol 且有key
const a Symbol.for(aaa);
console.log(Symbol.keyFor(a)); // aaa
// 创建一个全局 Symbol 但没有key
const b Symbol.for();
console.log(Symbol.keyFor(b)); // undefined
// 创建一个非全局 Symbol 且有key
const c Symbol(ccc);
// 创建一个全局的 Symbol 且有相同的key
const c2 Symbol.for(ccc);
console.log(Symbol.keyFor(c)); // undefined
console.log(Symbol.keyFor(c2)); // ccc
// 验证两者是否为同一个symbol
console.log(c c2); // false
// 下面的 原生Symbol 没有保存在全局 Symbol 注册表中
console.log(Symbol.keyFor(Symbol.iterator)); // undefined3、toString()
Symbol对象拥有自己的toString()方法覆盖了原型链上的Object.prototype.toString()方法。
symbol数据不能隐式转换为字符串因此需要toString()方法将数据转换成字符串。
// 创建一个symbol
const a Symbol(aaa);
console.log(a.toString()); // Symbol(aaa)
// 创建一个全局symbol
const b Symbol.for(bbb);
console.log(b.toString()); // Symbol(bbb)4、valueOf()等其他方法
请自行了解。。。
五、相关应用
1、作为对象唯一的属性键
Symbol可以用作对象属性的键确保属性key的唯一性避免属性被意外覆盖或冲突。
// 声明一个 symbol 数据
const a Symbol(aaa);
// 声明一个全局 symbol 数据
const b Symbol.for(bbb)
// 声明对象 利用 symbol 数据作为 key
const obj {[a]: 11111111,a: 22222222,[b]: 33333333
};
// 再次声明一个 symbol 数据 与 a 有相同的description
// 以该symbol作为key 修改数据 虽然声明时的 description 相同
// 但是是两个不同的 symbol 数据 所以obj[Symbol(aaa)] 与 obj[a] 是两个不同的属性
// 修改其中一个不会影响另一个
obj[Symbol(aaa)] 44444444;
// 输出属性数据
console.log(obj[a]); // 11111111
// 此处相当于又声明了一个symbol
console.log(obj[Symbol(aaa)]); // undefined
// 再次输出对象的数据
console.log(obj);// 可通过 symbol 数据作为 key 修改数据
// obj[a] 44444444;执行结果 2、声明唯一的常量
借助Symbol数据的唯一性我们可以声明常量并确保常量值的唯一性而且不会被意外修改或覆盖。
// 声明一个常量 且常量值为 symbol 数据
const a Symbol(aaa);
// 在函数中匹配常量值
function myFunction(value) {// 判断传入的值是否与常量值相等if (value a) {console.log(常量值被匹配);} else {console.log(常量值未匹配);}
}
// 传入定义的变量
myFunction(a); // 输出 常量值被匹配
// 传入一个新的 symbol 数据 且 description 与常量值相同
myFunction(Symbol(aaa)); // 输出 常量值未匹配3、改写对象的内置方法
通过利用Symbol和内置属性我们可以改写对象的内置方法以适应特定的业务场景并自定义对象的行为。但在改写内置方法时不能破坏原有的语言规范和其他代码的预期行为。
// 声明一个对象 并改写其内置toString方法的返回值
const myObj {// 该Symbol的内置属性 决定了toString方法的返回值[Symbol.toStringTag]: MyObject,
};
// 输出对象的toString方法的返回值
console.log(Object.prototype.toString.call(myObj)); // 输出 [object MyObject]4、定义类的私有成员
Symbol可以在类中作为私有成员的标识符。
// 定义一个symbol数据
const _privateMember Symbol(private);
// 定义一个类
class MyClass {constructor() {// 定义类的私有成员 以symbol数据作为标识符this[_privateMember] 私有成员;}// 私有成员的get方法getPrivateMember() {return this[_privateMember];}
}// new 一个实体对象
const instance new MyClass();
// 通过get方法正常访问
console.log(instance.getPrivateMember()); // 输出 私有成员
// 直接访问 无法访问
console.log(instance[_privateMember]); // 输出 undefined5、其他用法。。。
六、参考资料
Symbol