JavaScript第七种数据类型Symbol的用法详解
发布时间:2025-05-23 14:35:15 发布人:远客网络
一、JavaScript第七种数据类型Symbol的用法详解
Symbol是ES6中引入的一种新的基本数据类型,用于表示一个独一无二的值。它是JavaScript中的第七种数据类型,与undefined、null、Number(数值)、String(字符串)、Boolean(布尔值)、Object(对象)并列。Symbol的特点包括:Symbol的值是唯一的,用来解决命名冲突问题;Symbol值不能与其他数据进行运算;Symbol定义的对象属性不能使用for...in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。
基本用法示例:let a= Symbol("末晨曦吖");console.log(a);// Symbol(末晨曦吖)console.log(typeof a);//symbollet b= Symbol("末晨曦吖");console.log(a=== b);//false
相同参数下Symbol()返回的值不相等的原因在于,使用Symbol()创建一个Symbol类型的值并赋值给a变量后,你就得到了一个在内存中独一无二的值。除非通过变量a,任何人在任何作用域内都无法重新创建出这个值。尽管a和b都是使用Symbol()创建出来的,但是它们在内存中看起来却是这样的:实际上,a变量拿到了内存中某块内存的唯一引用(这里所说的引用,其实就是该内存的地址)。如果不借助a变量,你不可能再得到这个地址。因此:a!== b;//a和b持有的是两块内存的引用const c= a;//手动把a里保存的地址保存在c变量中a=== c;//c和a现在指向同一块内存,因为它们保存了同样的地址。
这种行为看似难以理解,但其实它与对象遵循相同的规则。如:let a={};let b={}; a!== b;//a和b各自被分配了不同的内存,因此它们保存了不同的地址借助变量a,变量c拿到了a指向的那个对象的地址,因此两者相等let c= a;a=== c;
但是对于同为基本数据类型的字符串来说,它不遵循类似的规则。比如:let a="123";let b="123"; a=== b;//返回true。两者在常量区引用同一个字符串。我们首先通过变量a在内存中创建了字符串123,然后在不借助变量a的情况下,又通过var b= 123拿到了对123这个字符串的引用,两者指向内存中的同一块内存地址。因此我们说,a无法确保别的变量无法拿到它保存的地址(前提是不通过a)。但是对于var a= Symbol()这样的语句,a变量内保存的值是唯一的,因为除了借助a变量,你永远无法得到a中保存的值。这也是Symbol的本质。
作为属性名的Symbol的用法示例:let mySymbol= Symbol();let a={};a[mySymbol]='Hello!';let a={ [mySymbol]:'Hello!'};let a={};Object.defineProperty(a, mySymbol,{ value:'Hello!'});以上写法都得到同样结果:a[mySymbol]//"Hello!"注意,Symbol值作为对象属性名时,不能用点运算符。let a={};let name= Symbol();a.name='lili';a[name]='lucy';console.log(a.name,a[name]);//lili,lucySymbol值作为属性名时,该属性还是公开属性,不是私有属性。
Symbol中的方法:1、Symbol.for(),我们知道Symbol()创建的两个变量永远不会是相同的。那么如果我们需要重新使用同一个Symbol怎么办,总不能需要挨个去进行比较吧。还好,es6为我们提供了Symbol.for()方法。参数是symbol类型的描述信息,不同于Symbol(),这个而参数只能是字符串或者是undefined,若已经创建了则返回这个symbol,否则就进行创建并将这个新的symbol返回,代码如下:let name= Symbol.for("末晨曦");let name1= Symbol.for("末晨曦");console.log(name=== name1);// true
请注意,我们在使用创建描述信息为末晨曦的变量的时候,使用的是for,而不是Symbol(),倘若使用Symbol()进行首次创建,for会再次创建一次,二者不会相等,代码如下:let name= Symbol("末晨曦");let name1= Symbol.for("末晨曦");console.log(name=== name1);// false
原因在于Symbol.for()会有一个登记机制,使用for只会对通过for创建的symbol进行检查,不会对Symbol()创建的进行检查。2、Symbol.keyFor(),这个方法参数是一个通过Symbol.for()创建的symbol类型变量,返回这个symbol变量的描述信息。let name= Symbol.for("末晨曦");console.log(Symbol.keyFor(name));//"末晨曦"let name1= Symbol("末晨曦");console.log(Symbol.keyFor(name1));// undefined不能查找Symbol()创建的变量。
二、JavaScript 为什么要有 Symbol 类型
1、JavaScript引入 Symbol类型主要是为了在对象属性管理方面提供独特优势,尤其是在避免命名冲突和模拟私有属性方面。具体来说:
2、与 Proxy结合实现复杂对象操作拦截:
3、综上所述,JavaScript引入 Symbol类型是为了在对象属性管理方面提供更强的灵活性、隐私保护和操作控制能力。尽管在序列化等方面存在一些限制,但 Symbol仍然是一个有价值的新增特性。
三、ArcGIS API for JavaScript根据点坐标画圆
1.给出一个点的坐标和半径。要求以这个点为圆心,以半径绘出一个圆圈。并且对特定的2个图层进行查询,把落入这个圆圈的空间对象标记出来,并且可以点击产生infowindow
a.先通过GeometryService(几何服务)绘制出一个buffer的圆。
b.把这个buffer,也就是一个graphic放入到 map的graphics中显示
c.然后定义一个query,并且对此 query的geometry指定为这个 buffer.这样所有的查询结果就会是:查询出的空间对象落入这个buffer中。
d.定义一个featureLayer,对这个featureLayer和这个query进行 selectFeatures方法调用。
e.对查询后调用的函数中,进行每个graphic设置 infowindow和加入 map的graphic。
/*以一个map上标记的点为圆心,以指定的半径标记一个圆圈
sky.gis.Context.prototype.doBuffer= function(point,buffer_radius,lineColor,lineWidth,fillColor,infoWidth,infoHeight,url)
var infoTemplate= new esri.InfoTemplate();
infoTemplate.setContent("<iframe src=${iframe_url} height="+infoHeight+" width="+infoWidth+">");
_map.infoWindow.resize(infoWidth, infoHeight);
var bufferParams= new esri.tasks.BufferParameters();
bufferParams.geometries= [ point ];
bufferParams.distances= [ buffer_radius ];
bufferParams.outSpatialReference= self._map.spatialReference;
// bufferParams.unit= esri.tasks.GeometryService.esriDecimalDegrees;
bufferParams.unit= esri.tasks.GeometryService.esriMeters;
self.gsvc.buffer(bufferParams,function showBuffer(buffers)
dojo.forEach(buffers, function(b){
//根据指定的颜色和线色进行填充。画出一个圆
var sfs= new esri.symbol.SimpleFillSymbol(esri.symbol.SimpleFillSymbol.STYLE_SOLID,
new esri.symbol.SimpleLineSymbol(esri.symbol.SimpleLineSymbol.STYLE_SOLID,lineColor, lineWidth),
var graphic= new esri.Graphic(bufferGeometry, sfs);
if(graphic.attributes== null)
graphic.attributes= new Object();
graphic.attributes.iframe_url= new Object();
console.debug(graphic.attributes.iframe_url);
graphic.attributes.iframe_url= url;
// graphic.setInfoTemplate(infoTemplate);//可以指定这个圆圈的infowindow
self._map.graphics.add(graphic);//把这个圆圈显示出来
var query= new esri.tasks.Query();
query.geometry= bufferGeometry;//指定查询出的空间对象一定要落在这个圆圈内
//查询落入buffer层的门板信息点
self._bufferFeatureLayer= new esri.layers.FeatureLayer(infoLayerURL,
mode: esri.layers.FeatureLayer.MODE_SELECTION,
self._bufferFeatureLayer.selectFeatures(query, esri.layers.FeatureLayer.SELECTION_NEW, function(results){
dojo.forEach(results,function(result){//对查询出的结果进行遍历。把graphic放入map的graphics中
symbol= new esri.symbol.PictureMarkerSymbol('./imgs/infos.jpeg', 32, 32);
graphic.setInfoTemplate(infoTemplate);
self._map.graphics.add(graphic);
//查询落入buffer层的摄像头信息点
self._bufferFeatureLayer= new esri.layers.FeatureLayer(cameraLayerURL,
mode: esri.layers.FeatureLayer.MODE_SELECTION,
self._bufferFeatureLayer.selectFeatures(query, esri.layers.FeatureLayer.SELECTION_NEW, function(results){
for( var i= 0; i< results.length; i++){
symbol= new esri.symbol.PictureMarkerSymbol('./imgs/camera.gif', 32, 32);
graphic.setInfoTemplate(infoTemplate);
self._map.graphics.add(graphic);