ES6之Symbol

ES6之Symbol

ES6(ECMAScript 2015)中,Symbol是一种新的原始数据类型,它是JavaScript语言的第七种数据类型,用于生成独一无二的值。

Symbol的主要目的是为了解决对象属性名可能产生的冲突问题,因为它确保每个由Symbol创建的值都是唯一的。

Symbol的特点包括:

  1. 唯一性:每个通过Symbol创建的值都是独一无二的,即使传入相同的描述字符串,也会得到不同的Symbol值。
  2. 不可变性:一旦创建,Symbol值就不能改变,也不能与其他数据类型进行算术或逻辑运算。
  3. 不可枚举性:Symbol作为对象的键时,不会被常规的for...in循环遍历到,也不会出现在Object.keys()Object.getOwnPropertyNames()返回的结果中,但可以通过Object.getOwnPropertySymbols()获取。
  4. 非字符串键:Symbol可以作为对象的属性键,这样的属性不能用.操作符访问,必须用方括号[]语法访问。
  5. 可选描述:创建Symbol时可以传入一个描述字符串,这个字符串主要是为了开发人员在调试时理解Symbol的用途,但不影响Symbol的唯一性。

使用场景及举例说明:

私有属性

在对象中使用Symbol作为属性名,可以创建实际上的“私有”属性,因为外界无法通过常规手段遍历或猜测这些属性的存在。

const mySymbol = Symbol();
const obj = {
  [mySymbol]: 'This is a private property',
};
console.log(obj[mySymbol]); // 输出: This is a private property
防止属性名冲突

在大型项目或库中,使用Symbol可以避免因不小心重用属性名而引起的冲突。

const idSym = Symbol('id');
const user = {
  name: 'Alice',
  [idSym]: 123,
};
// 即使有其他代码也使用"id"作为属性名,也不会与[idSym]冲突
内置Symbol用途

ES6还定义了一些内置的Symbol值,如Symbol.iterator用于实现迭代协议,让对象可迭代。

let iterable = {
  [Symbol.iterator]() {
    let step = 0;
    return {
      next() {
        if (step < 2) {
          step++;
          return { value: step, done: false };
        } else {
          return { done: true };
        }
      }
    };
  }
};

for (let num of iterable) {
  console.log(num); // 输出: 1, 2
}

通过上述例子可以看出,Symbol为JavaScript提供了更强大的对象属性管理和防止名称冲突的能力,特别适用于库开发和需要维护内部状态的场景。

详细说明

ES5困境:容易造成属性名的冲突

ES5 的对象属性名都是字符串,这容易造成属性名的冲突

比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入 Symbol 的原因。

Symbol

ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值。

它是JavaScript 语言的第七种数据类型,前六种是:

  • undefined 、
  • null 、
  • 布尔值(Boolean)、
  • 字符串(String)、
  • 数值(Number)、
  • 对象(Object)
    • 对象
    • 数组
    • 函数
    • 正则

Symbol 值通过 Symbol 函数生成。

这就是说,对象的属性名现在可以有两种类型:

  • 一种是原来就有的字符串
  • 另一种就是新增的 Symbol 类型。

凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

Symbol是一种类似于字符串的数据类型

Symbol 函数前不能使用 new 命令,否则会报错。

这是因为生成的 Symbol 是一个原始类型的值,不是对象。

也就是说,由于 Symbol值不是对象,所以不能添加属性。

基本上,它是一种类似于字符串的数据类型。

Symbol的作用

上面我们说到,Symbol不能与其他数据类型进行运算,那么新增这样一种数据类型有什么用呢?

举个例子:

//文件A.js
var a = {
	name: "夕山雨",
    getName(){
        return this.name;
    }
}
exports default a;

//文件B.js
var a = require("A.js");
a.getName = function(){
    return "xxx";
}

由于getName这个键本质上只是个字符串,而无论在哪个模块或作用域内,都可以直接引用到“getName”这个字符串,因此字符串类型的属性 很容易被意外覆盖

但是如果a中的属性是使用Symbol类型的变量作为键,那么它就无法被篡改:

//模块A.js
var s = Symbol();
var a = {
	name: "夕山雨",
	//s是个变量,因此需要用中括号包裹起来
    [s]: function(){  
        return this.name;
    }
}
exports default a;

//模块B.js
var a = require("A.js");
var s = Symbol();

a[s] = function(){
    ...  //它不会对A模块中的[s]属性造成任何影响,因为两个模块的[s]不是同一个属性
}

我们使用一个Symbol类型的变量作为对象属性的键。由于s是一个变量,而不是字符串,因此需要使用中括号括起来(否则它会被当做字符串对待)。

在模块B中我们使用同样的语句var s = Symbol();创建了一个同名变量s,“企图”通过为a[s]重新赋值覆盖a对象上原来的[s]属性,但这并不能生效,因为模块A中的变量s和模块B中的变量s是各自独立的Symbol,他们并不相等,因此无法覆盖。

根本原因在任何情况下都满足:

"getName" === "getName"
//而
Symbol() !== Symbol() //该行为类似{} !== {}

通过把对象的属性的键值设置为Symbol类型,我们有效避免了对象属性被修改,在模块化开发中,对象本身也就更安全。

扩展:JavaScript 语言的数据类型

JavaScript 语言是一种动态类型、弱类型、基于原型和多范式的编程语言。它支持以下几种主要的数据类型:

  • 原始(基本)数据类型

    • 字符串(String):用于表示文本,用单引号(’ ')或双引号(" ")包围。
    • 数字(Number):用于表示整数和浮点数,JavaScript 中没有单独的整数类型,所有数字都是浮点数。
    • 布尔值(Boolean):表示逻辑上的真(true)和假(false)。
    • undefined:表示一个变量已被声明但未被赋值时的默认值。
    • null:表示一个空对象指针,也可以视为代表“无值”的特殊值。
    • Symbol(ES6 引入):一种唯一的、不可变的数据类型,常用于对象的键,以避免属性名的冲突。
  • 对象(Object)

    • 对象字面量:由花括号{}包围的键值对集合。
    • 数组(Array):一种特殊的对象,用于存储多个值的有序集合,元素可以是任意类型。
    • 函数(Function):在 JavaScript 中,函数是一等公民,既是对象也是可以赋值给变量、作为参数传递和作为其他函数的返回值。
    • 日期(Date):用于处理日期和时间。
    • 正则表达式(RegExp):用于匹配字符串中的模式。
    • Error对象:用于表示错误信息。
    • Math对象:提供数学相关的属性和方法。
    • 更多内置对象和自定义对象:如Map、Set、WeakMap、WeakSet等(ES6引入),以及用户可以通过构造函数创建的自定义对象。
  • 特殊类型

    • BigInt(ES2020 引入):用于表示大于 2^53 - 1 的整数,解决大整数的精确表示问题。

在JavaScript中,可以使用 typeof 操作符来检测非对象类型的值,而 Object.prototype.toString.call() 方法可以更准确地检测任何类型,包括对象。

原始数据类型

Undefined: 代表未定义的值。当一个变量被声明但没有被赋予任何值时,它的值就是 undefined

let x;
console.log(x); // 输出: undefined

Null: 代表空值或者有意设置为无值的对象。它是 undefined 类型的一个特殊值。

let y = null;
console.log(y); // 输出: null

Boolean: 逻辑类型,只有两个值:truefalse

let isTrue = true;
console.log(isTrue); // 输出: true

Number: 表示整数和浮点数。JavaScript 中的数字都是64位浮点数。

let num = 42;
console.log(num); // 输出: 42

String: 用于表示文本,可以使用单引号或双引号包裹。

let text = "Hello, world!";
console.log(text); // 输出: Hello, world!

Symbol (ES6引入): 一种唯一的、不可变的数据类型,通常用作对象的唯一属性键。

let sym = Symbol();
console.log(sym); // 输出: (一个独特的Symbol值)

BigInt (ES2020引入): 用于表示任意精度的整数,超出 Number 类型的范围。

let bigInt = BigInt("9007199254740991");
console.log(bigInt); // 输出: 9007199254740991n

对象类型

Object: 包括数组、函数、日期等,是复合数据类型,可以包含多个值。

  • Array: 有序的值集合。
    let arr = [1, "text", true];
    console.log(arr); // 输出: [1, "text", true]
    
  • Function: 用于执行特定任务的可复用代码块。
    let func = function() { return "Hello"; };
    console.log(func()); // 输出: Hello
    
  • Date: 用来处理日期和时间。
    let now = new Date();
    console.log(now); // 输出: 当前日期和时间
    
  • Regular Expression: 用于文本匹配。
    let regex = /\d+/; // 匹配一个或多个数字
    console.log("123abc".match(regex)); // 输出: ["123"]
    
  • Other Objects: 自定义对象、Map、Set、WeakMap、WeakSet等。

每种数据类型都有其独特的特性和用途,理解这些数据类型是JavaScript编程的基础。

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端布道人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值