多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[toc] ### 普通符号 符号的基本概念: - 符号是ES6中新增的一种数据类型。 - 它通过使用Symbol(符号描述)来创建。符号描述为定义符号时针对该符号的描述信息,仅用于方便识别创建该符号的用途。 - 符号设计的初衷,是为了给对象设置私有属性 - 对象的私有属性是指该属性只能在对象内部使用,外部是无法调用的这些属性。 符号的特点: - 符号没有字面量。 - 使用typeof得到的类型为symbol。 - **每次调用Symbol得到的符号永远不相等,无论符号名是否相同** - 符号可以做为对象的属性名存在,这种属性称之为符号属性。 ```js const syb1 = Symbol('定义一个符号'); //创建了一个符号类型的变量syb1 const obj = { a: 1, b: 2, [syb1]: 'abc' //把syb1做为obj的一个符号属性,定义时需用[]包裹符号变量名,属性的内容可以随便定义。 //函数内部调用符号属性也需要用[符号变量名]来调用。 } ``` - 开发者可以通过一些设计,让这些属性无法通过常规方式被外界访问。 >通过创建立即执行函数,在函数内创建符号属性。可以在常规的情况下实现私有化属性。 ```js //例如:游戏角色每次攻击伤害值的取值过程 const hero = (function () { const getRandom = Symbol(); return { attack: 30, hp: 300, defence: 10, gongji() { //攻击 //伤害:攻击力*随机数(0.8~1.1) const dmg = this.attack * this[getRandom](0.8, 1.1); console.log(dmg); }, [getRandom](min, max) { //根据最小值和最大值产生一个随机数 return Math.random() * (max - min) + min; } } })() //调用该方法会产生一个getRandom符号属性,因为是立即执行函数。函数执行完毕即销毁了,所以在外部无法调用getRandom属性。 //定义一个类的时候也可以使用同样的方法,返回一个类表达式。 ``` - 符号属性是不能被枚举的,因此在for-in循环中无法读取到符号属性,Object.key方法也无法读取到符号属性。 - Object.getOwnPropertyNames 尽管可以得到所有无法枚举的属性,但是仍然无法读取到符号属性 - ES6 新增 Object.getOwnPropertySymbols 方法,可以读取符号 - 符号无法被隐式转换,因此不能被用于数学运算、字符串拼接或其他隐式转换的场景,但符号可以显式的转换为字符串,通过 String 构造函数进行转换即可,console.log 之所以可以输出符号,是它在内部进行了显式转换 >该章节重点撑握符号类型的基本特性,会使用符号属性创建一个私有属性。 ### 共享符号 当我们在某个对象或类中创建了一个符号类型的私有属性,但又想在其它文件的代码中调用该符号属性。ES6中提供了共享符号的方法。 ```js //Symbol.for("符号名/符号描述"),用来创建一个共享符号 const sy1 = Symbol.for('abc') const sy2 = Symbol.for('abc') sy1 === sy2 //返回的结果为true,说明虽然是两个变量,但其指向同一个符号,可以在不同的位置使用。 ``` 共享符号可以从外部直接调用 ```js const obj = { a:1, b:2, [Symbol.for('cc')]: 'ccc' } console.log(obj[Symbol.for('cc')]); //返回的结果为ccc,即可以用这种方法在外部调用共享符号属性。 ``` ### 知名(公共、具名)符号 - 知名符号是一些具有特殊含义的共享符号,通过Symbol的静态属性得到。 - ES6延续了ES5的思想:减少魔法(指不清楚实现原理的一些方法),暴露内部实现。因此,ES6使用知名符号暴露了某些场景的内部实现。 1. Symbol.hasInstance 该符号用于定义构造函数的静态成员,它将影响 instanceof 的判定 ```js obj instanceof A //该符号等效于 A[Symbol.hasInstance](obj) // Function.prototype[Symbol.hasInstance] ``` 2. [扩展] Symbol.isConcatSpreadable 该知名符号会影响数组的 concat 方法,只有true和false两个参数。 当设置为true时,concat方法会将拼接的数组分割成每一个独立的值,追加到对应的数组中。 当设置为false时,concat方法会将拼接的数组直接追加到对应的数组中。 ```js let arr = [0, 1] let arr1 = [2, 3] arr1[Symbol.isConcatSpreadable] = true; //拼接进行分割 let newarr = arr.concat(arr1); //newarr的值为[0,1,2,3] arr1[Symbol.isConcatSpreadable] = false; //拼接不进行分割 let newarr = arr.concat(arr1); //newarr的值为[0,1,[2,3]] ``` 3. [扩展] Symbol.toPrimitive 该知名符号会影响类型转换的结果 ```js const obj = { a: 1, b: 2 } //正常情况下obj在进行基本运算时会启动隐式类型转换,如obj+123,结果为:[object object]123,obj最终会被使用toString方法转为字符串。 obj[Symbol.toPrimitive] = function(type){ return 2 } //当使用obj的Symbol.toPrimitive知名符号,可以定义一个函数。该函数的返回值就是隐式类型转换后的值。 const res = obj+123; //例如使用了上面的知名符号后,obj隐式类型转换返回的结果变成2了,所以res的结果为125 //该知名符号定义的函数会返回一个type参数,该参数用来表示当前是在会哪种方式进行转换,返回值有default、number、String。 ``` 4. [扩展] Symbol.toStringTag 该知名符号会影响 Object.prototype.toString 的返回值。 如果把该符号写入一个类或对象中,指定一个名称,那么该名称会替换toString方法返回的第二位的内容 例如:一个对象toString后返回[object Object],说明这是一个对象。若在该对象中加入[Symbol.toStringTag] = 'Student'。那么再次执行toString后会返回[object Student]。