Symbol 函数

Symbol :每次返回的都是一个新的值;

1.Symbol是ES6引进的一种新的原始数据类型,表示一种独一无二的值;
2.Symbol值通过Symbol函数来生成,这就是说,现在的属性值有两种类型:
2.1 一种是原有的字符串的值;
2.2 一种是新增的Symbol函数的值;
2.3 凡是属性名属于Symbol类型,就是独一无二的值,可以保证不会和其他属性名产生冲突;
example: 
let s = Symbol() ;
typeof s ;
在这里的Symbol就是一个独一无二的值 ;
注意: 
Symbol函数不能使用new, 因为他不是一个对象,而是一个类似于字符串的值;所以,它不能添加属性;


4.Symbol可以接收一个字符串作为参数,表示对Symbol函数的描述;
这样是为了方便的在控制台里面显示,或者是转换称为字符串时方便输出;
example 1 :
var s1 = Symbol( 'foo1' ) ;
var s1 = Symbol( 'foo2' ) ;
s1 // Symbol( 'foo1' ) ;
s2 // Symbol( 'foo2' ) ;
s1.toString() // "Symbol( 'foo2' )" ;
s2.toString() // "Symbol( 'foo2' )" ;
注意: 
上面Symbol()函数生成的值,如果没有添加字符串进行区分,输出的时候就不能区分那个数值是那个数值;
example 2 :
at1: 如果Symbol的值是一个对象,就会自动调用对象的toString方法,将其转换成字符串,
 然后才生成一个Symbol值;
const obj = {
toString () {
return 'abc' ;
}
}
const sym = Symbol( obj ) ;
sym // Symbol( obj ) ;
at2: Symbol即使里面传入的参数是一致的,每个Symbol返回的都是一个不一样的值;
没有参数的情况:
var s1 = Symbol() ;
var s2 = Symbol() ;
s1 === s2 ; // false ;
有参数的情况:
var s1 = Symbol( 'foo' ) ;
var s2 = Symbol( 'foo' ) ;
s1 === s2 ; // false ;
5.Symbol值不能与其他类型值进行运算,会报错;
example: 
var sym = Symbol( 'my symbol' ) ;
'you symbol id ' + sym ;
但是,Symbol值可以显示转换策划那个字符串 ;
var sym = Symbol( 'my symbol' ) ;
String( sym ) ; // 'Symbol( my symbol )' ;
sym.toString() ; // 'Symbol( my symbol )' ;
6.Symbol也可以转为bool值,但是不能转为数值;
example: 
var sym = Symbol() ;
Boolean( sym ) ; // true
!sym ;// false
if ( sym ) {
// 程序是可以执行的。。。
}
Number( sym ) ; // type error
sym + 2 ; // type error
  7.Symbol值作为对象的属性名,可以防止我们在编写代码的时候对象的某个键值被修改 ;
  var sym = Symbol() ;
  var a = {} ;
 
  a[ symbol ] = 'hello' ;
 
  var a = {
  [ symbol ]: 'hello' ,
  }


  Object.defineProperty( a , mySymbol , { value : 'hello!' } ) ;
  上面的代码通过方括号结构和defineProperty, 将对象属性名定义为一个Symbol值 ;


  Symbol作为对象的属性名时,不能作为点运算符 ;
  因为点运算后面的总是字符串,不能取到作为Symbol所标识的值 ;
  example: 
  var mySymbol = Symbol() ;
  a.mySymbol ; // 'hello' ;
  a[mySymbol] ; // undefined
  a[ 'mySymbol' ] ; // 'hello'
  同理,在对象内部的时候,使用Symbol值作为一个属性的时候,也需要将其放置在一个方括号里面 ;


  const COLOR_GREEN = Symbol() ;
  const COLOR_RED = Symbol() ;
  function checkColor ( color ) {
  switch ( color ) {
  case COLOR_GREEN :
  return COLOR_RED ;
  case COLOR_RED :
  return COLOR_RED ;
  default throw new Error ( ' undefined color ' ) ;
  }
  }
  需要注意的是Symbol值作为属性的时候,该属性还是公有属性,而不是私有属性 ;
  8. Symbol值可以消除代码的强耦合,使代码的结构看起来更加的清晰 ;
  下面就是一段强耦合的代码:
  function getArea ( shapeType , options ) {
  switch ( shapeType ) {
  case 'Triangle' :
  area = .5 * options.width * options.height ;
  break ;
  ...more code ;
  }
  return area ;
  }
  getArea( 'Triangle' , { width: 10 , height: 10 } ) ;
 
  常用的消除字符串的方法,就是把它写成一个变量;
  var shapeType = {
  triangle : 'triangle' ,
  }
  function getArea ( area , options ) {
  var area = 0 ;
  switch ( shape ) {
  case shape === 'triangle' :
  area = options.width * options.height * .5 ;
  break ;
  }
  return area ;
  }
  getArea( shapeType.shape , { width: 10 , height: 10 } ) ;


  9.Symbol作为一个属性值,不会出现在 for...in , for...of 循环中 ,也不会被Object.keys() , 
  Object.getOwnPropertyNames() , JSON.Stringfy()返回 ;
  但是,它也不是私有属性,有一个getOwnPropertySymbols()方法,可以获取指定对象的所有Symbol属性名 ;


  getOwnPropertySymbols() 方法返回一个数组, 成员是当前对象的所有用作属性名的Symbol值 ;
  var obj = {} ;
  var a = Symbol( 'a' ) ;
  var b = Symbol( 'b' ) ;
  obj[a] = 'hello' ;
  obj[b] = 'world' ;
  var objectSymbols = Object.getOwnPropertySymbols( obj ) ;
  objectSymbols ; // Symbol( 'a' ) , Symbol( 'b' ) ;
  example: 
  getOwnPropertyNames() , for...in , getOwnPropertySymbols() 之间的对比 ;
  var obj = {} ;
  var foo = Symbol( 'foo' ) ;
  Object.defineProperty( obj , foo , { value : 'foobar' } ) ;
  for ( var i in obj ) { console.log( i ) ; } ;
  Object.getOwnPropertyNames( obj ) ; // []
  Object.getOwnPropertySymbols( obj ) ; //[Symbol('foo')]


  10.Reflect.ownKeys() , 新的API , 方法可以返回所有类型的键名,包括常规的键名和Symbol键名 ;
  let obj = {
  [Symbol('myKey')] : 1 ,
  enum: 2 ,
  nonEnum: 3 ,
  } ;
  11.Symbol.for() 
  它接收一个字符串作为参数,然后搜索有没有该参数作为名称的Symbol值,如果有就返回这个值,
  如果没有就重新新建并返回一个Symbol值;
  example: 
  var s1 = Symbol.for( 'foo' ) ;
  var s2 = Symbol.for( 'foo' ) ;
  s1 === s2 ; // true ;
  上面的代码中,虽然都是Symbol值,但都是通过Symbol.for生成的值,所以它们是相等的;
 
  12.Symbol() , Symbol.for()之间的区别 ;
  前者会登记在全局中搜索,后者则不会,不会每次新建一个Symbol值,而是去轮询是否存在,如果存在
  则返回已存在的值,不存在才会新建一个新的值 ;
  example: 
  Symbol.for( 'bar' ) === Symbol( 'bar' ) ; // true
  Symbol( 'bar' ) === Symbol( 'bar' ) ; // false
  13.Symbol.keyFor() ; 每次调用都会返回一个已经存在的Symbol值, 若是不存在则会返回undefined ;
  example: 
  var s1 = Symbol.for( 'foo' ) ;
  Symbol.keyFor( s1 ) ; // foo ;
  var s2 = Symbol( 'foo' ) ;
  Symbol.keyFor( s2 ) ; // undefined ;


  14.Symbol.for() 生成的Symbol值是在全局环境中的, 可以在不同的iframe或者server worker中
  取得同一个值 ;
  var iframe = Document.createElement( 'iframe' ) ; 
  iframe.src = String( window.location ) ;
  document.body.appendChild( iframe ) ;
  iframe.contentWindow.Symbol.for( 'foo' ) === Symbol.for( 'foo' ) ;
  上面的代码中生成的Symbol值,可以在主页面得到 ;


  15.模块的SingleTon模式 ;
  该模式调用的是一个类,但是任何时候返回的都是一个实例 ;
  对于node来说,模块可以看成是一个类 ,要保证每次执行这个模块文件,生成同一个实例 , 
  只要把这个类放置在顶级对象global中 ;
  example: 
  // mod.js
  function foo () { this.foo = 'hello' ; }
  if ( !global._foo ) { return new foo() ; }
  module.exports = global._foo ;
  var mod = require( 'mod.js' ) ;
  console.log( foo._foo ) ;
  但是这里的global._foo每次返回的都是一个实例,但是是可以修改的,为了保证这个这个变量不会失真,
  引进Symbol可以达到这样的目标 ;
 example: 
  const FOO_KEY = Symbol.for( 'foo' ) ;
  function A () { this.foo = 'hello' ; }
  if ( !global[ FOO_KEY ] ) { return new A() ; }
  module.exports = global[ FOO_KEY ] ;
  上面的代码中,可以保证键值不会被无意间被覆盖,但还是可以被改写 ;
  var a = require( './mod.js' ) ;
  global[ Symbol.for( 'foo' ) ] = 123 ;
  如果键名使用的是Symbol方法生成 ,那么外部将无法引用这个值, 当然也就无法改写 ; 

.Symbol.for() 和 Symbol() 每次都会生成新的值;
区别在于 .for 不会主动去创建一个新的Symbol值,每次都会返回同样的值,轮询是否存在,若不存在则会创建新的值;Symbol每次都会返回新的值;
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页