闽公网安备 35020302035485号
Symbol([description])举个例子:
// 堆代码 duidaima.com
const symbol1 = Symbol();
const symbol2 = Symbol(123);
const symbol3 = Symbol('test');
console.log(symbol2); // Symbol(123)
console.log(typeof symbol1); // symbol
console.log(symbol2 === 123); // 这个永远输出是false
console.log(Symbol('test')===Symbol('test'));// 永远输出是false
可以看出通过 Symbol 创建返回的symbol值都是唯一的。var symbol = new Symbol()上面这种是有问题的创建 symbol 值方式,会抛出 TypeError 错误。
2.5Object.getOwnPropertyNames():返回一个数组,其中包含对象的所有属性(包括不可枚举属性)的名称,但是不包括使用symbol值作为名称的属性
let symbol = Symbol('test');
let obj = {[symbol]:123};
for(const key in obj){
console.log(key); // 无打印信息
}
console.log(obj[symbol]); // 123
console.log(Object.keys(obj)); // []
console.log(Object.getOwnPropertySymbols(obj)); // [ Symbol(test) ]
console.log(Reflect.ownKeys(obj)); // [ Symbol(test) ]
3.Object.assign 将属性从源对象复制到目标对象,会包含 Symbol 类型作为 key 的属性const symbolKey = Symbol('key');
const source = {
[symbolKey]: 'Symbol Property',
regularProperty: 'Regular Property'
};
Object.defineProperty(source,"w",{
value:456,
enumerable:true,
configurable:true,
writable:true
})
Object.defineProperty(source,"r",{
value:123,
enumerable:false,
configurable:false,
writable:false
})
const target = {};
Object.assign(target, source);
console.log(target);
// 输出
// {
// regularProperty: 'Regular Property',
// w: 456,
// [Symbol(key)]: 'Symbol Property'
// }
// [Symbol(key)] 类型也会被打印,但是不可枚举属性不会打印
3. Symbol 在 JSON.stringify 中的问题let symbol = Symbol('test');
let obj = {[symbol]:123};
console.log(obj[symbol]); // 123
5. Symbol.For 介绍console.log(Symbol.for('test') === Symbol.for('test')); // true
console.log(Symbol("test")===Symbol("test")); // false
6. Symbol 直接传入一个函数let a = function(){
console.log('哈哈哈');
}
console.log(Symbol(a)); // Symbol(function(){ console.log('哈哈哈');})
console.log(typeof Symbol(a)); // symbol
Symbol 应用场景let symbolObjTest1 = {
0:"a",
1:"b",
2:"c",
length:3,
[Symbol.iterator]:function(){
let index = 0;
return {
next(){ // 迭代器返回的对象需要有next函数
return {
value:symbolObjTest1[index++], // value为迭代器生成的值
done:index>symbolObjTest1.length // 迭代器的终止条件,done为true时终止遍历
}
}
}
}
}
for(const iterator1 of symbolObjTest1){
console.log(iterator1); // 打印 a b c
}
demo2(Symbol.iterator属性中使用Generator)let symbolObjTest2 = {
0:"d",
1:"e",
2:"f",
length:3,
[Symbol.iterator]:function*(){ // 注意Generator函数格式
let index = 0;
while(index<symbolObjTest2.length){
yield symbolObjTets2[index++]
}
}
}
for(const iterator2 of symbolObjTest2){
console.log(iterator2);//打印 d e f
}
demo3(不影响原始对象遍历,遍历正常返回key value)const obj = {a:1,b:2,c:3};
obj[Symbol.iterator] = function*(){
for(const key of Object.keys(this)){
yield [key,this[key]]
}
}
for(const [key,value] of obj){
console.log(`${key}:${value}`); // 打印
}
总结一下,一个对象只要有[Symbol.iterator]属性,它就拥有了可迭代的能力。class Animal{
constructor(name,sex,isMammal){
this.name = name;
this.sex = sex;
this.isMammal = isMammal;
}
}
// 堆代码 duidaima.com
class Zoo{
constructor(){
this.animals = [];
}
addAnimals(animal){
this.animals.push(animal);
}
[Symbol.iterator](){
let index = 0;
const animals = this.animals;
return {
next(){
return {
value:animals[index++],
done:index>animals.length
}
}
}
}
}
const zoo = new Zoo();
zoo.addAnimals(new Animal('dog','victory',true));
zoo.addAnimals(new Animal('pig','defeat',false));
zoo.addAnimals(new Animal('cat','defeat',false));
for (const animal of zoo) {
console.log(`${animal.name};${animal.sex};${animal.isMammal}`)
}
// 打印 dog;victory;true pig;defeat;false cat;defeat;false
这个例子写完文章后感觉不太贴切,用动物园和动物进行举例,大家练习的时候可以把它改成实体和列表,更好理解const toStringCallFun = Object.prototype.toString.call; toStringCallFun(new Date); // [object Date] toStringCallFun(new String); // [object String] toStringCallFun(Math); // [object Math] toStringCallFun(undefined); // [object Undefined] toStringCallFun(null); // [object Null]我们也可以自定义函数,来覆盖默认的 toString() 方法。自定义的 toString() 方法可以是任何你想要的值。 举个例子:
function Student(score,age){
this.score = score;
this.age = age;
}
let student = new Student('100',13);
// 直接调用toString函数
console.log(student.toString()); // '[object Object]'
// 覆盖默认的toString函数
Student.prototype.toString = function(){
return `年龄${this.age};成绩${this.score}`
}
console.log(student.toString()); // 年龄13;成绩100
默认情况下,toString() 方法被每个 Object 对象继承,如果此方法在自定义对象中未被覆盖,toString() 返回“[object type]”,其中 type 是对象的类型。Object.prototype.toString.call(new Map()); // "[object Map]"
Object.prototype.toString.call(function* () {}); // "[object GeneratorFunction]"
Object.prototype.toString.call(Promise.resolve()); // "[object Promise]"
// ... and more
但是在早期不是所有对象都有 toStringTag 属性,没有 toStringTag 属性的对象也会被toString() 方法识别并返回特定的类型标签。如下:let toStringFunc = Object.prototype.toString
toStringFunc.call('foo') // '[object String]'
toStringFunc.call([1, 2]) // '[object Array]'
toStringFunc.call(3) // '[object Number]'
toStringFunc.call(true) // '[object Boolean]'
toStringFunc.call(undefined) // '[object Undefined]'
toStringFunc.call(null) // '[object Null]'
介绍了这么多再来说我们可以 Symbol.toStringTag 做点什么? 我们自己创建的类,toString() 可就找不到 toStringTag 属性喽!只会默认返回 Object 标签class TestClass{}
Object.prototype.toString.call(new TestClass());// '[object Object]'
我们给类增加一个 toStringTag 属性,自定义的类也就拥有了自定义的类型标签class TestClass{
get [Symbol.toStringTag](){
return "TestToStringTag"
}
}
Object.prototype.toString.call(new TestClass());// '[object TestToStringTag]'
Symbol.asyncIterator 实现对象异步迭代器// 异步迭代器demo
class AsyncRequest{
constructor(request){
this._request = request;
}
async *[Symbol.asyncIterator](){
for (const item of this._request) {
const res = await this._dealAsyncRequest(item);
yield res;
}
}
async _dealAsyncRequest(item){
// 模拟异步处理数据请求的过程
return new Promise((resolve)=>{
setTimeout(()=>{
resolve(item*100);
},1000)
})
}
}
(async function dealData(){
const dataSource = new AsyncRequest([1,2,3,4]);
for await(const data of dataSource){
console.log(data)
}
})()
使用 for await of 进行异步迭代时,每次迭代都会等待前一个异步操作完成,然后再进行下一次迭代,这样可确保按顺序处理每个异步操作的结果export const pathMetadataKey = Symbol('path');
export function GET(path: string) {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
Reflect.defineMetadata(pathMetadataKey, path, target, propertyKey);
implementProcess(Method.GET, path, target, propertyKey, descriptor);
}
}
自己实现一个 Symbol(function(){
let root = this;
// 因为symbol一个特殊的能力就是可以保证对象key的唯一性
const generateName = (function(){
let postfix = 0;
return function(descStr){
postfix++;
return `&&_${descStr}_&&_${postfix}`;
}
})()
const CustomSymbol = function(desc){
// 不可以 new
if(this instanceof CustomSymbol) throw new TypeError('Symbol is not a constructor')
// desc 如果不是undefined会被toString
let descStr =desc === undefined ? undefined : String(desc);
// 需保证 symbol 值唯一性
let symbol = Object.create({
toString:function(){
return this.__Name__;
// 没有直接返回Symbol字符串是和保证作为对象key的唯一性有冲突,选择了后者 obj[symbol1] obj[symbol2]
// return 'Symbol('+this.__Desc__+')';
},
// 显示调用返回该值 隐式调用(会先调用对象的valueOf函数,如果没有返回基本值,就会再调用toString方法)
valueOf:function(){
return this;
}
});
// 保证 symbol 值唯一性
Object.defineProperties(obj,{
'__Desc__':{
value:descStr,
writable:false,
enumerable:false,
configurable:false,
},
// __Name__的generateName保证作为对象key时唯一性
'__Name__':{
value:generateName(descStr),
writable:false,
enumerable:false,
configurable:false,
}
});
return symbol;
}
let forMap = {}
Object.defineProperties(customSymbol,{
// 实现 Symbol.for
'for':{
value:function(desc){
let descStr = des
if(!Reflect.has(forMap,key)){
Reflect.set(forMap,key,customSymbol(descStr))
}
return Reflect.get(forMap,key)
},
writable:false,
enumerable:false,
configurable:false,
},
// 实现 Symbol.keyFor
'keyFor':{
value:function(symbolValue){
for (const [key,value] of forMap.entries()) {
if(value === symbolValue) return key
}
},
writable:false,
enumerable:false,
configurable:false
}
})
root.symbol = CustomSymbol;
})()
---------------------------------文章到此结束,欢迎点赞收藏-------------------------