如何编写一个复制 `new` 运算符功能的函数?

问题描述 投票:0回答:3

如何使用函数

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

javascript constructor
3个回答
1
投票

您可以使用

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


0
投票

如果您想要不使用 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
}

0
投票

在 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 来选择要使用的定义;不要将两个版本放在同一个函数中。)

© www.soinside.com 2019 - 2024. All rights reserved.