[译] JavaScript 中为什么会有 Symbol 类型?

简介: [译] JavaScript 中为什么会有 Symbol 类型?

声明

本文转载自:掘金-熊咆龙吟

背景

JavaScript中有两种数据类型:基本数据类型和对象(对象也包括函数),基本数据类型包括简单数据类型,比如Number(从整数到浮点数,从Infinity到NaN都属于Number类型)、Boolean、String、undefined、null(注意尽管typeof null === object,null仍然是一个基本数据类型)。

基本数据类型的值是不可以改变的,即不能更改变量的原始值,当然可以重新对变量进行赋值。例如,代码:

let x = 1;
x++;

虽然,你通过重新赋值改变了变量x的值,但是变量的原始值1仍没有被改变。

一些语言,比如C语言,有按引用传递和按值传递的概念。JavaScript也有类似的概念,它是根据传递数据的类型推断出来的。如果将值传入一个函数,则在函数中重新对它赋值不会修改它在调用位置的值。但是,如果你修改的是基本数据的值,那么修改后的值会在调用它的地方被修改。

考虑下面的例子:

function primitiveMutator(val) {
  val = val + 1;
}
let x = 1;
primitiveMutator(x);
console.log(x); //1
function objectMutator(val) {
  val.prop = val.prop + 1;
}
let obj = {prop: 1};
objectMutator(obj);
console.log(obj.prop); //2

基本数据类型(NaN除外)总是与另一个具有相同值的基本数据类型完全相等。如下:

const first = "abc" + "def";
const second = "ab" + "cd" + "ef";
console.log(first === second);  //true

然而,构造两个值相同的非基本数据类型则得到不相等的结果。我们可以看到发生了什么:

const obj1 = { name: "666"};
const obj2 = {name: "666"};
console.log(obj1 === obj2); //false

对象在JavaScript中扮演着重要的角色,几乎所有地方可以见到它们的身影。对象通常是键值对的集合,然而这种形式的最大限制是:对象的键只能是字符串,知道Symbol出现这一限制才得到解决。如果我们使用非字符串的值作为对象的键,该值会被强制转换为字符串。下面的程序中可以看到这种强制转换:

const obj = {};
obj.foo = "foo";
obj['bar'] = 'bar';
obj[2] = 2;
obj[{}] = 'someobj';
console.log(obj);

image.png

Symbol是什么?

现在既然我们已经知道了基本数据类型是什么,也就终于可以定义Symbol了。

Symbol是不能被重新创建的基本数据类型。在这种情况下,Symbol类似与对象,因为对象创建多个实例也将导致不完全相等的值。但是,Symbol也是基本数据类型,因为它不能被改变。下面是Symbol用法的一个例子:

const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); //false

当实例化一个Symbol值时,有一个可选的首选参数,你可以赋值一个字符串。此值用于调试代码,不会真正影响Symbol本身。

const s1 = Symbol('debug');
const str = 'debug';
const s2 = Symbol('xxxy');
console.log(s1 === str); //false
console.log(s1 === s2); //false
console.log(s1); //Symbol(debug)

Symbol作为对象属性

symbol还有一个重要的用法,他们可以被当作对象中的键!下面是一个在对象中使用Symbol作为键的例子:

const obj = {};
const sym = Symbol();
obj[sym] = 'foo';
obj.bar = 'bar';
console.log(obj); 
console.log(sym in obj);
console.log(obj[sym]);
console.log(Object.keys(obj));

image.png


注意,Symbol键不会被在Object.keys()返回。也是为了满足向后兼容性。旧版本的JavaScript中没有Symbol数据类型,因此不应该从旧的Object.keys()方法中被返回。

乍一看,这就像是可以用Symbol在对象上创建私有属性!许多其他编程语言可以在其类中有私有属性,而JavaScript却遗漏了这种功能,长期以来被视为其语法的一种缺点。

不幸的是,与该对象交互的代码仍然可以访问对象那些键为Symbol的属性。甚至是在调用代码自己无法访问Symbol的情况下也有可能发生。例如,Reflect.ownKeys()方法能够得到一个对象的所有键的列表,包括字符串和Symbol:

function tryToAddPrivate(obj) {
  obj[Symbol('Pseudo Private')] = 42;
}
const obj = { prop: 'hello' };
tryToAddPrivate(obj);
console.log(Reflect.ownKeys(obj));
console.log(obj[Reflect.ownKeys(obj)[1]]); // 42


防止属性名冲突

后续请查看原文。。。

相关文章
|
4天前
|
JavaScript 前端开发 开发者
如何在 JavaScript 中处理不同类型的错误?
【10月更文挑战第29天】通过对不同类型错误的准确识别和恰当处理,可以提高JavaScript程序的可靠性和稳定性,减少错误对程序运行的影响。
|
26天前
|
JavaScript 前端开发 安全
深入理解TypeScript:增强JavaScript的类型安全性
【10月更文挑战第8天】深入理解TypeScript:增强JavaScript的类型安全性
42 0
|
3月前
|
前端开发 JavaScript 搜索推荐
Next.js 适合什么类型的项目开发?
【8月更文挑战第4天】Next.js 适合什么类型的项目开发?
184 3
|
3天前
|
JavaScript 前端开发 Java
除了 JavaScript,还有哪些编程语言支持 Set 类型
【10月更文挑战第30天】这些编程语言中的 `Set` 类型虽然在语法和具体实现细节上有所不同,但都提供了类似的集合操作功能,方便开发者在不同的编程场景中处理集合相关的数据和逻辑。
|
4天前
|
存储 JavaScript 前端开发
js的基础类型和引用类型
【10月更文挑战第29天】理解 JavaScript 中的基础类型和引用类型的区别对于正确地编写代码和理解程序的行为非常重要。在实际开发中,需要根据具体的需求合理地选择和使用不同的数据类型,以避免出现一些意想不到的错误和问题。同时,在处理引用类型数据时,要特别注意对象的引用关系,避免因共享引用而导致的数据不一致等问题。
|
26天前
|
JavaScript 前端开发
JavaScript返回判断类型有哪些?
JavaScript返回判断类型有哪些?
26 0
|
3月前
|
缓存 JavaScript 前端开发
|
3月前
|
JavaScript 前端开发
在JavaScript如何确认数据的类型?
# `typeof` 与 `instanceof` 数据类型判断 `typeof` 操作符用于确定变量的基本数据类型,例如: - "string" - "number" - "boolean" - "undefined" 但对于引用类型如对象和数组,包括 `null`,它返回 "object"。 `instanceof` 用于检查对象是否为特定构造函数的实例,返回布尔值。它能准确识别数组等复杂类型,通过检查对象的原型链来确定其是否属于某个构造函数的实例。 两者结合使用可全面判断数据类型。
34 2
|
3月前
|
JavaScript 前端开发 UED
探秘 JavaScript 错误背后的真相——揭开异常类型的神秘面纱,让你的代码从此无懈可击!
【8月更文挑战第23天】本文深入探讨了JavaScript中常见的异常类型,包括`ReferenceError`(未定义的引用)、`TypeError`(类型错误)、`SyntaxError`(语法错误)、`RangeError`(范围错误)、`EvalError`(评估错误)以及`URIError`(URI错误),并通过示例展示了如何有效地诊断与处理这些异常。此外,还介绍了如何自定义错误类以适应特定场景的需求。掌握这些异常处理技巧对于构建稳定可靠的Web应用程序至关重要。
38 0
|
3月前
|
JavaScript 前端开发 安全
TypeScript:解锁JavaScript的超级英雄模式!类型系统如何化身守护神,拯救你的代码免于崩溃与混乱,戏剧性变革开发体验!
【8月更文挑战第22天】TypeScript作为JavaScript的超集,引入了强大的类型系统,提升了编程的安全性和效率。本文通过案例展示TypeScript如何增强JavaScript:1) 显式类型声明确保函数参数与返回值的准确性;2) 接口和类加强类型检查,保证对象结构符合预期;3) 泛型编程提高代码复用性和灵活性。这些特性共同推动了前端开发的标准化和规模化。
56 0