npm i merge-anything
รวมวัตถุและประเภทอื่น ๆ ซ้ำ ๆ รองรับ TypeScript อย่างเต็มที่! การบูรณาการที่เรียบง่ายและเล็ก
ฉันสร้างแพ็คเกจนี้เพราะฉันลองใช้แพ็คเกจที่คล้ายกันจำนวนมากที่ทำการรวม / การรวมลึก / การกำหนดวัตถุแบบเรียกซ้ำ ฯลฯ แต่ทั้งหมดก็มีนิสัยแปลก ๆ และ ทั้งหมดก็ทำลายสิ่งที่พวกเขาไม่ควรทำลาย ... ?
ฉันกำลังมองหา:
Object.assign()
แต่ลึก อันสุดท้ายนี้สำคัญมาก! ใน JavaScript เกือบทุกอย่างเป็น object แน่นอน แต่ฉันไม่ต้องการให้ฟังก์ชันผสานพยายามผสานเช่น new Date()
สองอินสแตนซ์! ไลบรารีจำนวนมากใช้คลาสแบบกำหนดเองที่สร้างออบเจ็กต์ที่มีต้นแบบพิเศษ และออบเจ็กต์ดังกล่าวทั้งหมดจะเสียหายเมื่อพยายามรวมเข้าด้วยกัน ดังนั้นเราต้องระวัง!
Merge-anything จะรวมวัตถุและคุณสมบัติที่ซ้อนกัน แต่ตราบเท่าที่มันเป็น "วัตถุธรรมดา" ทันทีที่เสาย่อยไม่ใช่ "วัตถุธรรมดา" และมีต้นแบบพิเศษ มันจะคัดลอกอินสแตนซ์นั้นไป "ตามที่เป็น"
import { merge } from 'merge-anything'
const starter = { name : 'Squirtle' , types : { water : true } }
const newValues = { name : 'Wartortle' , types : { fighting : true } , level : 16 }
const evolution = merge ( starter , newValues , { is : 'cool' } )
// returns {
// name: 'Wartortle',
// types: { water: true, fighting: true },
// level: 16,
// is: 'cool'
// }
ในตัวอย่างด้านบน หากคุณใช้ TypeScript และเลื่อนเมาส์ไปวางเหนือ evolution
คุณจะเห็นประเภทของออบเจ็กต์ใหม่ของคุณได้ทันที สิ่งนี้ทรงพลังมาก เพราะคุณสามารถรวมสิ่งต่าง ๆ ได้ และโดยไม่จำเป็นต้อง any
TypeScript จะรู้ได้อย่างแน่ชัดว่าออบเจ็กต์ที่รวมใหม่ของคุณมีลักษณะอย่างไร!
ประเภทการส่งคืนของฟังก์ชัน merge()
สามารถใช้เป็นยูทิลิตี้ TypeScript ได้เช่นกัน:
import type { Merge } from 'merge-anything'
type A1 = { name : string }
type A2 = { types : { water : boolean } }
type A3 = { types : { fighting : boolean } }
type Result = Merge < A1 , [ A2 , A3 ] >
แพ็คเกจนี้จะวนซ้ำผ่านวัตถุธรรมดาและรวมค่าเข้ากับวัตถุใหม่
โปรดทราบว่าแพ็คเกจนี้รู้จักอ็อบเจ็กต์ JavaScript พิเศษ เช่น คลาสอินสแตนซ์ ในกรณีเช่นนี้ มันจะไม่รวมพวกมันแบบวนซ้ำเหมือนออบเจ็กต์ แต่กำหนดคลาสให้กับออบเจ็กต์ใหม่ "ตามสภาพ"!
// all passed objects do not get modified
const a = { a : 'a' }
const b = { b : 'b' }
const c = { c : 'c' }
const result = merge ( a , b , c )
// a === {a: 'a'}
// b === {b: 'b'}
// c === {c: 'c'}
// result === {a: 'a', b: 'b', c: 'c'}
// However, be careful with JavaScript object references with nested props. See below: A note on JavaScript object references
// arrays get overwritten
// (for "concat" logic, see Extensions below)
merge ( { array : [ 'a' ] } , { array : [ 'b' ] } ) // returns {array: ['b']}
// empty objects merge into objects
merge ( { obj : { prop : 'a' } } , { obj : { } } ) // returns {obj: {prop: 'a'}}
// but non-objects overwrite objects
merge ( { obj : { prop : 'a' } } , { obj : null } ) // returns {obj: null}
// and empty objects overwrite non-objects
merge ( { prop : 'a' } , { prop : { } } ) // returns {prop: {}}
ผสานทุกอย่างอย่างเหมาะสมทำให้วัตถุพิเศษไม่เสียหาย เช่น วันที่, regex, ฟังก์ชัน, อินสแตนซ์ของคลาส ฯลฯ
อย่างไรก็ตาม จำเป็นอย่างยิ่ง ที่คุณจะต้องเข้าใจวิธีแก้ไขการอ้างอิงออบเจ็กต์ JavaScript โปรดอย่าลืมอ่าน #a หมายเหตุเกี่ยวกับการอ้างอิงออบเจ็กต์ JavaScript ด้านล่าง
ลักษณะการทำงานเริ่มต้นคืออาร์เรย์จะถูกเขียนทับ คุณสามารถนำเข้า mergeAndConcat
ได้หากคุณต้องการต่ออาร์เรย์เข้าด้วยกัน แต่อย่ากังวลหากคุณไม่ต้องการสิ่งนี้ ไลบรารีนี้สามารถสั่นไหวแบบต้นไม้ได้และจะไม่นำเข้าโค้ดที่คุณไม่ได้ใช้!
import { mergeAndConcat } from 'merge-anything'
mergeAndConcat (
{ nested : { prop : { array : [ 'a' ] } } } ,
{ nested : { prop : { array : [ 'b' ] } } }
)
// returns { nested: { prop: { array: ['a', 'b'] } } },
อาจมีบางครั้งที่คุณต้องปรับแต่งตรรกะเมื่อมีการรวมสองสิ่งเข้าด้วยกัน คุณสามารถจัดเตรียมฟังก์ชันที่คุณกำหนดเองซึ่งจะถูกทริกเกอร์ทุกครั้งที่มีการเขียนทับค่า
สำหรับกรณีนี้ เราใช้ mergeAndCompare
นี่คือตัวอย่างที่มีฟังก์ชันการเปรียบเทียบที่เชื่อมสตริงเข้าด้วยกัน:
import { mergeAndCompare } from 'merge-anything'
function concatStrings ( originVal , newVal , key ) {
if ( typeof originVal === 'string' && typeof newVal === 'string' ) {
// concat logic
return ` ${ originVal } ${ newVal } `
}
// always return newVal as fallback!!
return newVal
}
mergeAndCompare ( concatStrings , { name : 'John' } , { name : 'Simth' } )
// returns { name: 'JohnSmith' }
หมายเหตุสำหรับผู้ใช้ TypeScript ประเภทที่ส่งคืนโดยฟังก์ชันนี้อาจไม่ถูกต้อง ในกรณีนั้นคุณจะต้องส่งผลลัพธ์ไปยังอินเทอร์เฟซที่คุณจัดเตรียมไว้
ระวังการอ้างอิงวัตถุ JavaScript คุณสมบัติใด ๆ ที่ซ้อนกันจะเกิดปฏิกิริยาและเชื่อมโยงระหว่างวัตถุดั้งเดิมและวัตถุที่รวมเข้าด้วยกัน! ด้านล่างนี้เราจะแสดงวิธีป้องกันสิ่งนี้
const original = { airport : { status : 'dep. ?' } }
const extraInfo = { airport : { location : 'Brussels' } }
const merged = merge ( original , extraInfo )
// we change the status from departuring ? to landing ?
merged . airport . status = 'lan. ?'
// the `merged` value will be modified
// merged.airport.status === 'lan. ?'
// However `original` value will also be modified!!
// original.airport.status === 'lan. ?'
กฎสำคัญที่ต้องจำคือ:
คุณสมบัติใดๆ ที่ซ้อนกันมากกว่า 1 ระดับโดยไม่มีคุณสมบัติหลักที่ทับซ้อนกันจะถูกเปิดใช้งานและเชื่อมโยงทั้งในผลลัพธ์การรวมและแหล่งที่มา
อย่างไรก็ตาม มีวิธีแก้ปัญหาที่ง่ายมาก เราสามารถคัดลอกผลการผสานเพื่อกำจัดปฏิกิริยาใดๆ ได้ สำหรับสิ่งนี้ เราสามารถใช้ไลบรารีการคัดลอกอะไรก็ได้ ไลบรารีนี้ยังช่วยให้แน่ใจว่า อินสแตนซ์ของคลาสพิเศษไม่เสียหาย ดังนั้นคุณจึงสามารถใช้งานได้โดยไม่ต้องกลัวว่าของจะพัง!
ดูวิธีที่เราผสานรวม 'คัดลอกอะไรก็ได้' ด้านล่าง:
import { copy } from 'copy-anything'
const original = { airport : { status : 'dep. ?' } }
const extraInfo = { airport : { location : 'Brussels' } }
const merged = copy ( merge ( original , extraInfo ) )
// we change the status from departuring ? to landing ?
merged . airport . status = 'lan. ?' ( merged . airport . status === 'lan. ?' ) (
// true
// `original` won't be modified!
original . airport . status === 'dep. ?'
) // true
จากนั้นคุณสามารถเล่นตำแหน่งที่คุณต้องการวางฟังก์ชัน copy()
ได้
Copy Anything รองรับ TypeScript อย่างสมบูรณ์!
แท้จริงแล้วเป็นเพียงการผ่านวัตถุแบบวนซ้ำและกำหนดค่าให้กับวัตถุใหม่ดังด้านล่าง อย่างไรก็ตาม มันถูกรวมไว้เพื่อให้มีพารามิเตอร์เพิ่มเติม ฯลฯ โค้ดด้านล่างนี้เป็นการบูรณาการขั้นพื้นฐาน ซึ่งจะทำให้คุณเข้าใจพื้นฐานวิธีการทำงาน
import { isPlainObject } from 'is-what'
function mergeRecursively ( origin , newComer ) {
if ( ! isPlainObject ( newComer ) ) return newComer
// define newObject to merge all values upon
const newObject = isPlainObject ( origin )
? Object . keys ( origin ) . reduce ( ( carry , key ) => {
const targetVal = origin [ key ]
if ( ! Object . keys ( newComer ) . includes ( key ) ) carry [ key ] = targetVal
return carry
} , { } )
: { }
return Object . keys ( newComer ) . reduce ( ( carry , key ) => {
const newVal = newComer [ key ]
const targetVal = origin [ key ]
// early return when targetVal === undefined
if ( targetVal === undefined ) {
carry [ key ] = newVal
return carry
}
// When newVal is an object do the merge recursively
if ( isPlainObject ( newVal ) ) {
carry [ key ] = mergeRecursively ( targetVal , newVal )
return carry
}
// all the rest
carry [ key ] = newVal
return carry
} , newObject )
}
* แน่นอนว่ามีความแตกต่างเล็กน้อยกับซอร์สโค้ดจริงเพื่อรับมือกับกรณีที่หายากและคุณสมบัติพิเศษ ซอร์สโค้ดจริงอยู่ที่นี่