如何创建新构造函数拦截原有构造函数并修改参数调用
拦截构造函数并修改参数的正确实现
你的核心需求是拦截构造函数调用、修改参数后再转发给原构造函数,但原来的代码存在两个关键问题:一是调用原构造函数时没有绑定正确的this(导致原构造函数的实例属性不会挂载到新实例上),二是没有维护原型链(新实例无法访问原构造函数原型上的方法)。下面给出几种适配不同场景的正确实现方式:
方案1:ES6+推荐方案(使用Reflect.construct)
这个方法能完美处理构造函数的new调用逻辑,同时正确维护原型链:
const obj = { a: function aConstructor(message) { this.message = message; }, b: function bConstructor(message) { this.text = message; } }; const obj2 = {}; _.each(obj, (OriginalConstructor, key) => { obj2[key] = function InterceptedConstructor(message) { // 按需求修改参数 if (message === null) { message = "MY CUSTOM MESSAGE"; } // 使用Reflect.construct调用原构造函数,确保this指向当前实例 return Reflect.construct(OriginalConstructor, [message], new.target); }; // 同步原型链,让实例能访问原构造函数原型上的方法 obj2[key].prototype = Object.create(OriginalConstructor.prototype); obj2[key].prototype.constructor = obj2[key]; }); // 测试用例 const a = new obj2.a(null); console.log(a.message); // 输出 "MY CUSTOM MESSAGE" console.log(a instanceof obj.a); // true,原型链继承正确
Reflect.construct的第三个参数new.target还能处理拦截构造函数被继承的场景,保证原型链的完整性。
方案2:ES6 Class简洁实现
如果你的运行环境支持ES6 Class,用extends继承原构造函数会更简洁,class会自动处理原型链:
const obj = { a: function aConstructor(message) { this.message = message; }, b: function bConstructor(message) { this.text = message; } }; const obj2 = {}; _.each(obj, (OriginalConstructor, key) => { obj2[key] = class extends OriginalConstructor { constructor(message) { // 先修改参数 if (message === null) { message = "MY CUSTOM MESSAGE"; } // 调用父类构造函数 super(message); } }; }); // 测试用例 const a = new obj2.a(null); console.log(a.message); // 输出 "MY CUSTOM MESSAGE" console.log(a instanceof obj.a); // true
方案3:ES5兼容方案
如果需要兼容ES5环境,可以手动处理实例创建和原型链:
const obj = { a: function aConstructor(message) { this.message = message; }, b: function bConstructor(message) { this.text = message; } }; const obj2 = {}; _.each(obj, (OriginalConstructor, key) => { obj2[key] = function InterceptedConstructor(message) { if (message === null) { message = "MY CUSTOM MESSAGE"; } // 创建继承自原构造函数原型的实例 const instance = Object.create(OriginalConstructor.prototype); // 绑定this到新实例,调用原构造函数 OriginalConstructor.call(instance, message); // 返回实例 return instance; }; // 同步原型链 obj2[key].prototype = OriginalConstructor.prototype; obj2[key].prototype.constructor = obj2[key]; }); // 测试用例 const a = new obj2.a(null); console.log(a.message); // 输出 "MY CUSTOM MESSAGE" console.log(a instanceof obj.a); // true
核心要点总结
- 必须确保原构造函数的
this指向新创建的实例,否则原构造函数的实例属性无法挂载到新对象上 - 必须维护原型链的一致性,保证拦截后的实例能继承原构造函数原型上的方法和属性
- 用
new调用拦截构造函数时,要保证返回的实例符合原构造函数的实例规范
内容的提问来源于stack exchange,提问作者Arbaz Siddiqui
相关产品推荐
相关产品推荐

