웹 프론트엔드 JS 튜토리얼 深入了解JavaScript中的Symbol的使用方法_基础知识

深入了解JavaScript中的Symbol的使用方法_基础知识

May 16, 2016 pm 03:48 PM

Symbol 是什么?

Symbols 不是图标,也不是指在代码中可以使用小图片:

2015728114935470.jpg (291×49)

也不是指代其他一些东西的语法。那么,Symbol 到究竟是什么呢?
七种数据类型

JavaScript 在 1997 年被标准化时,就有 6 种数据类型,直到 ES6 出现之前,程序中的变量一定是以下 6 种数据类型之一:

    Undefined
    Null
    Boolean
    Number
    String
    Object

每种数据类型都是一系列值的组合,前面 5 种数据类型值的数量都是有限的。Boolean 类型只有两个值:true 和 false,为 Boolean 类型的变量赋值时,并不会产生新的值(共享了true 和 false 这两个值)。对于 Number 和 String 来说,它们的值则多得多了,标准的说法是有 18,437,736,874,454,810,627 个 Number 类型的值(包括 NAN)。String 类型的个数就难以统计了,我原以为是 (2144,115,188,075,855,872 ? 1) ÷ 65,535…不过也许我算错了。

对象值的个数是无限的,每个对象都是独一无二的,每次打开一个网页,都创建了一系列的对象。

ES6 中的 Symbol 也是一种数据类型,但是不是字符串,也不是对象,而是一种新的数据类型:第七种数据类型。

下面我们来看一个场景,也许 Symbol 能派上用场。
一个布尔值引出的问题

有时,把一些属于其他对象的数据暂存在另一个对象中是非常方便的。例如,假设你正在编写一个 JS 库,使用 CSS 中的 transition 来让一个 DOM 元素在屏幕上飞奔,你已经知道不能同时将多个 transition 应用在同一个 div 上,否则将使得动画非常不美观,你也确实有办法来解决这个问题,但是首先你需要知道该 div 是否已经在移动中。

怎么解决这个问题呢?

其中一个方法是使用浏览器提供的 API 来探测元素是否处于动画状态,但杀鸡焉用牛刀,在将元素设置为移动时,你的库就知道了该元素正在移动。

你真正需要的是一种机制来跟踪哪些元素正在移动,你可以将正在移动的元素保存在一个数组中,每次要为一个元素设置动画时,首先检查一下这个元素是否已经在这个列表中。

啊哈,但是如果你的数组非常庞大,即便是这样的线性搜索也会产生性能问题。

那么,你真正想做的就是直接在元素上设置一个标志:

if (element.isMoving) {
 smoothAnimations(element);
}
element.isMoving = true;

 
if (element.isMoving) {
 smoothAnimations(element);
}
element.isMoving = true;

로그인 후 복사

这也有一些潜在的问题,不得不承认这样一个事实:还有其他代码也可能操作该 ODM 元素。

  • 在其他代码中,你创建的属性会被 for-in 或 Object.keys() 枚举出来;
  • 在其他一些库中也许已经使用了同样的方式(在元素上设置了相同的属性),那么这将和你的代码发生冲突,产生不可预计的结果;
  • 其他一些库可能在将来会使用同样的方式,这也会与你的代码发生冲突;
  • 标准委员会可能会为每个元素添加一个 .isMoving() 原生方法,那么你的代码就彻底不能工作了。

当然,对于最后三个问题,你可以选择一个无意义的不会有人会使用到的字符串:

if (element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__) {
 smoothAnimations(element);
}
element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__ = true;
 
if (element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__) {
 smoothAnimations(element);
}
element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__ = true;

로그인 후 복사

这似乎太不靠谱了,看了让人眼睛痛。

你还可以用加密算法来生成一个几乎唯一的字符串:

// get 1024 Unicode characters of gibberish
var isMoving = SecureRandom.generateName();

...

if (element[isMoving]) {
 smoothAnimations(element);
}
element[isMoving] = true;
 
// get 1024 Unicode characters of gibberish
var isMoving = SecureRandom.generateName();
 
...
 
if (element[isMoving]) {
 smoothAnimations(element);
}
element[isMoving] = true;

로그인 후 복사

object[name] 语法允许我们将任何字符串作为属性名,代码能正常工作,冲突几乎是不可能了,代码看起来也美观多了。

但是,这回导致糟糕的调试体验,每次使用 console.log() 打印出包含该属性的元素时,你回看到一个庞大的垃圾字符串,并且如果还不止一个这样的属性呢?每次刷新后属性名都发生了变化,怎么样使这些属性看起来更加直观呢?

为什么这么难?我们只是为了保存一个小小的标志位。
用 Symbol 来解决问题

Symbol 值可以由程序创建,并可以作为属性名,而且不用担心属性名冲突。

var mySymbol = Symbol();

var mySymbol = Symbol();

로그인 후 복사

调用 Symbol() 方法将创建一个新的 Symbol 类型的值,并且该值不与其它任何值相等。

与数字和字符串一样,Symbol 类型的值也可以作为对象的属性名,正是由于它不与任何其它值相等,对应的属性也不会发生冲突:

obj[mySymbol] = "ok!"; // guaranteed not to collide
console.log(obj[mySymbol]); // ok!
 
obj[mySymbol] = "ok!"; // guaranteed not to collide
console.log(obj[mySymbol]); // ok!
로그인 후 복사

下面是使用 Symbol 来解决上面的问题:

// create a unique symbol
var isMoving = Symbol("isMoving");

...

if (element[isMoving]) {
 smoothAnimations(element);
}
element[isMoving] = true;
 
// create a unique symbol
var isMoving = Symbol("isMoving");
 
...
 
if (element[isMoving]) {
 smoothAnimations(element);
}
element[isMoving] = true;

로그인 후 복사

上面代码需要注意几点:

  • 方法 Symbol("isMoving") 中的 "isMoving" 字符串被称为 Symbol 的描述信息,这对调试非常有帮助。可以通过 console.log(isMoving) 打印出来,或通过 isMoving.toString() 将 isMoving 转换为字符串时,或在一些错误信息中显示出来。
  • element[isMoving] 访问的是 symbol-keyed 属性,除了属性名是 Symbol 类型的值之外,与其它属性都一样。
  • 和数组一样,symbol-keyed 属性不能通过 . 操作符来访问,必须使用方括号的方式。
  • 操作 symbol-keyed 属性也非常方便,通过上面代码我们已经知道如何获取和设置 element[isMoving] 的值,我们还可以这样使用:if (isMoving in element) 或 delete element[isMoving]。
  • 另一方面,只有在 isMoving 的作用域范围内才可以使用上述代码,这可以实现弱封装机制:在一个模块内创建一些 Symbol,只有在该模块内部的对象才能使用,而不用担心与其它模块的代码发生冲突。

由于 Symbol 的设计初衷是为了避免冲突,当遍历 JavaScript 对象时,并不会枚举到以 Symbol 作为建的属性,比如,for-in 循环只会遍历到以字符串作为键的属性,Object.keys(obj)和 Object.getOwnPropertyNames(obj) 也一样,但这并不意味着 Symbol 为键的属性是不可枚举的:使用 Object.getOwnPropertySymbols(obj) 这个新方法可以枚举出来,还有 Reflect.ownKeys(obj) 这个新方法可以返回对象中所有字符串和 Symbol 键。(我将在后面的文章中详细介绍 Reflect 这个新特性。)

库和框架的设计者将会发现很多 Symbol 的用途,稍后我们将看到,JavaScript 语言本身也对其有广泛的应用。
Symbol 究竟是什么呢

> typeof Symbol()
"symbol"
 
> typeof Symbol()
"symbol"

로그인 후 복사

Symbol 是完全不一样的东西。一旦创建后就不可更改,不能对它们设置属性(如果在严格模式下尝试这样做,你将得到一个 TypeError)。它们可以作为属性名,这时它们和字符串的属性名没有什么区别。

另一方面,每个 Symbol 都是独一无二的,不与其它 Symbol 重复(即便是使用相同的 Symbol 描述创建),创建一个 Symbol 就跟创建一个对象一样方便。

ES6 中的 Symbol 与传统语言(如 Lisp 和 Ruby)中的 Symbol 中的类似,但并不是完全照搬到 JavaScript 中。在 Lisp 中,所有标识符都是 Symbol;在 JavaScript 中,标识符和大多数属性仍然是字符串,Symbol 只是提供了一个额外的选择。

值得注意的是:与其它类型不同的是,Symbol 不能自动被转换为字符串,当尝试将一个 Symbol 强制转换为字符串时,将返回一个 TypeError。

> var sym = Symbol("<3");
> "your symbol is " + sym
// TypeError: can't convert symbol to string
> `your symbol is ${sym}`
// TypeError: can't convert symbol to string
 
> var sym = Symbol("<3");
> "your symbol is " + sym
// TypeError: can't convert symbol to string
> `your symbol is ${sym}`
// TypeError: can't convert symbol to string

로그인 후 복사

应该避免这样的强制转换,应该使用 String(sym) 或 sym.toString() 来转换。
获取 Symbol 的三种方法

  1.     Symbol() 每次调用时都返回一个唯一的 Symbol。
  2.     Symbol.for(string) 从 Symbol 注册表中返回相应的 Symbol,与上个方法不同的是,Symbol 注册表中的 Symbol 是共享的。也就是说,如果你调用 Symbol.for("cat") 三次,都将返回相同的 Symbol。当不同页面或同一页面不同模块需要共享 Symbol 时,注册表就非常有用。
  3.     Symbol.iterator 返回语言预定义的一些 Symbol,每个都有其特殊的用途。

如果你仍不确定 Symbol 是否有用,那么接下来的内容将非常有趣,因为我将为你演示 Symbol 的实际应用。
Symbol 在 ES6 规范中的应用

我们已经知道可以使用 Symbol 来避免代码冲突。之前在介绍 iterator 时,我们还解析了 for (var item of myArray) 内部是以调用 myArray[Symbol.iterator]() 开始的,当时我提到这个方法可以使用 myArray.iterator() 来代替,但是使用 Symbol 的后向兼容性更好。

在 ES6 中还有一些地方使用到了 Symbol。(这些特性还没有在 FireFox 中实现。)

  •     使 instanceof 可扩展。在 ES6 中,object instanceof constructor 表达式被标准化为构造函数的一个方法:constructor[Symbol.hasInstance](object),这意味着它是可扩展的。
  •     消除新特性和旧代码之间的冲突。
  •     支持新类型的字符串匹配。在 ES5 中,调用 str.match(myObject) 时,首先会尝试将 myObject 转换为 RegExp 对象。在 ES6 中,首先将检查 myObject 中是否有 myObject[Symbol.match](str) 方法,在所有正则表达式工作的地方都可以提供一个自定义的字符串解析方法。

这些用途还比较窄,但仅仅通过我文章中的代码很难看到这些新特性产生的重大影响。JavaScript 的 Symbol 是 PHP 和 Python 中 __doubleUnderscores 的改进版本,标准组织将使用它来为语言添加新特性,而不会对已有代码产生影响。

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Demystifying JavaScript : 그것이하는 일과 중요한 이유 Demystifying JavaScript : 그것이하는 일과 중요한 이유 Apr 09, 2025 am 12:07 AM

JavaScript는 현대 웹 개발의 초석이며 주요 기능에는 이벤트 중심 프로그래밍, 동적 컨텐츠 생성 및 비동기 프로그래밍이 포함됩니다. 1) 이벤트 중심 프로그래밍을 사용하면 사용자 작업에 따라 웹 페이지가 동적으로 변경 될 수 있습니다. 2) 동적 컨텐츠 생성을 사용하면 조건에 따라 페이지 컨텐츠를 조정할 수 있습니다. 3) 비동기 프로그래밍은 사용자 인터페이스가 차단되지 않도록합니다. JavaScript는 웹 상호 작용, 단일 페이지 응용 프로그램 및 서버 측 개발에 널리 사용되며 사용자 경험 및 크로스 플랫폼 개발의 유연성을 크게 향상시킵니다.

JavaScript의 진화 : 현재 동향과 미래 전망 JavaScript의 진화 : 현재 동향과 미래 전망 Apr 10, 2025 am 09:33 AM

JavaScript의 최신 트렌드에는 Typescript의 Rise, 현대 프레임 워크 및 라이브러리의 인기 및 WebAssembly의 적용이 포함됩니다. 향후 전망은보다 강력한 유형 시스템, 서버 측 JavaScript 개발, 인공 지능 및 기계 학습의 확장, IoT 및 Edge 컴퓨팅의 잠재력을 포함합니다.

JavaScript 엔진 : 구현 비교 JavaScript 엔진 : 구현 비교 Apr 13, 2025 am 12:05 AM

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

Python vs. JavaScript : 학습 곡선 및 사용 편의성 Python vs. JavaScript : 학습 곡선 및 사용 편의성 Apr 16, 2025 am 12:12 AM

Python은 부드러운 학습 곡선과 간결한 구문으로 초보자에게 더 적합합니다. JavaScript는 가파른 학습 곡선과 유연한 구문으로 프론트 엔드 개발에 적합합니다. 1. Python Syntax는 직관적이며 데이터 과학 및 백엔드 개발에 적합합니다. 2. JavaScript는 유연하며 프론트 엔드 및 서버 측 프로그래밍에서 널리 사용됩니다.

JavaScript : 웹 언어의 다양성 탐색 JavaScript : 웹 언어의 다양성 탐색 Apr 11, 2025 am 12:01 AM

JavaScript는 현대 웹 개발의 핵심 언어이며 다양성과 유연성에 널리 사용됩니다. 1) 프론트 엔드 개발 : DOM 운영 및 최신 프레임 워크 (예 : React, Vue.js, Angular)를 통해 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축합니다. 2) 서버 측 개발 : Node.js는 비 차단 I/O 모델을 사용하여 높은 동시성 및 실시간 응용 프로그램을 처리합니다. 3) 모바일 및 데스크탑 애플리케이션 개발 : 크로스 플랫폼 개발은 개발 효율을 향상시키기 위해 반응 및 전자를 통해 실현됩니다.

Next.js (Frontend Integration)를 사용하여 멀티 테넌트 SaaS 응용 프로그램을 구축하는 방법 Next.js (Frontend Integration)를 사용하여 멀티 테넌트 SaaS 응용 프로그램을 구축하는 방법 Apr 11, 2025 am 08:22 AM

이 기사에서는 Contrim에 의해 확보 된 백엔드와의 프론트 엔드 통합을 보여 주며 Next.js를 사용하여 기능적인 Edtech SaaS 응용 프로그램을 구축합니다. Frontend는 UI 가시성을 제어하기 위해 사용자 권한을 가져오고 API가 역할 기반을 준수하도록합니다.

Next.js (백엔드 통합)로 멀티 테넌트 SAAS 애플리케이션 구축 Next.js (백엔드 통합)로 멀티 테넌트 SAAS 애플리케이션 구축 Apr 11, 2025 am 08:23 AM

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.

C/C에서 JavaScript까지 : 모든 것이 어떻게 작동하는지 C/C에서 JavaScript까지 : 모든 것이 어떻게 작동하는지 Apr 14, 2025 am 12:05 AM

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

See all articles