Object.assign扩展Array.prototype报this.map非函数TypeError原因
核心差异与报错原因解析
两种Array.prototype扩展方案的核心差异
两种方案的本质区别是对属性(尤其是访问器属性getter/setter)的复制、挂载逻辑完全不同:
Object.assign方案:只会读取源对象所有可枚举自有属性的值,再写入目标对象,不会复制属性的底层描述符。遇到源对象上的getter,会在复制阶段立即执行getter拿到返回值,再把返回值作为普通数据属性写到目标上,根本不会把getter本身挂载到目标对象。同时该方法复制的属性默认都是可写、可枚举、可配置的。- 直接赋值+
Object.defineProperty方案:直接给原型赋值方法,是把函数作为普通数据属性挂载;defineProperty可以精确配置属性的底层描述符,能把getter/setter逻辑完整挂载到目标对象上,不会提前触发getter执行。如果不手动指定属性配置项,该方法定义的属性默认是不可写、不可枚举、不可配置的。
Object.assign方案报错的根本原因
报错根本不是发生在后续调用m.max()的阶段,而是Object.assign(Array.prototype, {...})执行的瞬间就触发了错误,完整触发流程如下:
- 传入Object.assign的第二个参数是普通对象字面量,其中
maxRowLength是用get语法定义的访问器属性。 - Object.assign处理到
maxRowLength属性时,不会把这个getter挂载到Array.prototype上,而是先在源对象字面量的上下文里执行这个getter,准备拿到返回值后再赋值给Array.prototype。 - 此时getter内部的
this指向的是源对象字面量本身(一个普通Object实例,不是数组),执行到this.max(row => row.length)时,会调用源对象自有的max方法,max方法内部的this依然指向这个普通对象。 - 普通对象没有数组原型上的
map方法,执行到this.map(...)时直接抛出TypeError: this.map is not a function,整个Object.assign执行中断,后续的测试代码自然无法运行。
补充:一次性挂载方法和getter的正确写法
Object.assign本身不支持复制访问器描述符,如果要实现批量挂载包含getter/setter的属性,可以用属性描述符相关API实现:
Object.defineProperties( Array.prototype, Object.getOwnPropertyDescriptors({ max(mapf = (x) => x) { return Math.max(...this.map(x => mapf(x))); }, get maxRowLength() { return this.max(row => row.length); } }) );
这种写法会把源对象的所有属性描述符(包括getter、可枚举性等配置)完整复制到Array.prototype上,不会提前触发getter执行,和手动实现的第二种方案效果一致。
内容的提问来源于stack exchange,提问作者lochiwei
相关产品推荐
相关产品推荐

