ES6
Symbol(简单篇)
概念
symbol类型表示的是独一无二的值,常用在定义对象的唯一属性名。
描述为字符串或者是数字。在内存中代表一个唯一的值。

let s1=Symbol('111'); // Symbol(111)
let s2=Symbol('222'); // Symbol(222)
let s3=Symbol.iterator;
let arr=[1,2,3]
console.dir(s1);
console.dir(s2);
console.dir(s3);
console.log(s1===s2);
console.log(arr);
console.log(arr[Symbol.interator])

注意点
不能new
不能参与运算


基础用法
定义很多常量,然后又不希望它们重复。
绝对不可能重复,因为每一个symbol都是不一样的。


高级用法
-
定义对象的唯一属性名
-
不会被Object.keys和for...in遍历到,所以它起到了私有属性保护的作用。同理,也不会被JSON.stringify到。

-
当用symbol去定义对象属性的时候,一定要用中括号 [ ] 语法;(声明、获取、赋值都需要中括号包裹)
let a={};
let s=Symbol(123)
// 给对象添加属性
a[s]='hello'
console.log(a);
// 字面量
let b={
[s]:'world',
x:'hello',
}
console.log(b);
console.log(Object.keys(b));

案例

let obj={
name:'angela',
age:18,
gender:1,
[Symbol('password')]:'123456'
};
console.log(JSON.stringify(obj));
共享容器中的使用
需要有唯一值的,不希望多个字段覆盖的情况
class Cache{
static data={};
static set(name,value){
this.data[name]=value;
}
static get(name){
return this.data[name];
}
}
let user={
name:'apple',
age:18,
key:Symbol(),
}
let cart={
name:'apple',
key:Symbol()
}
Cache.set(user.key,user);
Cache.set(cart.key,cart);
console.log(Cache.data);
扩展
for-in
遍历对象用for-in,for-of不能用在对象上
-
for-in是会遍历到原型链上的属性的;Object.keys()、hasOwnProperty是不会的
for of 和 for in 的区别_前端路上有你有我!-优快云博客_forof和forin的区别

Object.getOwnPropertySymbols
获取此对象的Symbol属性
Object.prototype[Symbol('global')]='global'
let obj={
a:'hello world',
b:'hello jsp',
[Symbol('blue')]:'blue',
[Symbol('red')]:'red',
}
console.log(obj)
// 遍历不到原型链上的属性的
console.log(Object.getOwnPropertySymbols(obj));
// 获取全部属性
console.log(Reflect.ownKeys(obj));
Object.prototype.a='a'
class User{
type='people';
constructor(name){
this.name=name;
this[Symbol('site')] = 'houdunren';
}
getName(name){
return this.name;
}
}
let person= new User('angela');
console.log(person.getName());
console.log(person);
for(key in person){
console.log('---')
console.log(key)
if(person.hasOwnProperty(key)){
console.log(key)
}
}
Symbol.for()
Symbol.for是全局的,他首先会去全局搜索有没有这个symbol值,有就直接返回;没有才去创建。Symbol.for有一个登记机制,会在内存中有一个记录。比如,Symbol.for 100次,其实只有一个symbol;但是Symbol 100次,会有100个symbol。
全局定义的symbol可以通过Symbol.keyFor(symbol_var)获取到它的描述
es6 Symbol.for(),Symbol.keyFor()_歪脖先生的博客-优快云博客_symbol.for
Symbol类型
前置知识
js数据类型:
原始类型
null undefined boolean string number Symbol bigint
对象类型
标准普通对象:大括号包裹的
标准特殊对象:数组 正则 date error
非标准特殊对象:new Number() ->原始类型所对应的对象类型实例
函数对象:function
概念
Symbol:唯一值
不能被new执行的:与类的区别,创建实例,通过new来执行

例子:

运用场景
语法:用 [] 包裹
场景:
-
给对象设置唯一值的属性

获取对象属性的一些方法:
for-in:遍历不到Symbol;会把原型上可枚举(公共)的属性迭代到,所以性能就比较差;
Object.key:获取自身的私有属性,非Symbol的
Object.getOwnPropertySymbols:获取对象的Symbol属性
Reflect.ownKeys:对象的Symbol+非Symbol属性

-
公共状态管理:行为标识


Symbol.for
symbol全局注册表的概念


迭代器
打印一下Symbol
.for .keyFor
.match .matchAll 跟正则匹配相关的
迭代器规范
-
只要部署了interator接口机制就可以完成for-of循环遍历,for-of循环的底层机制是用的iterator
-
迭代器规范要求需要有一个next方法

有Symbol.iterator属性的我们就说具备迭代器规范的

for-of的原理:手写Symbol.iterator
-
for-of循环开始就会调Symbol.iterator函数,而这个函数就是按照Iterator规范来设计的
-
迭代器规范是这样,Symbol.iterator要返回一个对象,该对象要具有next方法,每次for-of都会执行这个方法;而next也会返回一个对象,该对象有2个固定的属性,done表示迭代是否完成,value表示当前迭代返回的结果



let obj={
name:'angela',
age:18,
[Symbol('abc')]:'abc',
}
Object.prototype[Symbol.iterator]=function(){
let index = 0;
const self=this;
// 这是获取非Symblo属性
// const keys=Object.keys(self);
// 这是获取所有属性
const keys=Reflect.ownKeys(self);
return {
next(){
if(index>keys.length-1){
return {
done:true,
value:undefined,
}
}
return{
done:false,
value:self[keys[index++]]
}
}
}
}
for(let abc of obj){
console.log(abc);
}
生成器
生成器对象
概念:前面加 * 号的就是generator生成器函数,它会返回一个迭代器对象。并不会执行函数体。调用next才开始执行函数体,遇到yield则停止。
function* generator(){
console.log('1--')
yield 10;
console.log('2--')
yield 20;
console.log('3--')
yield 30;
}
let iter=generator()
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());

for await of
[Symbol.asyncIterator]函数必须要async修饰
yield返回一个promise实例,await等待其resolve
循环处理promise,适合串行需求
2个要注意的地方:
-
立即执行函数要加async,因为里面有for await;
-
generator函数要加async,因为其函数体中有return new Promise
function func1(){
return new Promise(resolve=>{
setTimeout(()=>{
resolve()
},1000)
})
}
function func2(){
return new Promise(resolve=>{
setTimeout(()=>{
resolve()
},2000)
})
}
function func3(){
return new Promise(resolve=>{
setTimeout(()=>{
resolve()
},3000)
})
}
let obj={};
obj[Symbol.asyncIterator]=async function*(){
console.log('1 start');
// 等待promise实例成功
yield func1();
console.log('2 start');
yield func2();
console.log('3 start');
yield func3();
};
(async function(){
for await(let value of obj){
}
})();
Symbol.hasInstance


instanceof的原理
instanceof的表现:
x instanceof y: instanceof会沿着原型链往上找,看有没有y这个原型
其实这也就是 instanceof 原理是什么:
obj instanceof Ctor => 会执行Ctor[Symbol.hasInstance](obj),会执行这个方法,传obj进来;
没有这个方法才会按原型链去找
目的:避免原型重定向,只允许实例是我才行
class Fn{
constructor(){
this.x = Symbol.for('x');
}
static [Symbol.hasInstance](obj){
return obj.x && obj.x === Symbol.for('x');
}
}
let fn = new Fn();
// console.log(Reflect.ownKeys(fn));
// console.log(Object.getOwnPropertySymbols(fn));
console.log(fn instanceof Fn); // true
let arr=[10,20,30];
// arr.__proto__ = Fn.prototype;
Object.setPrototypeOf(arr,Fn.prototype);
console.log(arr instanceof Fn); // true
Symbol.toPrimitive

前言:
defineProperty和proxy,面试官可能会问你2.0和3.0的区别
toString、valueOf:对象转换为原始类型经历了哪些步骤。它会有更深层次的问法。
对象转换为字符串(数字)经历的步骤
== : 左边是对象
-
首先看对象 [Symbol.toPrimitive] 这个属性,有则按这个处理;
-
如果没有则看 valueOf,验证是否是原始类型
-
如果不是原始类型,则看toString 将其转换为字符串
-
将字符串转换为数字

let a ={
i:0,
[Symbol.toPrimitive](hint){
console.log(hint);
return ++this.i;
}
}
if(a ==1 && a==2 & a==3){
console.log('ok');
}
js面试题:a==1&&a==2&&a=3的两个思路_imoo的笔记-优快云博客_a===1&&a===2&&a===3
Symbol.toPrimitive - JavaScript | MDN
Symbol.toStringTag
-
先看[Symbol.toStringTag]
-
没有则调用内置Class
class Fn{
constructor(){
}
get[Symbol.toStringTag](){ return 'Fn' }
}
// Fn.prototype[Symbol.toStringTag]=function(){ return 'Fn' };
let fn = new Fn();
console.log(fn.toString());
console.log(Object.prototype.toString.call(fn));
let n = new Number(12);
console.log(Object.prototype.toString.call(n));
let m = true;
console.log(Object.prototype.toString.call(''));
通过Object.prototype.toString - 精确判断对象的类型 - 李小菜丶 - 博客园



1822

被折叠的 条评论
为什么被折叠?



