JavaScript Deep Copy ได้รับการพัฒนาโดยผู้เริ่มต้นและแม้กระทั่งประสบการณ์และพวกเขามักจะพบปัญหาและไม่สามารถเข้าใจการคัดลอกลึกของ JavaScript ได้เป็นอย่างดี
DeepClone?
ตรงกันข้ามกับสำเนาลึกคือสำเนาตื้น ผู้เริ่มต้นหลายคนสับสนเมื่อพวกเขาเข้ามาติดต่อกับความรู้สึกนี้
ทำไมต้องใช้สำเนาลึก?
ในหลายกรณีเราจำเป็นต้องกำหนดค่าให้กับตัวแปรและกำหนดค่าให้กับที่อยู่หน่วยความจำ อย่างไรก็ตามเมื่อกำหนดประเภทค่าอ้างอิงเราจะแชร์พื้นที่หน่วยความจำเท่านั้นซึ่งส่งผลให้เกิดความสอดคล้องกับค่าก่อนหน้าเมื่อกำหนด
ดูตัวอย่างเฉพาะ
// กำหนดวัตถุให้ทดสอบ var test = {a: 'a', b: 'b'}; // กำหนดทดสอบให้ทดสอบ 2 // ในเวลานี้ทดสอบและทดสอบ 2 แบ่งปันวัตถุหน่วยความจำเดียวกันซึ่งเป็นสำเนาตื้นของ VAR Test2 = test; test2.a = 'a2'; test.a === 'a2' // เป็นจริงภาพประกอบ:
นี่เป็นความคิดที่ดีที่จะเข้าใจว่าทำไมข้อมูลประเภทค่าอ้างอิงจึงมีผลต่อกันและกัน
ทำให้สำเร็จ
ในการใช้ฟังก์ชั่นการคัดลอกลึกเราต้องพูดคุยเกี่ยวกับประเภทตัวเลขของ JavaScript
กำหนดประเภท JavaScript
มีประเภทพื้นฐานต่อไปนี้ใน JavaScript
ประเภทคำอธิบาย
ประเภทที่ไม่ได้กำหนดที่กำหนดมีค่าเดียวที่ไม่ได้กำหนดซึ่งเป็นค่าเมื่อไม่ได้กำหนดตัวแปร
ประเภท nullnull ยังมีค่า null เพียงค่าเดียวมันเป็นข้อมูลอ้างอิงวัตถุที่ว่างเปล่า
Booleanboolean มีสองค่า: จริงและเท็จ
สตริงแสดงข้อมูลข้อความ
หมายเลขมันแสดงถึงข้อมูลดิจิทัล
วัตถุมันเป็นคอลเลกชันที่ไม่มีการเรียงลำดับของชุดคุณสมบัติรวมถึงฟังก์ชั่นฟังก์ชั่นและอาร์เรย์อาร์เรย์
เป็นไปไม่ได้ที่จะตัดสินฟังก์ชั่นและอาร์เรย์โดยใช้ typeof ที่นี่เราใช้ Object.prototype.toString Method
[โดยค่าเริ่มต้นแต่ละวัตถุจะสืบทอดจากวัตถุไปยังวิธี TOSTRING () หากวิธีนี้ไม่ได้เขียนทับ (บล็อก) ด้วยวิธีชื่อเดียวกันบนวัตถุเองหรือต้นแบบบนที่ใกล้กว่าวิธีการ toString () ของวัตถุจะถูกเรียกและประเภทสตริงที่นี่แสดงถึงประเภทวัตถุ] [1]
ประเภทฟังก์ชัน (obj) {var toString = object.prototype.toString; var map = {'[object boolean]': 'boolean', '[หมายเลขวัตถุ]': 'number', '[สตริงวัตถุ]': 'สตริง', '[ฟังก์ชันวัตถุ]': 'ฟังก์ชั่น', '[อาร์เรย์วัตถุ]': 'อาร์เรย์', ' 'null', '[Object Object]': 'Object'}; กลับแผนที่ [toString.call (obj)];}ใช้ DeepClone
สำหรับค่าตัวเลขของประเภทค่าที่ไม่ได้รับการอ้างอิงค่าจะถูกกำหนดโดยตรงและสำหรับประเภทค่าที่อ้างอิง (วัตถุ) คุณต้องข้ามอีกครั้งและกำหนดซ้ำ
ฟังก์ชั่น DeepClone (data) {var t = type (data), o, i, ni; if (t === 'array') {o = []; } อื่นถ้า (t === 'object') {o = {}; } else {return data; } if (t === 'array') {สำหรับ (i = 0, ni = data.length; i <ni; i ++) {o.push (deepclone (data [i])); } return o; } อื่นถ้า (t === 'object') {สำหรับ (i ในข้อมูล) {o [i] = deepClone (data [i]); } return o; -มีจุดหนึ่งที่ทุกคนควรให้ความสนใจ สำหรับประเภทฟังก์ชั่นบล็อกเกอร์กำหนดค่าโดยตรงหรือแบ่งปันค่าหน่วยความจำ นี่เป็นเพราะฟังก์ชั่นเกี่ยวกับการทำฟังก์ชั่นบางอย่างด้วยค่าอินพุตและค่าส่งคืนและสำหรับบริการระดับบนพวกเขาจะทำหน้าที่ทางธุรกิจให้เสร็จสมบูรณ์มากขึ้นและไม่จำเป็นต้องคัดลอกฟังก์ชั่นอย่างลึกซึ้ง
แต่จะคัดลอกประเภทฟังก์ชั่นได้อย่างไร?
ในความเป็นจริงบล็อกเกอร์คิดว่าจะใช้ใหม่เพื่อใช้งาน แต่ฟังก์ชั่นจะถูกดำเนินการครั้งเดียวและฉันไม่กล้าจินตนาการว่าผลการดำเนินการจะเป็นอย่างไร! o (□) o! ฉันยังไม่มีความคิดที่ดีโปรดให้คำแนะนำ!
ณ จุดนี้สำเนาลึกเกือบเสร็จแล้ว แต่บางคนคิดว่าทำไมสำเนาตื้นจึงไม่ถูกนำไปใช้?
สำเนาตื้น?
สำหรับสำเนาตื้นสามารถเข้าใจได้ว่าใช้พื้นที่หน่วยความจำทั่วไปเพียงแห่งเดียวเท่านั้น! จะมีอันตรายที่นี่! -
หากคุณใช้งานข้อมูลที่ใช้ร่วมกันนี้โดยตรงโดยไม่ต้องควบคุมข้อมูลข้อยกเว้นข้อมูลมักจะเกิดขึ้นและมีการเปลี่ยนแปลงโดยส่วนอื่น ๆ ดังนั้นคุณไม่ควรใช้แหล่งข้อมูลโดยตรงจัดหาวิธีการบางอย่างเพื่อดำเนินการ CULD บนข้อมูล
มันอาจจะเกือบจะเหมือนกันที่นี่ แต่เป็นส่วนหน้าไม่เพียง แต่พิจารณา JavaScript เท่านั้น แต่ยังรวมถึง DOM เบราว์เซอร์ ฯลฯ
ประเภทองค์ประกอบ
มาดูรหัสต่อไปนี้จะส่งคืนอะไรในผลลัพธ์
Object.prototype.toString.call(document.getElementsByTagName('div')[0])
คำตอบคือ [Object htmldivelement]
บางครั้งเมื่อองค์ประกอบ DOM ถูกบันทึกไว้และหากคุณคัดลอกลึกโดยไม่ตั้งใจฟังก์ชั่นการคัดลอกลึกด้านบนขาดการตัดสินเกี่ยวกับองค์ประกอบองค์ประกอบ หากต้องการตัดสินองค์ประกอบองค์ประกอบให้ใช้อินสแตนซ์ของการตัดสิน เพราะสำหรับแท็กที่แตกต่างกัน ToString จะส่งคืนตัวสร้างที่สอดคล้องกับแท็กที่แตกต่างกัน
ประเภทฟังก์ชัน (obj) {var toString = object.prototype.toString; var map = {'[object boolean]': 'boolean', '[หมายเลขวัตถุ]': 'number', '[สตริงวัตถุ]': 'สตริง', '[ฟังก์ชันวัตถุ]': 'ฟังก์ชั่น', '[อาร์เรย์วัตถุ]': 'อาร์เรย์', ' 'null', '[Object Object]': 'Object'}; if (องค์ประกอบ OBJ instanceof) {return 'element'; } return map [toString.call (obj)];}วิธีอื่น?
การดำเนินการของ jQuery
สำหรับรายละเอียดโปรดดู https: //github.com/jquery/jqu ...
การดำเนินการเน้นย้ำ
สำหรับรายละเอียดโปรดดู https: //github.com/jashkenas/...
การใช้งาน Lodash
สำหรับรายละเอียดโปรดดู https: //github.com/lodash/lod ...
การใช้งาน JSON
คุณสามารถรับรู้สำเนาลึกโดยผ่าน json.stringify ครั้งแรกจากนั้น json.parse อย่างไรก็ตามประเภทข้อมูลรองรับประเภทตัวเลขพื้นฐานเท่านั้น
var obj = {a: 'a', b: function () {console.log ('b')}} // เมื่อ json.stringify ฟังก์ชั่นจะถูกกรอง json.stringify (obj) // "{" a ":" a "}"สรุป
ที่นี่เราสรุปสำเนาลึกและวิธีการใช้สำเนาลึก ในสถานการณ์ที่แตกต่างกันมีความจำเป็นที่จะต้องพิจารณาว่าจำเป็นต้องมีการคัดลอกลึกตามสถานการณ์ทางธุรกิจหรือไม่