免费搭建网站模板,wordpress wp users,深圳ui设计培训机构,头像定制在线生成器1、 引入Symbol类型的背景
ES5 的对象属性名都是字符串#xff0c;这容易造成属性名冲突的问题
举例: 使用别人的模块/对象, 又想为之添加新的属性,这就容易使得新属性名与原有属性名冲突
2、Symbol类型简介
symbol是一种原始数据类型
其余原始类型: 未定义(undefined) 、…1、 引入Symbol类型的背景
ES5 的对象属性名都是字符串这容易造成属性名冲突的问题
举例: 使用别人的模块/对象, 又想为之添加新的属性,这就容易使得新属性名与原有属性名冲突
2、Symbol类型简介
symbol是一种原始数据类型
其余原始类型: 未定义(undefined) 、 空值(null)、布尔值boolean、字符串string、数值number、对象objectsymbol表示独一无二的值symbol类型的真实值无法获取,也就是说Symbol类型没有对应的字面量symbol类型的意义在于区分彼此和不重复,不在于真实值
Symbol()是一种原生函数
常见的原生函数有String()、Number()、Boolean()、Array()、Object()、Function()、RegExp()、Date()、Error()、Symbol()
3、基本用法
符号需要使用Symbol()函数初始化。
let sym Symbol();
// 因为符号本身是原始类型所以typeof操作符对符号返回symbol
console.log(typeof sym); // symbol调用Symbol()函数时也可以传入一个字符串参数作为对符号的描述将来可以通过这个字符串来调试代码。但是这个字符串参数与符号定义或标识完全无关
// Symbol的值是唯一的不会出现相同值的常量
let genericSymbol Symbol();
let otherGenericSymbol Symbol();
console.log(genericSymbol otherGenericSymbol); // false// 可以传入一个字符串参数作为对符号的描述
let fooSymbol Symbol(foo);
let otherFooSymbol Symbol(foo);
console.log(fooSymbol otherFooSymbol); // false符号没有字面量语法。 按照规范只要创建Symbol()实例并将其用作对象的新属性就可以保证它不会覆盖已有的对象属性无论是符号属性还是字符串属性。
let genericSymbol Symbol();
console.log(genericSymbol); // Symbol()let fooSymbol Symbol(foo);
console.log(fooSymbol); // Symbol(foo)Symbol()函数不能与new关键字一起作为构造函数使用。 这样做是为了避免创建符号包装对象像使用Boolean、String或Number那样它们都支持构造函数且可用于初始化包含原始值的包装对象。
let myBoolean new Boolean();
console.log(typeof myBoolean); // objectlet myString new String();
console.log(typeof myString); // objectlet myNumber new Number();
console.log(typeof myNumber); // objectlet mySymbol new Symbol(); // 报错TypeError
console.log(mySymbol);如果想使用符号包装对象可以借用Object()函数
let mySymbol Symbol();
let myWarppedSymbol Object(mySymbol);
console.log(typeof myWarppedSymbol); // object4、 使用全局符号注册表
如果运行时的不同部分需要共享和重用符号实例那么可以用一个字符串作为键在全局符号注册表中创建并重用符号。 Symbol.for()方法
let fooGlobalSymbol Symbol.for(foo);
console.log(typeof fooGlobalSymbol); // symbolSymbol.for()对每个字符串键都执行幂等操作。 第一次使用某个字符串调用时它会检查全局运行时注册表发现不存在对应的符号于是就会生成一个新符号实例并添加到注册表中。 后续使用相同字符串的调用同样会检查注册表发现存在与该字符串对应的符号然后就会返回该符号实例。 // 创建新符号
let fooGlobalSymbol Symbol.for(foo);
// 重用已有符号
let otherFooGlobalSymbol Symbol.for(foo);console.log(fooGlobalSymbol otherFooGlobalSymbol); // true采用相同符号在全局注册表中定义的符号跟使用Symbol()定义的符号也不等同
// 使用Symbol()定义
let localSymbol Symbol(foo);
// 使用全局注册表定义
let globalSymbol Symbol.for(foo);console.log(localSymbol globalSymbol); // false全局注册表中的符号必须使用字符串键来创建因此作为参数传给Symbol.for()的任何值都会被转换为字符串。
注册表中使用的键同时也会被用作符号描述。
let emptyGlobalSymbol Symbol.for();
console.log(emptyGlobalSymbol); // Symbol(undefined)使用Symbol.keyFor()来查询全局注册表这个方法接收符号返回该全局符号对应的字符串键。如果查询的不是全局符号则返回undefined。
// 创建全局符号
let s Symbol.for(foo);
console.log(Symbol.keyFor(s)); // foo// 创建普通符号
let s2 Symbol(bar);
console.log(Symbol.keyFor(s2)); // undefined如果传给Symbol.keyFor()的不是符号则该方法抛出TypeError。
Symbol.keyFor(123); // TypeError: 123 is not a symbol5、 使用符号作为属性
凡是可以使用字符串或数值作为属性的地方都可以使用符号。 包括对象字面量属性和 Object.defineProperty(obj, prop, descriptor) / Object.defineProperties() 定义的属性。 对象字面量只能在计算属性语法中使用符号作为属性。
let s1 Symbol(foo),s2 Symbol(bar),s3 Symbol(baz),s4 Symbol(qux);let o {// [属性]会对属性进行读取并且转换成字符串。[s1]是读取了Symbol的字符串键foo[s1]: foo val
};
// 或 o[s1] foo val;
console.log(o); // { [Symbol(foo)]: foo val }Object.defineProperty(o, s2, { value: bar val });
console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val}Object.defineProperties(o, {[s3]: { value: baz val },[s4]: { value: qux val }
});
console.log(o); // {Symbol(foo): foo val, Symbol(bar): baz val,// Symbol(foo): foo val, Symbol(bar): qux val}
let s1 Symbol(foo),s2 Symbol(bar);let o {[s1]: foo val,[s2]: bar val,baz: baz val,qux: qux val
};// Object.getOwnPropertySymbols()返回对象实例的符号属性数组
console.log(Object.getOwnPropertySymbols(o)); // [ Symbol(foo), Symbol(bar) ]// Object.getOwnPropertyNames()返回对象实例的常规属性数组
console.log(Object.getOwnPropertyNames(o)); // [ baz, qux ]// Object.getOwnPropertyDescriptors()会返回同时包含常规和符号属性描述符的对象
console.log(Object.getOwnPropertyDescriptors(o));
// {
// baz: {
// value: baz val,
// writable: true,
// enumerable: true,
// configurable: true
// },
// qux: {
// value: qux val,
// writable: true,
// enumerable: true,
// configurable: true
// },
// [Symbol(foo)]: {
// value: foo val,
// writable: true,
// enumerable: true,
// configurable: true
// },
// [Symbol(bar)]: {
// value: bar val,
// writable: true,
// enumerable: true,
// configurable: true
// }
// }// Reflect.ownKeys()会返回两种类型的键
console.log(Reflect.ownKeys(o)); // [ baz, qux, Symbol(foo), Symbol(bar) ]注意Object.getOwnPropertyNames()和Object.getOwnProperty-Symbols()两个方法的返回值彼此互斥。 因为符号属性是对内存中符号的一个引用所以直接创建并用作属性的符号不会丢失。
但是如果没有显式地保存对这些属性的引用那么必须遍历对象的所有符号属性才能找到相应的属性键。
let o {[Symbol(foo)]: foo val,[Symbol(bar)]: bar val
};
console.log(o); // { [Symbol(foo)]: foo val, [Symbol(bar)]: bar val }let barSymbol Object.getOwnPropertySymbols(o).find((Symbol) Symbol.toString().match(/bar/));
console.log(barSymbol); // Symbol(bar)6、 所有属性
属性含义Symbol.asyncIterator符号指定了一个对象的默认异步迭代器。如果一个对象设置了这个属性它就是异步可迭代对象可用于for await…of循环。Symbol.prototype.descriptiondescription 是一个只读属性它会返回 Symbol 对象的可选描述的字符串。Symbol.hasInstance用于判断某对象是否为某构造器的实例。因此你可以用它自定义 instanceof 操作符在某个类上的行为。Symbol.isConcatSpreadable用于配置某对象作为Array.prototype.concat()方法的参数时是否展开其数组元素。Symbol.iterator为每一个对象定义了默认的迭代器。该迭代器可以被 for…of 循环使用。Symbol.match指定了匹配的是正则表达式而不是字符串。String.prototype.match() 方法会调用此函数Symbol.matchAll内置通用well-known符号指定方法返回一个迭代器该迭代器根据字符串生成正则表达式的匹配项。此函数可以被 String.prototype.matchAll() 方法调用。Symbol.replace这个属性指定了当一个字符串替换所匹配字符串时所调用的方法。Symbol.search指定了一个搜索方法这个方法接受用户输入的正则表达式返回该正则表达式在字符串中匹配到的下标这个方法由以下的方法来调用 String.prototype.search()。Symbol.species知名的 Symbol.species 是个函数值属性其被构造函数用以创建派生对象。Symbol.split指向 一个正则表达式的索引处分割字符串的方法。这个方法通过 String.prototype.split() 调用。Symbol.toPrimitive是内置的 symbol 属性其指定了一种接受首选类型并返回对象原始值的表示的方法。它被所有的强类型转换制算法优先调用。Symbol.toStringTag内置通用well-knownsymbol 是一个字符串值属性用于创建对象的默认字符串描述。它由 Object.prototype.toString() 方法内部访问。Symbol.unscopables指用于指定对象值其对象自身和继承的从关联对象的 with 环境绑定中排除的属性名称。