如何使用函数
myNew
模拟“新”运算符?尝试了一切,但我无法让它工作。
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
}
function myNew(){
var obj = Object.create(Object.prototype);
var instance = this.apply(obj, arguments);
return instance;
}
var person = myNew(Person, 'Test');
console.log(person instanceof Person); // true
person.getName(); // Test
您可以使用
Reflect.construct
。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/construct
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
}
var person = Reflect.construct(Person, ['Test']);
console.log(person instanceof Person); // true
console.log(person.getName()); // Test
如果您想要不使用 Reflect.construct 的模拟,请尝试以下操作:
function myNew(constructor) {
var instance = Object.create(constructor.prototype)
var args = Array.from(arguments)
args.shift()
constructor.apply(instance, args)
return instance
}
如果支持ES6,可以写得更短为:
function myNew(constructor, ...args) {
var instance = Object.create(constructor.prototype)
constructor.apply(instance, args)
return instance
}
编辑:刚刚注意到 Array.from 在 ES6 中可用,但如果你想支持 ES5,你可以轻松模拟它
编辑2: 查看 new 运算符的 MDN 页面,我注意到我忘记了从构造函数创建对象的一个重要步骤。我使用的算法几乎与页面上解释的算法相同,除了关键部分:有些构造函数实际上返回某些内容(并非所有构造函数都返回
undefined
)。在这种情况下,返回的 object is 新表达式的评估。所以函数的最终形式(我希望)将是
function myNew(constructor, ...args) {
var instance = Object.create(constructor.prototype)
var obj = constructor.apply(instance, args)
if(obj instanceof Object) return obj
return instance
}
在 ECMAScript 6 中,如果你想编写一个可以调用任意函数作为带有任意参数的构造函数的函数,你可以只使用
new
和扩展语法:
const myNew = (cons, ...args) => new cons(...args);
当你无法使用新的ES6语法时,你可以求助于
Reflect.construct
:
function myNew(cons) {
var args = Array.prototype.slice.call(arguments, 1);
return Reflect.construct(cons, args);
}
当
Reflect.construct
和扩展语法都不可用时,这是eval
的适当用途之一:function myNew(cons) {
var args = new Array();
for (var i = 1; i < arguments.length; ++i)
args[i - 1] = 'arguments[' + i + ']';
return eval('new cons(' + args.join(',') + ');');
}
在到达最后一个之前,最好使用特征检测来机会性地使用
Reflect.construct
定义(如果可用),这样就可以避免
eval
的性能问题。 (也就是说,检查是否存在
Reflect.construct
来选择要使用的定义;不要将两个版本放在同一个函数中。)