跳到主要內容

JavaScript : How to copy properties of objects into another object ?


有時候我們可能會想要將某一個物件的屬性複製到另一個物件,所以我們可能會寫出像下面這樣的程式碼。

    let order = {
      OrderID: 'A001',
      OrderDate: '2018-10-14'
    };
    let items = [
        { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
        { ItemName: '鉛筆', Price: 10, Quantity: 10 }
      ];
    order.Items = items;
    // Output :
    // {
    //   OrderID: 'A001',
    //   Items: [
    //     { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
    //     { ItemName: '鉛筆', Price: 10, Quantity: 10 }
    //   ],
    //   OrderDate: '2018-10-14'
    // }
如果我們有很多的屬性要做複製的話,向上面這樣的寫法實在太費時。
事實上,我們可以使用Object.assign()來輕鬆地完成這件事,它用於複製一個或多個物件,將它們所有可列舉的屬性到另一個目標物件。

    let order = {
      OrderID: 'A001',
      OrderDate: '2018-10-14'
    };
    let items = [
        { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
        { ItemName: '鉛筆', Price: 10, Quantity: 10 }
      ];  
    let customer = {
       CustomerID : 'C001'
    };
    Object.assign(order,{Items:items},customer);
    // Output :
    // {
    //   OrderID: 'A001',
    //   CustomerID = 'C001',
    //   Items: [
    //     { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
    //     { ItemName: '鉛筆', Price: 10, Quantity: 10 }
    //   ],
    //   OrderDate: '2018-10-14'
    // }
或者,是當我們要將陣列或是字串內的元素複製到另一個陣列或是物件,我們也可以使用Object.assign()

    Object.assign([], [100, 200, 300]);
    // Output : [100, 200, 300]

    Object.assign({}, [100, 200, 300]);
    // Output : {100, 200, 300}

    Object.assign([], 'ABC');
    // Output : ['A','B','C']

    target = Object.assign({}, 'ABC');
    // Output : {'A','B','C'}
以上是Object.assign()的基本應用方式。
另外,在使用Object.assign()需要特別注意的事,就是Object.assign()它是淺層複製。 例如以下例子,由於Object.assign()是淺層複製,它只複製參考,所以source也會跟著被改變,故Price為100。

    let target = {};
    const source = {
      OrderID: 'A001',
      Items: [
        { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
        { ItemName: '鉛筆', Price: 10, Quantity: 10 }
      ]
    };
    Object.assign(target, source);
    for (const i of target.Items) {
      i.Price = 100;
    }
    // Source Output :
    // {
    //  OrderID: 'A001',
    //  Items: [
    //    { ItemName: '橡皮擦', Price: 100, Quantity: 10 },
    //    { ItemName: '鉛筆', Price: 100, Quantity: 10 }
    //  ]
    // }
    // Target Output :
    // {
    //  OrderID: 'A001',
    //  Items: [
    //    { ItemName: '橡皮擦', Price: 100, Quantity: 10 },
    //    { ItemName: '鉛筆', Price: 100, Quantity: 10 }
    //  ]
    // }
如果我們想要同時能夠複製物件屬性又能夠達到深層複製效果,那我們可以使用Lodash的_.merge方法來達成這件事。 如下面的例子使用_.merge後,source和target都是完全獨立的實體,所以不會互相干涉。

    let target = {};
    const source = {
      OrderID: 'A001',
      Items: [
        { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
        { ItemName: '鉛筆', Price: 10, Quantity: 10 }
      ]
    };
    _.merge(target, source);
    for (const i of target.Items) {
      i.Price = 100;
    }
    // Source Output :
    // {
    //  OrderID: 'A001',
    //  Items: [
    //    { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
    //    { ItemName: '鉛筆', Price: 10, Quantity: 10 }
    //  ]
    // }
    // Target Output :
    // {
    //  OrderID: 'A001',
    //  Items: [
    //    { ItemName: '橡皮擦', Price: 100, Quantity: 10 },
    //    { ItemName: '鉛筆', Price: 100, Quantity: 10 }
    //  ]
    // }
還有一件要注意的事,當target和source有相同屬性時,target的屬性值會被source給覆蓋掉。 如下面的例子,target的OrderID值會是'A002'。

    let target = {
      OrderID: 'A001',
      Items: [
        { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
        { ItemName: '鉛筆', Price: 10, Quantity: 10 }
      ]
    }
    const source = { 
      OrderID: 'A002',
      OrderDate: '2018-10-14' 
    };
     Object.assign(target, source);
    // Target Output :
    // {
    //  OrderID: 'A002',
    //  Items: [
    //    { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
    //    { ItemName: '鉛筆', Price: 10, Quantity: 10 }
    //  ]
    // }
假如我們想要當target和source有相同屬性時,target的值不被覆蓋掉,我們可以使用Lodash的_.defaults或_.defaultsDeep方法。 如下面的例子,target的OrderID值仍會是'A001'。

    let target = {
      OrderID: 'A001',
      Items: [
        { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
        { ItemName: '鉛筆', Price: 10, Quantity: 10 }
      ]
    }
    const source = { 
      OrderID: 'A002',
      OrderDate: '2018-10-14' 
    };
     _.defaultsDeep(target, source);
    // Target Output :
    // {
    //  OrderID: 'A001',
    //  Items: [
    //    { ItemName: '橡皮擦', Price: 15, Quantity: 10 },
    //    { ItemName: '鉛筆', Price: 10, Quantity: 10 }
    //  ]
    // }

留言

這個網誌中的熱門文章

reCAPTCHA v3 的簡單教學

Google於10/29正式發布reCAPTCHA v3 API,該版本中最大的亮點就是透過分析使用者瀏覽網站的行為,以辨識使用者是否為機器人。換句話說,使用者再也不用一直回答問題和不停地點選圖片,所以說以後再也不用聽到客戶抱怨老是點錯圖片,果然科技始於人性啊~ 另外reCAPTCHA v3 的使用方式也非常簡單,只要短短幾個步驟,就能輕鬆地將reCAPTCHA v3運用在專案中。 1. 首先,至  https://www.google.com/recaptcha/admin  替你的網站註冊一個reCAPTCHA。 2. 註冊後,將會得到Site Key和Secret Key,其中Site Key是給前端使用,而Secret Key則是給後端使用。 3. 在前端HTML head的部分加入reCAPTCHA的api.js。 <script src='https://www.google.com/recaptcha/api.js?render=6Lc5vHgUAAAAAKHxlH0FdDJdA2-8yfzpoMDLIWPc'></script> 4. 接著在body的部分呼叫reCAPTCHA API向Google取得token後,再將token送至後端進行驗證,範例如下: <script> grecaptcha.ready(function () { console.log('1. grecaptcha.ready'); console.log('2. grecaptcha.execute("6Lc5vHgUAAAAAKHxlH0FdDJdA2-8yfzpoMDLIWPc", { action: "@Url.Action("VerifyBot", "Account")" })'); grecaptcha.execute('6Lc5vHgUAAAAAKHxlH0FdDJdA2-8yfzpoMDLIWPc', { action: '@

MongoDB: Save Files Using GridFS

過去我們在使用File System,我們必須自己處理備份、複製、擴充的問題;如今我們可以我們可以使用MongoDB作為File DB,它可以利用Replica和Sharing的機制幫助我們解決備份、複製、動態擴充、分散式儲存、自動平衡、故障回復的問題,且效能優於RDBMS。若真要說MongoDB這類NoSql的缺點就是它不能處理Transaction。 在MongoDB中對大於16MB BSON Document(如:圖片、音頻、影片等)是使用GridFS的方式做儲存。 GridFS是一種在MongoDB中存儲大二進製文件的機制,GridFS 會將文件分割成多個Chunk(預設256 KB),而GridFS使用fs.files和fs.chunks等兩個Collection來存儲檔案資料,其中fs.files負責存放文件的名稱、大小、上傳的時間等資訊,而fs.chunks則是負責存放經過分割後的Chunks,其優點是透過分割儲存的方式能夠快速讀取檔案中任何的片段。 fs.files Collection { "_id" : , // 檔案的Unique ID "filename": data_string, //檔案名稱 "length" : data_number, // 檔案大小 "chunkSize" : data_number, // chunk大小,預設256k "uploadDate" : data_date, // 儲存時間 "md5" : data_string //檔案的md5值 } fs.chunks Collection { "_id" : , // 檔案chunk的Unique ID "files_id" : , //對應檔案的Unique ID "n" : chunk_number, // 檔案chunk的數量 "data" : data_binary, // 以二進為儲存檔案 } 在下面例子,我們將簡單地示範使用.NET MongoDB Driver來存取與操作MongoDB的G

Upload large files to web api using resumable.js

最近工作剛好遇到大檔案(> 2GB)上傳的需求,大檔案的上傳方式與平常處裡小檔案上傳當方式有些不同,對於大檔案上傳我們需要額外考量三個問題 : 1. 上傳逾時。 2  IIS 不支援超過2BG 的檔案上傳 3. 檔案在上傳過程中中斷。 上述這三個問題可以透過multipart/form-data和chuck 的方式,將檔案分割成無數個chunk,且給予每個chunk編號,如果傳送失敗就重新傳送chunk ,進而實現斷點續傳的功能。 目前市面三個有支援大檔案與斷點續傳的JavaScript Library分別有 Resumable.js 、 Dropzone.js 、jQuery Ajax File Upload,且它們底層皆是使用HTML5 File API,此外它們的作者都有提供Server Side Implementation Sample,而且連TypeScript的定義檔都有,真的都是佛心來著。 接著我們開始介紹如何使用Resumable.js 上傳檔案至Web API(.NET) : Server Side (Web API)的主要流程: 1. 首先,在Web API需要使用MultipartFormDataStreamProvider來取得每一次Resumable.js 所傳過來的chunk,而chunk由FormData和FileData組成,其中FormData記載Resumable.js所定義的chuck欄位,而FileData則存放chunk的檔案內容。 2. 接著從FormData得到這些Resumable.js所定義的chuck欄位resumableFilename、resumableIdentifier、resumableTotalChunks、resumableChunkNumber欄位,並且根據這些欄位我們將chunk儲存在Upload 目錄下。 3. 等待所有chunk都到位,將合併這些chunk並組成完整的檔案。 FileStorageController Class [RoutePrefix("api/FileStorage")] public class FileStorageController : ApiController {