เมื่อเร็ว ๆ นี้ฉันพบคำถามที่น่าสนใจ: "ค่าใน js ผ่านตามค่าหรือโดยการอ้างอิงหรือไม่"
ก่อนที่จะวิเคราะห์ปัญหานี้เราต้องเข้าใจสิ่งที่เรียกว่าค่าและสิ่งที่เรียกโดยการอ้างอิง ในวิทยาศาสตร์คอมพิวเตอร์ส่วนนี้เรียกว่ากลยุทธ์การประเมินผล มันกำหนดวิธีการส่งผ่านระหว่างตัวแปรระหว่างพารามิเตอร์จริงและพารามิเตอร์ที่เป็นทางการเมื่อเรียกใช้ฟังก์ชัน
ผ่านมูลค่าเทียบกับ ผ่านการอ้างอิง
การโทรตามค่าเป็นกลยุทธ์การประเมินที่ใช้กันมากที่สุด: พารามิเตอร์อย่างเป็นทางการของฟังก์ชั่นคือสำเนาของพารามิเตอร์จริงที่ผ่านเมื่อเรียก การแก้ไขค่าของพารามิเตอร์ที่เป็นทางการจะไม่ส่งผลกระทบต่อพารามิเตอร์จริง
เมื่อผ่านโดยการอ้างอิง (การโทรโดยอ้างอิง) พารามิเตอร์ที่เป็นทางการของฟังก์ชั่นจะได้รับการอ้างอิงโดยนัยของพารามิเตอร์จริงแทนที่จะเป็นสำเนา ซึ่งหมายความว่าหากค่าของพารามิเตอร์ฟังก์ชันได้รับการแก้ไขพารามิเตอร์จริงจะถูกแก้ไขด้วย ทั้งสองชี้ไปที่ค่าเดียวกัน
ผ่านการอ้างอิงทำให้การติดตามฟังก์ชั่นเรียกยากขึ้นและบางครั้งก็ทำให้เกิดข้อบกพร่องบางอย่าง
ผ่านมูลค่าเนื่องจากแบบจำลองถูกโคลนทุกครั้งประสิทธิภาพจะต่ำกว่าสำหรับบางประเภทที่ซับซ้อน ทั้งสองวิธีการผ่านค่าผ่านมีปัญหาของตัวเอง
ก่อนอื่นให้ดูที่ตัวอย่าง C เพื่อทำความเข้าใจความแตกต่างระหว่างการส่งผ่านตามค่าและการอ้างอิง:
การคัดลอกรหัสมีดังนี้:
โมฆะแก้ไข (int p, int * q)
-
p = 27; // pass p โดยค่าเป็นสำเนาของพารามิเตอร์จริง A เฉพาะ P ถูกแก้ไขเท่านั้น
*Q = 27; // Q เป็นการอ้างอิงถึง B และทั้ง Q และ B ได้รับการแก้ไข
-
int main ()
-
int a = 1;
int b = 1;
แก้ไข (a, & b); // a pass by value, B ผ่านการอ้างอิง
// a ไม่เปลี่ยนแปลง B เปลี่ยนไป
return (0);
-
ที่นี่เราจะเห็น:
A => เมื่อ P ถูกส่งผ่านค่าการแก้ไขค่าของพารามิเตอร์ที่เป็นทางการ p จะไม่ส่งผลกระทบต่อพารามิเตอร์จริง A, P เป็นเพียงสำเนาของ A
B => Q ถูกส่งผ่านโดยการอ้างอิง เมื่อแก้ไขค่าของพารามิเตอร์ที่เป็นทางการ Q มันยังส่งผลกระทบต่อค่าของพารามิเตอร์จริง b
สำรวจว่าค่า JS ผ่านไปได้อย่างไร
ประเภทพื้นฐานของ JS ถูกส่งผ่านตามมูลค่า
การคัดลอกรหัสมีดังนี้:
var a = 1;
ฟังก์ชั่น foo (x) {
x = 2;
-
foo (a);
console.log (a); // ยัง 1 ไม่ได้รับผลกระทบจากการกำหนด x = 2
มาดูวัตถุ:
การคัดลอกรหัสมีดังนี้:
var obj = {x: 1};
ฟังก์ชั่น foo (o) {
OX = 3;
-
foo (obj);
console.log (obj.x); // 3 แก้ไข!
อธิบาย O และ OBJ เป็นวัตถุเดียวกันและ O ไม่ใช่สำเนาของ OBJ ดังนั้นจึงไม่ผ่านไปตามมูลค่า แต่นี่หมายความว่าวัตถุ JS ถูกส่งผ่านโดยการอ้างอิงหรือไม่? ลองดูตัวอย่างต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
var obj = {x: 1};
ฟังก์ชั่น foo (o) {
o = 100;
-
foo (obj);
console.log (obj.x); // ยัง 1, OBJ ยังไม่ได้รับการแก้ไขเป็น 100
หากผ่านการอ้างอิงการแก้ไขค่าของพารามิเตอร์ที่เป็นทางการ o ควรส่งผลกระทบต่อพารามิเตอร์จริง แต่การปรับเปลี่ยนมูลค่าของ O ที่นี่ไม่ส่งผลกระทบต่อ OBJ ดังนั้นวัตถุใน JS จะไม่ผ่านการอ้างอิง ดังนั้นค่าของวัตถุจะถูกส่งผ่านใน JS ได้อย่างไร?
ผ่านการโทรโดยการแบ่งปัน
เพื่อความแม่นยำประเภทพื้นฐานใน JS จะถูกส่งผ่านด้วยค่าและประเภทวัตถุจะถูกส่งผ่านโดยการแบ่งปัน (เรียกโดยการแบ่งปันหรือเรียกโดยวัตถุและแชร์โดยวัตถุ) มันถูกเสนอครั้งแรกโดย Barbara Liskov ในภาษา Glu 1974 กลยุทธ์การประเมินนี้ใช้ใน Python, Java, Ruby, JS และภาษาอื่น ๆ
จุดของกลยุทธ์นี้คือเมื่อฟังก์ชั่นผ่านอาร์กิวเมนต์ฟังก์ชั่นยอมรับสำเนาของการอ้างอิงอาร์กิวเมนต์ที่แท้จริงของวัตถุ (ทั้งสำเนาของวัตถุที่ส่งผ่านตามค่าหรือการอ้างอิงโดยนัยที่ส่งผ่านโดยการอ้างอิง) ความแตกต่างระหว่างมันและการส่งผ่านโดยการอ้างอิงคือการกำหนดพารามิเตอร์ฟังก์ชันในบัตรผ่านที่ใช้ร่วมกันจะไม่ส่งผลกระทบต่อค่าของพารามิเตอร์จริง ดังในตัวอย่างต่อไปนี้ค่าของ OBJ ไม่สามารถแก้ไขได้โดยการแก้ไขค่าของพารามิเตอร์ที่เป็นทางการ o
การคัดลอกรหัสมีดังนี้:
var obj = {x: 1};
ฟังก์ชั่น foo (o) {
o = 100;
-
foo (obj);
console.log (obj.x); // ยัง 1, OBJ ยังไม่ได้รับการแก้ไขเป็น 100
อย่างไรก็ตามแม้ว่าการอ้างอิงจะเป็นสำเนาวัตถุอ้างอิงก็เหมือนกัน พวกเขาแบ่งปันวัตถุเดียวกันดังนั้นการแก้ไขค่าแอตทริบิวต์ของวัตถุพารามิเตอร์อย่างเป็นทางการจะส่งผลกระทบต่อค่าแอตทริบิวต์ของพารามิเตอร์จริง
การคัดลอกรหัสมีดังนี้:
var obj = {x: 1};
ฟังก์ชั่น foo (o) {
OX = 3;
-
foo (obj);
console.log (obj.x); // 3 แก้ไข!
สำหรับประเภทวัตถุเนื่องจากวัตถุที่ไม่แน่นอนการแก้ไขวัตถุนั้นจะส่งผลกระทบต่อการแบ่งปันการอ้างอิงและสำเนาอ้างอิงของวัตถุ สำหรับประเภทพื้นฐานเนื่องจากทั้งคู่ไม่เปลี่ยนรูปไม่มีความแตกต่างระหว่างการผ่านโดยการแบ่งปันและการส่งผ่านตามมูลค่า (การโทรตามมูลค่า) ดังนั้นประเภทพื้นฐานของ JS จึงสอดคล้องกับการส่งผ่านตามมูลค่าและสอดคล้องกับการแชร์
การคัดลอกรหัสมีดังนี้:
var a = 1; // 1 คือหมายเลขประเภท, var b = a; b = 6;
ตามกลยุทธ์การประเมินผลที่ผ่านการแบ่งปัน A และ B เป็นข้อมูลอ้างอิงที่แตกต่างกันสองแบบ (B เป็นสำเนาอ้างอิงของ A) แต่อ้างอิงค่าเดียวกัน เนื่องจากประเภทพื้นฐานที่ 1 ที่นี่ไม่เปลี่ยนรูปจึงไม่มีความแตกต่างระหว่างการส่งผ่านตามมูลค่าและผ่านโดยการแบ่งปันที่นี่
คุณสมบัติพื้นฐานที่ไม่เปลี่ยนรูป
ประเภทพื้นฐานนั้นไม่เปลี่ยนรูปและวัตถุเท่านั้นที่ไม่แน่นอน ตัวอย่างเช่นค่าตัวเลข 100 ค่าบูลีนเป็นจริงเท็จและการแก้ไขค่าเหล่านี้ (ตัวอย่างเช่นการเปลี่ยน 1 เป็น 3 และเปลี่ยนเป็นจริงเป็น 100) ไม่สมเหตุสมผล สิ่งที่ง่ายกว่าที่จะเข้าใจผิดคือสตริงใน JS บางครั้งเราพยายามที่จะ "เปลี่ยน" เนื้อหาของสตริง แต่ใน JS การดำเนินการ "แก้ไข" ใด ๆ ที่ดูเหมือนว่าจะเป็นค่าสตริงจริง ๆ แล้วกำลังสร้างค่าสตริงใหม่
การคัดลอกรหัสมีดังนี้:
var str =“ abc”;
str [0]; //“ A”
str [0] = "D";
Str; // ยังคง "abc"; การมอบหมายไม่ถูกต้อง ไม่มีวิธีแก้ไขเนื้อหาของสตริง
วัตถุแตกต่างกันวัตถุเป็นตัวแปร
การคัดลอกรหัสมีดังนี้:
var obj = {x: 1};
obj.x = 100;
var o = obj;
OX = 1;
obj.x; // 1 แก้ไข
o = true;
obj.x; // 1 จะไม่เปลี่ยนแปลงเนื่องจาก o = true
ที่นี่ตัวแปร OBJ ถูกกำหนดค่าเป็นวัตถุและจากนั้นค่าของคุณสมบัติ obj.x ถูกตั้งค่าเป็น 100 จากนั้นกำหนดตัวแปรอื่น o และค่ายังคงเป็นวัตถุวัตถุนี้ ในเวลานี้ค่าของตัวแปรทั้งสอง OBJ และ O ชี้ไปที่วัตถุเดียวกัน (แชร์การอ้างอิงไปยังวัตถุเดียวกัน) ดังนั้นการปรับเปลี่ยนเนื้อหาของวัตถุจึงมีผลกระทบต่อทั้ง OBJ และ O อย่างไรก็ตามวัตถุไม่ผ่านการอ้างอิง ค่าของ O ถูกแก้ไขโดย O = TRUE และจะไม่ส่งผลกระทบต่อ OBJ