Rumah > hujung hadapan web > tutorial js > Pemahaman mendalam tentang siri JavaScript (19): Penjelasan terperinci tentang strategi penilaian_Pengetahuan asas

Pemahaman mendalam tentang siri JavaScript (19): Penjelasan terperinci tentang strategi penilaian_Pengetahuan asas

WBOY
Lepaskan: 2016-05-16 16:11:09
asal
968 orang telah melayarinya

Pengenalan

Dalam bab ini, kami akan menerangkan strategi menghantar parameter kepada fungsi dalam ECMAScript.

Dalam sains komputer, strategi ini biasanya dipanggil "strategi penilaian" (Nota pakcik: Ada orang kata ia diterjemahkan sebagai strategi penilaian, dan sesetengah orang menterjemahkannya sebagai strategi tugasan. Melihat kepada kandungan berikut, saya rasa ia dipanggil Strategi tugasan adalah lebih sesuai, bagaimanapun, tajuk harus ditulis sebagai strategi penilaian yang mudah difahami oleh semua orang), seperti menetapkan peraturan untuk menilai atau mengira ungkapan dalam bahasa pengaturcaraan. Strategi menyampaikan hujah kepada fungsi adalah kes khas.

http://dmitrysoshnikov.com/ecmascript/chapter-8-evaluation-strategy/
Sebab untuk menulis artikel ini adalah kerana seseorang di forum meminta penjelasan yang tepat tentang beberapa strategi lulus parameter Kami telah memberikan definisi yang sepadan di sini, berharap dapat membantu semua orang.

Ramai pengaturcara yakin bahawa dalam JavaScript (dan juga beberapa bahasa lain), objek diluluskan melalui rujukan, manakala jenis nilai primitif diluluskan oleh nilai Di samping itu, banyak artikel menyebut "fakta" ini, tetapi ramai orang Adakah anda benar-benar memahami istilah ini, dan berapakah yang betul kami akan menerangkannya satu persatu dalam artikel ini.

Teori Umum

Perlu diingat bahawa secara amnya terdapat dua strategi tugasan dalam teori tugasan: ketat-bermaksud bahawa parameter dikira sebelum memasuki program; adalah, bersamaan dengan pengiraan tertunda).

Kemudian, di sini kami mempertimbangkan strategi lulus parameter fungsi asas, yang sangat penting dari titik permulaan ECMAScript. Perkara pertama yang perlu diperhatikan ialah ECMAScript (dan juga bahasa lain seperti C, JAVA, Python dan Ruby) menggunakan strategi lulus parameter yang ketat.

Selain itu, susunan pengiraan parameter yang diluluskan juga sangat penting - dalam ECMAScript ia kiri ke kanan, dan susunan pantulan (dari kanan) yang dilaksanakan dalam bahasa lain​​​juga boleh digunakan.

Strategi lulus parameter yang ketat juga dibahagikan kepada beberapa substrategi, yang paling penting yang kami bincangkan secara terperinci dalam bab ini.

Bukan semua strategi yang dibincangkan di bawah digunakan dalam ECMAScript, jadi apabila membincangkan gelagat khusus strategi ini, kami menggunakan pseudokod untuk menunjukkannya.

Lewati nilai

Lewati nilai, seperti yang diketahui oleh ramai pembangun Nilai parameter ialah salinan nilai objek yang dilalui oleh pemanggil Menukar nilai parameter di dalam fungsi tidak akan menjejaskan objek luaran ( parameter adalah dalam nilai Luaran), secara amnya, memori baru diagihkan semula (kami tidak memberi perhatian kepada bagaimana memori yang diperuntukkan dilaksanakan - ia juga merupakan timbunan atau peruntukan memori dinamik), nilai blok memori baru adalah salinan objek luaran, dan Nilainya digunakan di dalam fungsi.

Salin kod Kod adalah seperti berikut:

bar = 10

prosedur foo(barArg):
barArg = 20;
tamat

foo(bar)

// Menukar nilai dalam foo tidak akan menjejaskan nilai bar dalaman
print(bar) // 10

Walau bagaimanapun, jika parameter fungsi itu bukan nilai primitif tetapi objek struktur yang kompleks, ia akan menyebabkan masalah prestasi yang besar C mempunyai masalah ini Apabila struktur dimasukkan ke dalam fungsi sebagai nilai - ia adalah salinan lengkap.

Mari kita berikan contoh umum dan gunakan strategi tugasan berikut untuk mengujinya. Fikirkan tentang fungsi yang menerima 2 parameter Parameter pertama ialah nilai objek, dan parameter kedua ialah tanda Boolean objek diubah suai sepenuhnya (ditugaskan semula nilai kepada objek), atau hanya beberapa sifat objek diubah suai.

Salin kod Kod adalah seperti berikut:

// Nota: Berikut adalah pseudokod, bukan pelaksanaan JS
bar = {
x: 10,
y: 20
}

prosedur foo(barArg, isFullChange):

jika adalahFullChange:
barArg = {z: 1, q: 2}
keluar
tamat

barArg.x = 100
barArg.y = 200

tamat

foo(bar)

// Melewati nilai, objek luaran tidak diubah
print(bar) // {x: 10, y: 20}

// Tukar objek sepenuhnya (tetapkan nilai baharu)
foo(bar, benar)

//Tiada perubahan juga
print(bar) // {x: 10, y: 20}, bukannya {z: 1, q: 2}

Lulus dengan rujukan

Satu lagi kaedah rujukan lulus yang terkenal tidak menerima salinan nilai, tetapi rujukan tersirat kepada objek, seperti alamat rujukan luaran langsung objek. Sebarang perubahan pada parameter di dalam fungsi akan menjejaskan nilai objek di luar fungsi, kerana kedua-duanya merujuk kepada objek yang sama, iaitu: pada masa ini, parameter adalah bersamaan dengan alias objek luaran.

Kod pseudo:

Salin kod Kod adalah seperti berikut:

prosedur foo(barArg, isFullChange):

jika adalahFullChange:
barArg = {z: 1, q: 2}
keluar
tamat

barArg.x = 100
barArg.y = 200

tamat

//Gunakan objek yang sama seperti di atas
bar = {
x: 10,
y: 20
}

// Hasil panggilan melalui rujukan adalah seperti berikut:
foo(bar)

// Nilai atribut objek telah ditukar
print(bar) // {x: 100, y: 200}

// Menetapkan semula nilai baharu ​​juga mempengaruhi objek
foo(bar, benar)

// Objek itu kini menjadi objek baharu
print(bar) // {z: 1, q: 2}

Strategi ini membolehkan penghantaran objek kompleks yang lebih cekap, seperti objek struktur besar dengan kumpulan sifat yang besar.

Panggil dengan berkongsi
Semua tahu dua strategi di atas, tetapi strategi yang ingin saya ceritakan di sini mungkin tidak difahami dengan baik oleh semua orang (sebenarnya ia adalah strategi akademik). Walau bagaimanapun, kami tidak lama lagi akan melihat bahawa ini betul-betul strategi yang memainkan peranan penting dalam strategi lulus parameter dalam ECMAScript.

Terdapat juga beberapa sinonim untuk strategi ini: "lalui objek" atau "lalui perkongsian objek".

Strategi ini telah dicadangkan oleh Barbara Liskov pada tahun 1974 untuk bahasa pengaturcaraan CLU.

Inti utama strategi ini ialah: fungsi menerima salinan (salinan) objek, dan salinan rujukan dikaitkan dengan parameter formal dan nilainya.

Kami tidak boleh memanggil rujukan yang dipaparkan di sini sebagai "laluan rujukan" kerana parameter yang diterima oleh fungsi tersebut bukanlah alias objek langsung, tetapi salinan alamat rujukan.

Perbezaan yang paling penting ialah: menetapkan semula nilai baharu kepada parameter di dalam fungsi tidak akan menjejaskan objek luaran (sama seperti kes lulus melalui rujukan dalam contoh di atas), tetapi kerana parameter itu adalah salinan alamat, ia tidak boleh diakses di luar dan di dalam Objek yang sama diakses (contohnya, objek luaran bukan salinan lengkap seperti lulus mengikut nilai), dan menukar nilai atribut objek parameter akan menjejaskan objek luaran.

Salin kod Kod adalah seperti berikut:

prosedur foo(barArg, isFullChange):

jika adalahFullChange:
barArg = {z: 1, q: 2}
keluar
tamat

barArg.x = 100
barArg.y = 200

tamat

//Masih menggunakan struktur objek ini
bar = {
x: 10,
y: 20
}

// Melepasi sumbangan akan menjejaskan objek
foo(bar)

// Sifat objek telah diubah suai
print(bar) // {x: 100, y: 200}

// Penugasan semula tiada kesan
foo(bar, benar)

// Masih nilai di atas
print(bar) // {x: 100, y: 200}


Pemprosesan ini menganggap bahawa objek digunakan dalam kebanyakan bahasa, bukannya nilai primitif.

Pas by share ialah kes khas pass by value

Strategi pass-by-share digunakan dalam banyak bahasa: Java, ECMAScript, Python, Ruby, Visual Basic, dsb. Tambahan pula, komuniti Python telah menggunakan istilah ini, dan bahasa lain juga boleh menggunakan istilah ini, kerana nama lain cenderung menyebabkan kekeliruan. Dalam kebanyakan kes, seperti dalam Java, ECMAScript atau Visual Basic, strategi ini juga dipanggil pass-by-value - bermaksud: salinan rujukan nilai khas.

Di satu pihak, ia adalah seperti ini - parameter yang dihantar ke fungsi hanyalah nama nilai terikat (alamat rujukan) dan tidak akan menjejaskan objek luaran.

Sebaliknya, istilah ini benar-benar dianggap salah tanpa menggali lebih dalam, kerana banyak forum bercakap tentang cara menghantar objek ke fungsi JavaScript).

Teori umum memang mengatakan bahawa ia diluluskan oleh nilai: tetapi pada masa ini nilai itu adalah apa yang kita panggil salinan alamat (salinan), jadi ia tidak melanggar peraturan.

Dalam Ruby, strategi ini dipanggil lulus dengan rujukan. Sekali lagi: ia tidak diluluskan sebagai salinan struktur besar (iaitu tidak diluluskan oleh nilai), dan sebaliknya, kami tidak berurusan dengan rujukan kepada objek asal, dan tidak boleh mengubah suainya; -konsep istilah boleh menyebabkan lebih banyak masalah.

Secara teori, tiada kes khas lulus melalui rujukan seperti kes khas lulus mengikut nilai.

Tetapi masih perlu untuk memahami bahawa dalam teknologi yang disebutkan di atas (Java, ECMAScript, Python, Ruby, lain-lain), sebenarnya - strategi yang mereka gunakan adalah pass-by-share.

Tekan Kongsi & Penunjuk

Untuk С/С, strategi ini dari segi ideologi sama dengan pass-by-pointer-by-value, tetapi dengan satu perbezaan penting - strategi ini boleh membatalkan rujukan penunjuk serta mengubah objek sepenuhnya. Tetapi secara umum, penunjuk nilai (alamat) diperuntukkan kepada blok memori baharu (iaitu, blok memori yang dirujuk sebelum ini kekal tidak berubah);

Jadi, dan kategori penunjuk, kita dapat melihat dengan jelas bahawa ini diluluskan oleh nilai alamat. Dalam kes ini, perkongsian lulus hanyalah "gula sintaksis" yang berkelakuan seperti tugasan penunjuk (tetapi tidak boleh menyahrujuk), atau mengubah suai sifat seperti rujukan (tidak memerlukan operasi penyahrujukan). ".

Walau bagaimanapun, С/С juga mempunyai gula sintaks khas apabila merujuk sifat objek tanpa nyahrujukan penunjuk yang jelas:

Salin kod Kod adalah seperti berikut:

obj->x bukannya (*obj).x

Ideologi ini paling rapat dikaitkan dengan C dan boleh dilihat dalam pelaksanaan "petunjuk pintar", contohnya, dalam boost::shared_ptr, yang membebankan pengendali tugasan dan pembina salinan dan juga menggunakan kaunter rujukan objek, padam objek melalui GC. Jenis data ini malah mempunyai nama yang serupa - shared_ptr.

Pelaksanaan ECMAScript

Sekarang kita tahu strategi menghantar objek sebagai parameter dalam ECMAScript - lulus dengan perkongsian: mengubah suai sifat parameter akan menjejaskan bahagian luar, tetapi penugasan semula tidak akan menjejaskan objek luaran. Walau bagaimanapun, seperti yang kami nyatakan di atas, pembangun ECMAScript di kalangan mereka biasanya memanggilnya: lulus mengikut nilai, kecuali nilai itu adalah salinan alamat rujukan.

Pencipta JavaScript Brendan Ash juga menulis: Apa yang diluluskan ialah salinan rujukan (salinan alamat). Jadi apa yang pernah dikatakan oleh semua orang dalam forum tentang passing by value juga betul di bawah penjelasan ini.

Lebih tepat, tingkah laku ini boleh difahami sebagai tugasan mudah Kita dapat melihat bahawa di dalamnya adalah objek yang sama sekali berbeza, tetapi ia merujuk kepada nilai yang sama - iaitu, salinan alamat.

Kod ECMAScript:

Salin kod Kod adalah seperti berikut:

var foo = {x: 10, y: 20};
var bar = foo;

alert(bar === foo); // benar

bar.x = 100;
bar.y = 200;

makluman([foo.x, foo.y]); // [100, 200]

Iaitu, dua pengecam (pengikatan nama) diikat pada objek yang sama dalam ingatan dan berkongsi objek ini:

nilai foo: addr(0xFF) => {x: 100, y: 200} (alamat 0xFF) <= nilai bar: addr(0xFF)
Dengan penugasan semula, pengikatan adalah kepada pengecam objek baharu (alamat baharu) tanpa menjejaskan objek terikat sebelumnya:

Salin kod Kod adalah seperti berikut:

bar = {z: 1, q: 2};

alarm([foo.x, foo.y]); // [100, 200] – unverändert
Alert([bar.z, bar.q]); // [1, 2] – aber jetzt referenziert ein neues Objekt

Das heißt, jetzt haben foo und bar unterschiedliche Werte und unterschiedliche Adressen:
Code kopieren Der Code lautet wie folgt:

foo-Wert: addr(0xFF) => {x: 100, y: 200} (Adresse 0xFF)
Balkenwert: addr(0xFA) => {z: 1, q: 2} (Adresse 0xFA)

Lassen Sie mich noch einmal betonen, dass der Wert des hier erwähnten Objekts die Adresse (Adresse) ist, nicht die Objektstruktur selbst. Das Zuweisen einer Variablen zu einer anderen Variablen ist ein Verweis auf den zugewiesenen Wert. Daher beziehen sich beide Variablen auf dieselbe Speicheradresse. Die nächste Zuweisung ist eine neue Adresse, die die Adressbindung an das alte Objekt auflöst und es dann an die Adresse des neuen Objekts bindet. Dies ist der wichtigste Unterschied zur Übergabe als Referenz.

Wenn wir außerdem nur die vom ECMA-262-Standard bereitgestellte Abstraktionsebene berücksichtigen, sehen wir im Algorithmus nur das Konzept des „Werts“ und den von der Implementierung übergebenen „Wert“ (kann ein primitiver Wert sein). oder ein Objekt), aber gemäß unserer obigen Definition kann es auch als „Wertübergabe“ bezeichnet werden, da die Referenzadresse auch ein Wert ist.

Um jedoch Missverständnisse zu vermeiden (warum die Eigenschaften externer Objekte innerhalb der Funktion geändert werden können), müssen hier noch Details auf Implementierungsebene berücksichtigt werden – was wir als Passing-by-Sharing oder anders betrachten Wörter - Übergeben Sie einen sicheren Zeiger, und es ist für einen sicheren Zeiger unmöglich, das Objekt zu dereferenzieren und zu ändern, aber er kann den Attributwert des Objekts ändern.

Termversion

Lassen Sie uns die Begriffsversion dieser Strategie in ECMAScript definieren.

Man kann es als „Wertübergabe“ bezeichnen – der hier erwähnte Wert ist ein Sonderfall, das heißt, der Wert ist eine Adresskopie. Von dieser Ebene aus können wir sagen: Alle Objekte in ECMAScript mit Ausnahme von Ausnahmen werden als Wert übergeben. Dies ist tatsächlich die abstrakte Ebene von ECMAScript.

Oder in diesem Fall wird es speziell als „Pass-by-Share“ bezeichnet. Daran können Sie den Unterschied zwischen der traditionellen Pass-by-Value und der Pass-by-Reference erkennen. Diese Situation kann in zwei Situationen unterteilt werden: 1: Originalwerte ​werden als Wert übergeben; 2: Objekte werden durch Teilen übergeben.

Der Satz „Konvertieren eines Objekts in eine Funktion anhand des Referenztyps“ hat nichts mit ECMAScript zu tun und ist falsch.

Fazit

Ich hoffe, dieser Artikel hilft dabei, mehr Details zum Gesamtbild und seiner Implementierung in ECMAScript zu verstehen. Wenn Sie Fragen haben, können Sie diese wie immer gerne besprechen.

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
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
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan