Symbol是ES6新增的原始类型数据,引入的初衷是为了对象可以有永不重复的属性名。

所以属性名可以是字符串外,还可以是Symbol值;

const a = Symbol("a");
const obj = {};
obj[a] = "Hello"

1.用法:

const a = Symbol([descName])

1) 直接调用方法,因为是原始值,切忌使用new,因为Symbol不是一个构造函数。

2) Symbol不会进行自动类型转换。所以不能参与任何运算

var a = Symbol('a');
a + 'str'; // Uncaught Error: Cannot convert a Symbol value to a string

3) Symbol类型的值可以手动转为String和Boolean;不能转为Number;

4) Symbol接受一个字符串类型的值作为Symbol值描述。可以通过原型链上的Symbol.prototype.description访问

const a = Symbol("a");
a.description; // "a"

描述只是为了调试区分,Symbol每次运行都生成一个新的值,即使描述一样,值也不一样。

Symbol('foo') === Symbol('foo'); // false

如果参数是对象,则会自动将对象转为字符串类型。

var a = Symbol({}); // Symbol([object Object])

源码模拟:

/**
* Symbol的原则:
* 1. 不能使用new命令,否则抛出TypeError异常
* 2. 描述参数如果是undefined,则属性description为undefined
* 3. 如果描述参数是其他类型的值,直接toString转为字符串
* 4. 返回一个唯一值。可以作为对象的属性值。
* 5. 有两个实例方法,位于prototype对象上:
* 1)for()用于复用Symbol值;
* 2)keyFor(symbol)用于查找其描述字符串
*
*/
(function() {
var root = this;
// 4. 生成唯一的值;该方法不能位于Symbol方法内部,否则每次调用都是一个新的generateName,postfix永远为0;
// 闭包;保证唯一值的纯净
var generateName = (function() {
let postfix = 0;
return function(desString) {
return `@@${desString}_${postfix++}`
}
})();
let = SymbolPolyfill = function Symbol(description) {
// 1. 不能使用new命令
if(this instanceof Symbol) {
throw new TypeError("Symbol is not a constructor");
}
// 2. 处理参数
let desString = description === undefined ? undefined : String(description);
// 3. 因为含有description属性,所以返回一个对象,每个对象都不同
let symbol = Object.create({
// 作为对象的属性时,默认调用toString方法
toString() {
return this.__Name__;
},
valueOf() {
return this;
}
});
Object.defineProperties(symbol, {
'__Name__': {
value: generateName(desString),
writable: false,
configurable: false,
enumerable: false
},
'__description__': {
value: desString,
writable: false,
configurable: false,
enumerable: false
}
})
return symbol;
}
let forMap = {}; //存储注册的值
// 5. 其原型对象上有两个方法
Object.defineProperties(Symbol.prototype, {
'for': {
value: function(desString) {
if(!forMap[desString]) {
forMap[desString] = SymbolPolyfill(desString);
}
return forMap[desString];
},
writable: true,
configurable: false,
enumerable: true
},
'keyFor': {
value: function(symbol) {
for(let key in forMap) {
if(forMap[key] === symbol) {
return key;
}
}
},
writable: true,
configurable: false,
enumerable: true
}
})
root.SymbolPolyfill = SymbolPolyfill;
})(); // 测试
let s1 = SymbolPolyfill('1');
let s2 = SymbolPolyfill('1');
console.log(s1.toString());
console.log(s2.__description__);

2. Symbol注册

Symbol.for(description)用于Symbol值全局环境(可跨iframe和service worker)注册;一部分功能和Symbol()重合;

Symbol.keyFor(变量名)用于获取已经注册过的变量的描述;

const sym = Symbol.for("foo"); // 如果未注册过就注册后返回;注册过就直接返回
Symbol.keyFor(sym); // "foo"
Symbol.for("foo") === Symbol.for("foo"); // true

3. 单例模式导出内容作为全局变量

nodeJS的通过require('./mod.js)引入下面的文件。

require的机制是,先判断是否有缓存结果,因为Node会将脚本的执行结果缓存。

如果有缓存,直接取出结果。如果没有,去新建实例。

// mod.js
const FOO_KEY = Symbol.for('foo');
// 不能用Symbol(),因为如果用户清空缓存,每次结果都不一样,global也无意义
function A() {
this.foo = 'hello';
}
// 将结果挂在全局对象上,避免多次实例化,因为用户可能清空缓存
if (!global[FOO_KEY]) {
global[FOO_KEY] = new A();
}
module.exports = global[FOO_KEY]; // 避免外部修改全局变量

4.内置函数(11个)

js提供了很多原生方法。这些原生方法的调用实际是调用的Symbol函数。

可以说,如果我们只要手动给原本不支持的对象添加这些Symbol函数,就可以让它支持这些原生方法。

Symbol.变量名 = Symbol(Symbol.变量名)

1. 构造函数内置函数

1)[Symbol.hasInstance]()---实例方法

对应 instanceof 方法

obj instanceof Fun
// 实际是直接调用
Fun[Symbol.hasInstance](obj)

2. 数组内置函数

1)[Symbol.isConcatSreadable]---属性

对应数组的concat函数; String类型也适用该方法。

var arr1 =[1,2];var arr2= [3,4];
arr1.concat(arr2); // [1,2,3,4]
// 实际是参数内部的属性Symbol.isConcatSpreadable === undefined
// 当这个属性为undefined/true时,都会展开
// 如果是false,不展开
arr2[Symbol.isConcatSpreadable] = false;
arr1.concat(arr2); // [1,2,[3,4]]

2)static get [Symbol.species]() --- 静态属性

对应数组的可以获得衍生数组的方法,如map, filter等方法。

这些方法的本质是,重新调用构造函数的[Symbol.species]属性返回的新的构造函数。

默认返回构造函数本身。

class MyArray extends Array{};
var a = new MyArray([1,2]);
var b = a.map(i => i*2);// 默认使用MyArray的构造函数
b instanceof MyArray; // true
b instanceof Array; // true
/**********如果修改静态属性*******/
class MyArray extends Array{
static get [Symbol.species]() { return Array } // 修改衍生对象的构造函数
};
var a = new MyArray([1,2]);
var b = a.map(i => i*2);
b instanceof MyArray; // false
b instanceof Array; // true

3. 字符串对象的内置函数

1)[Symbol.match]() -- 实例方法

str.match(string/RegExp) //返回匹配的数组,数组有index和input两个属性
// 实际对应
str[Symbol.match](str)/RegExp[Symbol.match](str)

2)[Symbol.search]() ---实例方法

str.search(string/RegExp) //返回匹配的位置
// 实际对应
str[Symbol.search](str)/RegExp[Symbol.search](str)

3)[Symbol.replace]() ---实例方法

String.prototype.replace(searchValue, replaceValue)
// 等同于
searchValue[Symbol.replace](this, replaceValue)

4)[Symbol.split]() --- 实例方法

String.prototype.split(separator, limit)
// 等同于
separator[Symbol.split](this, limit)

4. 可遍历对象

所有可遍历对象进行遍历时都是调用的[Symbol.iterator]() ;

[Symbol.iterator]() --- 实例Generator方法

class Collection {
*[Symbol.iterator]() {
let i = 0;
while(this[i] !== undefined) {
yield this[i];
++i;
}
}
}

5. 数据类型转换

js在运行中,经常会通过运算符,将数据自动转为原始数据

[Symbol.toPrimitive]()

var obj = {};
5 + obj; //"5[object Object]"
// 实际调用的是
obj[Symbol.toPrimitive](根据运算符决定的类型);

6. 对象内置函数

1)[Symbol.toStringTag] --- 属性

对应Object.prototype.toString()方法

var a = {};
var type = a.toString();
// 相当于
var type = a[Symbol.toStringTag];

2)[Symbol.unscopables] ---属性

指定不能使用With的属性

// 有 unscopables 时
class MyClass {
foo() { return 1; }
get [Symbol.unscopables]() {
return { foo: true }; // 设置为true表示不能被with访问,再向上级作用域查找
}
} var foo = function () { return 2; }; with (MyClass.prototype) {
foo(); //
}

ES6-12.Symbol的更多相关文章

  1. 《ES6标准入门》(阮一峰)--12.Symbol

    1.概述 ES5 的对象属性名都是字符串,这容易造成属性名的冲突.比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突.如果有一种 ...

  2. ES6之Symbol

    ES6中Symbol是为了防止属性名冲突而引入的,是独一无二的.Symbol值是通过Symbol函数生成.Symbol值不能与其他类型的值运算否则会报错且Symbol的值可以转换为字符串或者是布尔值但 ...

  3. ES6 之 Symbol

    1. 基本用法 Symbol 是ES6引入的一种新的原始数据类型,表示独一无二的值. 前六种基础数据类型是 undefined null Boolean String Number Object Sy ...

  4. ES6(六) --- Symbol

    概述: ES5 中属性名都是字符串,这容易就造成命名的冲突,特别是在混入模式(mixin模式)下.为解决这个问题ES6 引入了Symbol, Symbol是一种新的基本数据类型,表示独一无二的值!   ...

  5. Es6(Symbol,set,map,filter)

    首先再讲这几个新东西之前,先说一个Es6中新出的扩展运算符(...) 1.展开运算符,就是把东西展开,可以用在array和object上 比如: let a=[,] let b=[,...a,]//[ ...

  6. JS的ES6的Symbol

    一.Symbol 1.什么是Symbol: Symbol是ES6新添加的原始类型(ES5已有原始数据类型:String,Number,boolean,function,undefined,object ...

  7. [ES6] 12. Shorthand Properties in ES6

    Where destructuring in ES6 allows you to easily get properties out of an object, this shorthand prop ...

  8. ES6的Symbol

    let s = Symbol(); alert(typeof(s)); // Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比 ...

  9. es6(9)--Symbol

    //Symbol生成一个独一无二的值,生成的值不会相等 { //声明1 let a1=Symbol(); let a2=Symbol(); console.log(a1===a2);//false / ...

  10. ES6 中 Symbol.split的用法

    class Split1 { constructor(value) { this.value = value; } [Symbol.split](string) { var index = strin ...

随机推荐

  1. python 手机App数据抓取实战一

    前言 当前手机使用成为互联网主流,每天手机App产生大量数据,学习爬虫的人也不能只会爬取网页数据,我们需要学习如何从手机 APP 中获取数据,本文就以豆果美食为例,讲诉爬取手机App的流程 环境准备 ...

  2. docker&git&gitlab-安装/部署/新建

    --安装gcc yum -y install gcc --安装g++ yum -y install gcc-c++ --安装编译所需的包 yum -y install curl-devel expat ...

  3. SAS学习笔记46 宏变量的可使用范围

    全局宏变量 在宏程序内部,除了使用%GLOBAL语句创建.在某些情况下,还可以直接使用DATA步中的CALL SYMPUT创建. 在一个宏程序中,在包含CALL SYMPUT的DATA步程序之前,如果 ...

  4. c#入门学习笔记

    Hello World //打印语句 Console.WriteLine("Hello World"); //暂停 Console.ReadKey(); 数据类型 1.值类型 by ...

  5. .net Core CLR

    .net Core CLR是开源的.大部分文件是C++写成.这样他就可以编译后再不同的平台运行. https://github.com/dotnet/coreclr

  6. Asp.Net Core 存储Cookie 的问题

    Asp.Net Core 2.1生成的项目模板默认实现了<欧洲常规数据保护法规 (GDPR)>支持.这就使得我们的程序要想成功的存储除了用户身份以外的cookie通常是需要用户同意的. 3 ...

  7. matlab cell

    cell元包是matlab中提供的一种数据类型,功能强大. 关于cell的创建: 1.跟一般创建举证一样,直接使用C = {A B D E}这种形式,不过这里把"[]"改成了}&q ...

  8. 客户端相关知识学习(十一)之Android H5交互Webview实现localStorage数据存储

    前言 最近有一个需求是和在app中前端本地存储相关的,所以恶补了一下相关知识 webView开启支持H5 LocalStorage存储 有些时候我们发现写的本地存储没有起作用,那是因为默认WebVie ...

  9. ARM微控制器与嵌入式系统

    个牛人在ARM实现嵌入式系统的过程 第一章  概览 1.1课程概览 认识ARM嵌入式系统(什么是ARM?什么是嵌入式系统?) 备战智能车 在科技活动中玩起来 积累计算机.电路基础知识 1.2如何学好嵌 ...

  10. 最详细的原生js实现ajax的封装

    1. ajax的介绍 1.1 含义 ajax 的全称是Asynchronous JavaScript and XML 简单理解下:ajax就是异步的js和服务端的数据 1.2 组成 异步的js:事件, ...