⛔️ Object.assign causing TypeError
Object.assign(target, ...sources) 裡面 source 物件的 methods 似乎不是可以任意寫的,當內部使用物件方法時,JS 引擎(還是 Node 環境❓)竟然會檢查型別❗️
下面的範例用了三個方法來產生一個二維陣列的「最長列長」:
- ✅ 使用全域函數 (global functions) 
- ✅ 使用 Object.defineProperty() 
- ❌ 使用 Object.assign() 
但用最後一種方法 (mixin) 會出問題❗️
💊 解藥: .assignDescriptors()
// Array.prototype + .max(), .maxRowLength (by Object.assign)
Object.assign(Array.prototype, {
    // max something in the array
    max(mapf = (x) => x) {
        // -----------------------------------------
        return Math.max(...this.map(x => mapf(x)));
        //                 ^^^^^^^^
        // ⛔ TypeError: this.map is not a function
        // -----------------------------------------
    },
    // max row length of the matrix
    get maxRowLength() {
        return this.max(row => row.length);
    },
});
// matrix (2D array)
let m = [[1, 2, 3, 4], [1, 2], [1, 2, 3]];
m.max(row => row.length)    
m.maxRowLength- explanation: replit 
// ------------------------------------------------------------
// ⭐ `Object.assign()` copies with "get/set" operations, so if 
// • source object has a getter method, or 
// • target object has a setter method
// ⭐ they will be INVOKED❗, NOT COPIED❗.
// ------------------------------------------------------------
// the "source" object
let s = {
    // ⭐ function copied ✅
    max(mapf = (x) => x) {
        return Math.max(...this.map(x => mapf(x)));
        //                 ^^^^^^^^
        // ⛔ TypeError: this.map is not a function
    },
    // ⭐ getter invoked❗, NOT COPIED❗(during the assign❗)
    get maxRowLength() {
        return this.max(row => row.length);
    },
};
// ⭐ during `Object.assign`:
// ---------------------------------------------
// (function copied ✅)
// • t.max = t.max 
//   
// (source getter invoked❗, NOT COPIED❗)
// • t.maxRowLength =   s.maxRowLength
//                   ╰⭐ getter invoked ╯
//
//   => return this.max(...)                  // ⭐ this === s
//       => return Math.max(...this.map(...)) // ⛔ `s.map` is not a function
//                             ^^^^^^^^
// ⛔ TypeError: this.map is not a function
let t = Object.assign(Array.prototype, s);    // the "target" object
// matrix
let m = [[1, 2, 3, 4], [1, 2], [1, 2, 3]];    // can't even reach here!// max something in the array
function arrayMax(arr, mapf = x => x){
    return Math.max(...arr.map(x => mapf(x)));
}
// max row length of the 2D array
// assuming an element in the 2D array is called a "row".
function maxRowLength(matrix){
    return arrayMax(matrix, row => row.length);
}
// 2D array
let m = [[1, 2, 3, 4], [1, 2], [1, 2, 3]];
arrayMax(m, row => row.length)     // 4 ✅
maxRowLength(m)                    // 4 ✅// Array.prototype + .max()
Array.prototype.max = function(f = x => x){
    return Math.max(...this.map(x => f(x)));
};
// Array.prototype + .maxRowLength (by Object.defineProperty)
Object.defineProperty(Array.prototype, 'maxRowLength', {
    get: function(){ return this.max(row => row.length) }
});
// matrix (2D array)
let m = [[1, 2, 3, 4], [1, 2], [1, 2, 3]];
m.max(row => row.length)    // 4 ✅
m.maxRowLength              // 4 ✅Last updated
Was this helpful?