Menerapkan kembali == JavaScript di JavaScript – Beragampengetahuan
Artikel ini cocok untuk orang yang akrab dengan JavaScript == operator.
Operator “sama dengan” JavaScript, ==biasanya putus asa. Untuk alasan yang bagus: perilakunya rumit. Di mana === Menanyakan “Apakah ini hal yang sama?”, operator persamaan ganda memunculkan pertanyaan yang tidak terlalu sederhana.
Lebih khusus lagi, == Menerapkan algoritma yang disebut Algoritma Perbandingan Kesetaraan Abstrak, sebuah proses 13 langkah untuk menentukan apakah dua hal itu sama.
Mari kita coba menerapkan algoritma ini dalam JavaScript murni. (Jangan gunakan == Tentu saja itu operator. ) Ini pada dasarnya adalah ide yang tidak berguna, tapi saya ingin mencobanya!
Contents
Langkah 0: Kerangka
Kami akan menerapkan program yang disebut doubleEquals. Saya memasukkan yang berikut ini ke dalam doubleEquals.mjs:
export default function doubleEquals(x, y)
// TODO: steps 1 - 13
Saya juga menulis skrip pengujian yang mencoba banyak nilai berbeda untuk memastikannya berhasil.
Langkah 1: Gunakan === jika mereka bertipe sama
Langkah pertama dari algoritma ini dijelaskan sebagai berikut:
Jika Anda memasukkan (X) dan ketik(kamu), Kemudian
satu. Mengembalikan hasil dari melakukan perbandingan kesetaraan yang ketat X === kamu.
Spesifikasinya mengatakan “Simbol ‘Jenis(X)’ digunakan sebagai ‘tipe X‘” yang tipenya adalah “Tidak Terdefinisi, Null, Boolean, String, Simbol, Angka, BigInt, dan Objek”.
Ini mirip dengan typeof operator, tetapi Type(null) harus Null, di mana typeof null Ya "object"dan masukkan (Fungsi) harus menjadi objek di mana typeof myFunction Ya "function".
Jadi pada dasarnya kami ingin fungsi kami dimulai seperti ini:
export default function doubleEquals(x, y)
if (type(x) === type(y))
return x === y;
// TODO: steps 2 - 13
function type(x)
if (x === null)
return "null";
else if (typeof x === "function")
return "object";
else
return typeof x;
Ini akan mencakup situasi seperti 1 == 1, "foo" == "bar"Dan null == .
Langkah 2 dan 3: null Dan undefined
Langkah selanjutnya adalah sebagai berikut:
- jika X Ya Tidak sah Dan kamu Ya tidak jelaskembali nyata.
- jika X Ya tidak jelas Dan kamu Ya Tidak sahkembali nyata.
Dengan kata lain, ada kasus khusus yang bisa dibandingkan null Dan undefined.
Hal ini mudah untuk dicapai. Kita dapat menambahkan bagian berikut di bagian bawah:
export default function doubleEquals(x, y)
Sekarang kami ingin meliput undefined == null Dan null == undefined.
Langkah 4 dan 5: String dan Angka
Selanjutnya, kita perlu menangani kasus dimana kita memiliki string di satu sisi dan angka di sisi lain. Spesifikasi berlanjut:
- Jika Anda memasukkan (X) adalah angka dan tipe (kamu) adalah String, mengembalikan hasil perbandingan X ==! ke nomor (kamu).
- Jika Anda memasukkan (X) adalah string dan bertipe (kamu) adalah Angka, kembalikan hasil perbandingannya! ke nomor (X) == kamu.
Spesifikasinya menjelaskan ToNumber secara detail, khususnya untuk string. Namun, ini hampir terjadi Number Fungsi. Jadi kami akan menggunakannya daripada menerapkan kembali bagian spesifikasi tersebut.
export default function doubleEquals(x, y)
// ...steps 1 - 3...
if (type(x) === "number" && type(y) === "string")
return doubleEquals(x, Number(y));
if (type(x) === "string" && type(y) === "number")
return doubleEquals(Number(x), y);
// TODO: steps 6 - 13
Ini akan mencakup situasi seperti 1 == "1" Dan "0.3333333333333333333333333" == 1/3.
Langkah 6 dan 7: String dan BigInts
Anda juga dapat membandingkan string dan BigInts. Kasus khusus lainnya!
Jika Anda memasukkan (X) adalah BigInt dan bertipe (kamu) adalah sebuah string
satu. membiarkan N Ya! Ubah string menjadi bilangan bulat besar (kamu).
b.Jika N Ya Selatankembali Salah.
c. Mengembalikan hasil perbandingan X == N.
Jika Anda memasukkan (X) adalah string dan bertipe (kamu) adalah BigInt, mengembalikan hasil perbandingan kamu == X.
Dalam bahasa Inggris, langkah 6 artinya: Cobalah mengonversi string menjadi BigInt. Jika tidak, silakan kembali false. Bandingkan dengan BigInt jika memungkinkan. Langkah 7 pada dasarnya adalah kebalikannya.
StringToBigInt adalah fungsi yang hanya ada dalam spesifikasi (bukan perpustakaan standar), tetapi sangat mirip dengan global BigInt Fungsi. Kalau kita implementasi ulang tampilannya seperti ini:
function stringToBigInt(str)
try
return BigInt(str);
catch (err)
return NaN;
Setelah diimplementasikan, kita dapat menggunakannya di aplikasi kita doubleEquals Fungsi:
export default function doubleEquals(x, y)
// ...steps 1 - 5...
if (type(x) === "bigint" && type(y) === "string")
const n = stringToBigInt(y);
if (Number.isNaN(n))
return false;
return doubleEquals(x, n);
if (type(x) === "string" && type(y) === "bigint")
return doubleEquals(y, x);
// TODO: steps 8 - 13
Ini mencakup situasi seperti "5" == 5n Dan 123n == "garbage".
Langkah 8 dan 9: Nilai Boolean
Jika salah satu argumen adalah nilai Boolean, argumen tersebut harus dikonversi ke angka (0 berarti false1 untuk true) dan kemudian dengan ==.
- Jika Anda memasukkan (X) adalah nilai Boolean dan mengembalikan hasil perbandingan! ke nomor (X) == kamu.
- Jika Anda memasukkan (kamu) adalah nilai Boolean dan mengembalikan hasil perbandingan X ==! ke nomor (kamu).
Seperti sebelumnya, kita bisa menggunakan Number Sebagai perwakilan ToNumber. Number(false) Ya 0Dan Number(true) Ya 1.
export default function doubleEquals(x, y)
// ...steps 1 - 7...
if (type(x) === "boolean")
return doubleEquals(Number(x), y);
if (type(y) === "boolean")
return doubleEquals(x, Number(y));
// TODO: steps 10 - 13
Ini mencakup situasi seperti 1 == true, false == 0Dan 9 == true.
Langkah 10 dan 11: Objek ke Primitif
Menurut saya langkah-langkah di atas agak aneh, namun implementasinya terbilang singkat. Langkah 10 dan 11 adalah saat segalanya menjadi aneh.
Spesifikasi menguraikan langkah selanjutnya:
- Jika Anda memasukkan (X) adalah string, angka, BigInt, atau simbol dan tipe (kamu) adalah Objek, mengembalikan hasil perbandingan X ==KePrimitif(kamu).
- Jika Anda memasukkan (X) adalah objek dan tipenya (kamu) adalah String, Number, BigInt atau Simbol, dan mengembalikan hasil perbandingan ToPrimitive(X) == kamu.
Dengan kata lain: jika satu sisi adalah string, angka, BigInt, atau Simbol dan sisi lainnya adalah objek, ubah objek tersebut menjadi primitif dan bandingkan.
Spesifikasi ini mendefinisikan proses rinci untuk mengubah objek menjadi primitif. Namun, kita tidak perlu mengimplementasikan setiap bagian dari spesifikasi. Pada dasarnya kita perlu mencoba tiga metode (obj[Symbol.toPrimitive](), obj.valueOf()Dan obj.toString()).
ToPrimitive dapat diimplementasikan sebagai berikut. Saya mengomentarinya dengan baris dari spesifikasi.
function toPrimitive(input)
// > Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
const exoticToPrim = input[Symbol.toPrimitive];
// > If exoticToPrim is not undefined, then
if (exoticToPrim !== undefined)
// > Let result be ? Call(exoticToPrim, input, « hint »).
const result = exoticToPrim.call(input, "default");
// > If Type(result) is not Object, return result.
if (type(result) !== "object")
return result;
// > Throw a TypeError exception.
throw new TypeError("Cannot convert object to primitive");
// What follows is a simplified version of the
// ["OrdinaryToPrimitive" algorithm from the spec][4].
//
// [4]:
if (typeof input.valueOf === "function")
const result = input.valueOf();
if (type(result) !== "object")
return result;
if (typeof input.toString === "function")
const result = input.toString();
if (type(result) !== "object")
return result;
throw new TypeError("Cannot convert object to primitive");
seperti yang Anda lihat, TypeErrors dilemparkan dalam berbagai situasi. Itu sebabnya Anda melihat kesalahan saat mencoba menjalankannya 3 == Object.create(null). Sisi kanan tidak memiliki salah satu metode ini, sehingga tidak dapat dikonversi ke primitif dan karenanya terjadi kesalahan.
Dengan fungsi ini, kita dapat mengimplementasikan langkah 10 dan 11.
export default function doubleEquals(x, y)
// ...steps 1 - 9...
if (
["string", "number", "bigint", "symbol"].includes(type(x)) &&
type(y) === "object"
)
return doubleEquals(x, toPrimitive(y));
if (
type(x) === "object" &&
["string", "number", "bigint", "symbol"].includes(type(y))
)
return doubleEquals(toPrimitive(x), y);
// TODO: steps 12, 13
Ini menangani banyak situasi yang sangat membingungkan, seperti == "[object Object]" Dan 9 == [9].
Langkah 12: Angka dan BigInt
Langkah 12 agak aneh, tapi pada dasarnya kembali normal. Ini memungkinkan Anda membandingkan angka dan BigInt.
Jika Anda memasukkan (X) adalah BigInt dan bertipe (kamu) adalah angka, atau jika tipenya (X) adalah angka dan tipe (kamu) adalah BigInt, kalau begitu
satu. jika X atau kamu salah satu dari mereka Selatan, +∞atau -∞kembali Salah.
b.Jika nilai matematika X sama dengan nilai matematika kamukembali nyata; Jika tidak, kembalikan Salah.
Masing-masing bagian ini cukup mudah untuk diungkapkan, jika tidak sedikit membosankan. Untuk mengimplementasikan fungsi ini dalam JavaScript:
export default function doubleEquals(x, y)
Ini dapat menangani situasi seperti 123 == 123n.
Langkah 13: Saya rasa keduanya tidak setara
Langkah terakhir adalah favorit saya:
- kembali Salah.
Kami belum menemukan bahwa kedua nilai ini sama, jadi mari kita kembali false Katakanlah tidak.
Ketika ini selesai, fungsi kita (dan dependensinya) akan terlihat seperti ini. Saya telah menambahkan komentar.
// A re-implementation of the [Abstract Equality Comparison algorithm][0],
// which powers JavaScript's `==`.
//
// [0]:
export default function doubleEquals(x, y)
(x === undefined && y === null)
)
return true;
// > 4. If Type(x) is Number and Type(y) is String, return the result
// > of the comparison x == ! ToNumber(y).
//
// `Number` works well as an implementation of ToNumber.
if (type(x) === "number" && type(y) === "string")
return doubleEquals(x, Number(y));
// > 5. If Type(x) is String and Type(y) is Number, return the result
// > of the comparison ! ToNumber(x) == y.
if (type(x) === "string" && type(y) === "number")
return doubleEquals(Number(x), y);
// > 6. If Type(x) is BigInt and Type(y) is String, then
if (type(x) === "bigint" && type(y) === "string")
// > a. Let n be ! StringToBigInt(y).
const n = stringToBigInt(y);
// > b. If n is NaN, return false.
if (Number.isNaN(n))
return false;
// > c. Return the result of the comparison x == n.
return doubleEquals(x, n);
// > 7. If Type(x) is String and Type(y) is BigInt, return the result
// > of the comparison y == x.
if (type(x) === "string" && type(y) === "bigint")
return doubleEquals(y, x);
// > 8. If Type(x) is Boolean, return the result of the comparison
// > ! ToNumber(x) == y.
if (type(x) === "boolean")
return doubleEquals(Number(x), y);
// > 9. If Type(y) is Boolean, return the result of the comparison
// > x == ! ToNumber(y).
if (type(y) === "boolean")
return doubleEquals(x, Number(y));
// > 10. If Type(x) is either String, Number, BigInt, or Symbol and
// > Type(y) is Object, return the result of the comparison
// > x == ToPrimitive(y).
if (
["string", "number", "bigint", "symbol"].includes(type(x)) &&
type(y) === "object"
)
return doubleEquals(x, toPrimitive(y));
// > 11. If Type(x) is Object and Type(y) is either String, Number,
// > BigInt, or Symbol, return the result of the comparison
// > ToPrimitive(x) == y.
if (
type(x) === "object" &&
["string", "number", "bigint", "symbol"].includes(type(y))
)
return doubleEquals(toPrimitive(x), y);
// > 12. If Type(x) is BigInt and Type(y) is Number, or if Type(x) is
// > Number and Type(y) is BigInt, then
if (
(type(x) === "bigint" && type(y) === "number")
// See [the spec][1] for more details on this function. It's
// similar to `typeof`, but (1) `null` is its own type
// (2) functions should be treated as objects.
//
// [1]:
function type(x)
if (x === null)
return "null";
else if (typeof x === "function")
return "object";
else
return typeof x;
// See [the spec][2] for more details on this function.
//
// [2]:
function stringToBigInt(str)
try
return BigInt(str);
catch (err)
return NaN;
// [The spec][3] outlines detailed steps for converting a value to a
// primitive. This implements a simplified version of that, as used by
// `doubleEquals`.
//
// [3]:
function toPrimitive(input)
// > Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
const exoticToPrim = input[Symbol.toPrimitive];
// > If exoticToPrim is not undefined, then
if (exoticToPrim !== undefined)
// > Let result be ? Call(exoticToPrim, input, « hint »).
const result = exoticToPrim.call(input, "default");
// > If Type(result) is not Object, return result.
if (type(result) !== "object")
return result;
// > Throw a TypeError exception.
throw new TypeError("Cannot convert object to primitive");
// What follows is a simplified version of the
// ["OrdinaryToPrimitive" algorithm from the spec][4].
//
// [4]:
if (typeof input.valueOf === "function")
const result = input.valueOf();
if (type(result) !== "object")
return result;
if (typeof input.toString === "function")
const result = input.toString();
if (type(result) !== "object")
return result;
throw new TypeError("Cannot convert object to primitive");
sebagai kesimpulan
keseluruhanku doubleEquals Fungsi dan dependensinya adalah 104 baris kode (182 baris jika Anda menyertakan baris kosong dan komentar).
Seperti yang saya katakan di awal artikel, menerapkan kembali ini pada dasarnya adalah latihan yang tidak berguna. Saya harap ini membuktikannya == Alasan untuk tidak menyarankan: Ini adalah algoritma yang cukup rumit yang dapat menghasilkan beberapa hasil yang mengejutkan. Gunakan saja === alih-alih!
rencana pengembangan website
metode pengembangan website
jelaskan beberapa rencana untuk pengembangan website, proses pengembangan website, kekuatan dan kelemahan bisnis pengembangan website
, jasa pengembangan website, tahap pengembangan website, biaya pengembangan website
#Menerapkan #kembali #JavaScript #JavaScript