Rumah  >  Artikel  >  hujung hadapan web  >  Pemahaman mendalam tentang cara menggunakan Symbol dalam pengetahuan JavaScript_Basic

Pemahaman mendalam tentang cara menggunakan Symbol dalam pengetahuan JavaScript_Basic

WBOY
WBOYasal
2016-05-16 15:48:301449semak imbas

Apakah itu Simbol?

Simbol bukan ikon, dan juga tidak bermaksud imej kecil boleh digunakan dalam kod:

2015728114935470.jpg (291×49)

juga bukan sintaks untuk merujuk kepada sesuatu yang lain. Jadi, apa sebenarnya Simbol?
Tujuh jenis data

Apabila JavaScript diseragamkan pada tahun 1997, terdapat 6 jenis data Sehingga kemunculan ES6, pembolehubah dalam program mestilah salah satu daripada 6 jenis data berikut:

.

Tidak ditentukan
Batal
Boolean
Nombor
Rentetan
Objek

Setiap jenis data ialah gabungan siri nilai dan bilangan nilai lima jenis data pertama adalah terhad. Jenis Boolean hanya mempunyai dua nilai: benar dan salah Apabila memberikan nilai kepada pembolehubah jenis Boolean, tiada nilai baharu dijana (dua nilai benar dan salah dikongsi). Untuk Nombor dan Rentetan, nilainya lebih banyak. Pernyataan standard ialah terdapat 18,437,736,874,454,810,627 nilai jenis nombor (termasuk NAN). Bilangan jenis String sukar dikira pada asalnya (2144,115,188,075,855,872 ? 1) ÷ 65,535...tetapi mungkin saya silap.

Bilangan nilai objek tidak terhad, dan setiap objek adalah unik Setiap kali halaman web dibuka, satu siri objek dibuat.

Simbol dalam ES6 juga merupakan jenis data, tetapi ia bukan rentetan atau objek, tetapi jenis data baharu: jenis data ketujuh.

Mari kita lihat senario di mana Simbol mungkin berguna.
Soalan yang ditimbulkan oleh nilai Boolean

Kadangkala adalah sangat mudah untuk menyimpan sementara beberapa data kepunyaan objek lain dalam objek lain. Sebagai contoh, katakan anda menulis pustaka JS yang menggunakan peralihan dalam CSS untuk membuat elemen DOM terbang merentasi skrin Anda sudah tahu bahawa anda tidak boleh menggunakan berbilang peralihan pada div yang sama pada masa yang sama, jika tidak, animasi akan menjadi sangat tidak sedap dipandang. . Anda mempunyai cara untuk mengatasinya, tetapi pertama-tama anda perlu mengetahui sama ada div sudah bergerak.

Bagaimana untuk menyelesaikan masalah ini?

Salah satu cara ialah menggunakan API yang disediakan oleh penyemak imbas untuk mengesan sama ada elemen itu berada dalam keadaan animasi, tetapi ia membuang masa Apabila anda menetapkan elemen untuk bergerak, pustaka anda tahu bahawa elemen itu sedang bergerak.

Apa yang anda perlukan sebenarnya ialah mekanisme untuk menjejaki elemen mana yang bergerak, anda boleh menyimpan elemen bergerak dalam tatasusunan, dan setiap kali anda ingin menghidupkan elemen, semak dahulu sama ada elemen itu sudah ada dalam ini dalam senarai.

Ahem, tetapi jika tatasusunan anda sangat besar, walaupun carian linear seperti ini boleh mencipta isu prestasi.

Jadi, perkara yang anda mahu lakukan ialah tetapkan bendera terus pada elemen:

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

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

Ini juga mempunyai beberapa masalah yang berpotensi, dan anda perlu mengakui hakikat bahawa terdapat kod lain yang mungkin juga beroperasi pada elemen ODM ini.

  • Dalam kod lain, sifat yang anda buat akan disenaraikan oleh for-in atau Object.keys();
  • Kaedah yang sama mungkin telah digunakan dalam beberapa pustaka lain (menetapkan atribut yang sama pada elemen), maka ini akan bercanggah dengan kod anda dan menghasilkan keputusan yang tidak dapat diramalkan;
  • Sesetengah perpustakaan lain mungkin menggunakan pendekatan yang sama pada masa hadapan, yang juga akan bercanggah dengan kod anda;
  • Jawatankuasa piawaian boleh menambah kaedah asli .isMoving() pada setiap elemen dan kod anda tidak akan berfungsi sama sekali.
  • Sudah tentu, untuk tiga soalan terakhir, anda boleh memilih rentetan tidak bermakna yang tiada siapa akan gunakan:

Ini nampaknya tidak boleh dipercayai sehingga menyakitkan mata saya melihatnya.
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;

Anda juga boleh menggunakan algoritma penyulitan untuk menjana rentetan yang hampir unik:

Sintaks
objek[nama] membolehkan kami menggunakan sebarang rentetan sebagai nama sifat, kod akan berfungsi seperti biasa, konflik hampir mustahil dan kod akan kelihatan lebih baik.
// 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;

Walau bagaimanapun, ini membawa kepada pengalaman penyahpepijatan yang buruk Setiap kali anda menggunakan console.log() untuk mencetak elemen yang mengandungi atribut ini, anda akan melihat rentetan sampah yang besar, dan bagaimana jika terdapat lebih daripada satu atribut sedemikian? ? Nama atribut telah berubah selepas setiap muat semula Bagaimana untuk menjadikan atribut ini kelihatan lebih intuitif?

Kenapa susah sangat? Kami hanya menyimpan sedikit bendera.

Gunakan Simbol untuk menyelesaikan masalah


Nilai simbol boleh dibuat secara pengaturcaraan dan digunakan sebagai nama atribut tanpa perlu risau tentang konflik nama atribut.

调用 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

Paksaan sedemikian harus dielakkan dan String(sym) atau sym.toString() harus digunakan untuk penukaran.
Tiga cara untuk mendapatkan Simbol

  1. Symbol() mengembalikan Simbol unik setiap kali ia dipanggil.
  2. Symbol.for(string) mengembalikan Simbol yang sepadan daripada pendaftaran Simbol Tidak seperti kaedah sebelumnya, Simbol dalam pendaftaran Simbol dikongsi. Iaitu, jika anda memanggil Symbol.for("cat") tiga kali, Simbol yang sama akan dikembalikan. Pendaftaran sangat berguna apabila halaman yang berbeza atau modul yang berbeza dari halaman yang sama perlu berkongsi Simbol.
  3. Symbol.iterator mengembalikan beberapa Simbol yang dipratakrifkan oleh bahasa, setiap satu dengan tujuan khasnya sendiri.

Jika anda masih tidak pasti sama ada Simbol berguna, bahagian seterusnya akan menjadi sangat menarik kerana saya akan menunjukkan kepada anda Simbol dalam tindakan.
Aplikasi Simbol dalam spesifikasi ES6

Kami sudah tahu bahawa kami boleh menggunakan Simbol untuk mengelakkan konflik kod. Apabila memperkenalkan iterator sebelum ini, kami juga menganalisis bahawa untuk (var item myArray) secara dalaman bermula dengan memanggil myArray[Symbol.iterator](Pada masa itu, saya menyebut bahawa kaedah ini boleh digantikan dengan myArray.iterator(), tetapi menggunakan Simbol mempunyai keserasian ke belakang yang lebih baik.

Masih terdapat beberapa tempat di mana Simbol digunakan dalam ES6. (Ciri ini belum lagi dilaksanakan dalam FireFox.)

  • Jadikan instanceof extensible. Dalam ES6, contoh objek bagi ungkapan pembina diseragamkan kepada kaedah pembina: pembina[Symbol.hasInstance](objek), yang bermaksud ia boleh diperluaskan.
  • Hapuskan konflik antara ciri baharu dan kod lama.
  • Sokong jenis padanan rentetan baharu. Dalam ES5, apabila str.match(myObject) dipanggil, ia mula-mula cuba menukar myObject kepada objek RegExp. Dalam ES6, myObject akan disemak terlebih dahulu untuk kaedah myObject[Symbol.match](str), dan kaedah penghuraian rentetan tersuai boleh disediakan di mana-mana sahaja ungkapan biasa berfungsi.

Penggunaan ini masih agak sempit, tetapi sukar untuk melihat kesan ketara ciri baharu ini hanya dengan melihat kod dalam artikel saya. Simbol JavaScript ialah versi __doubleUnderscores yang dipertingkatkan dalam PHP dan Python, dan organisasi standard akan menggunakannya untuk menambah ciri baharu pada bahasa tanpa menjejaskan kod sedia ada.

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn