在JavaScript中模拟'new'运算符

9 javascript

我尝试用这样的代码在JavaScript中模拟'new'运算符:

Function.method('new', function ( ) {
    var objPrototype = Object.create(this.prototype);
    var instance = this.apply(objPrototype, arguments);

    return instance;
});
Run Code Online (Sandbox Code Playgroud)

但是,为了涵盖所有情况,return语句应如下所示:

return (typeof instance === 'object' && instance ) || objPrototype;
Run Code Online (Sandbox Code Playgroud)

现在进行测试:

var SomeClass = function (param1, param2) {
    this.param1 = param1;
    this.param2 = param2;
};

var test1 = String.new('test1'); //in this case, the "instance" variable is an object
var test2 = SomeClass.new('test1', 'test2'); // in this case, the "instance" variable is undefined
Run Code Online (Sandbox Code Playgroud)

这正是"新"运算符的作用吗?还有什么案子可以解决吗?

Rob*_*b W 9

规格:

11.2.2 new操作符#

生产NewExpression:new NewExpression的计算方法如下:

  1. ref是评估NewExpression的结果.
  2. 构造函数GetValue(ref).
  3. 如果Type(构造函数)不是Object,则抛出TypeError异常.
  4. 如果构造函数没有实现[[Construct]]内部方法,则抛出TypeError异常.
  5. 返回调用上的[[构建]]内部方法的结果的构造,从而提供没有参数(即,自变量列表为空).

生成MemberExpression:new MemberExpression Arguments 的计算方法如下:

  1. ref成为评估MemberExpression的结果.
  2. 构造函数GetValue(ref).
  3. argList成为评估Arguments的结果,生成一个参数值的内部列表(11.2.4).
  4. 如果Type(构造函数)不是Object,则抛出TypeError异常.
  5. 如果构造函数没有实现[[Construct]]内部方法,则抛出TypeError异常.
  6. 返回调用上的[[构建]]内部方法的结果的构造,提供所述列表ARGLIST作为参数值.

在任何一种情况下,都正确遵循所有步骤:

var objPrototype = Object.create(this.prototype);    // 1-4 1-5
var instance = this.apply(objPrototype, arguments);  // 5   6
Run Code Online (Sandbox Code Playgroud)

兴趣点是2. 州
的规范[[construct]]:

当使用可能为空的参数列表调用Function对象F的[[Construct]]内部方法时,将执行以下步骤:

  • 让obj成为新创建的本机ECMAScript对象.
    . . .
  • 设result是调用F的[[Call]]内部属性的结果,将obj作为this值提供,并将传递给[[Construct]]的参数列表作为args.
  • 如果Type(result)是Object,则返回结果.
  • 返回obj.

typeof obj返回"object"null,而null不是一个对象.但是,由于这null是一个虚假值,您的代码也可以按预期工作:

return (typeof instance === 'object' && instance ) || objPrototype;
Run Code Online (Sandbox Code Playgroud)

  • 实际上,当构造函数返回一个函数对象时,代码是错误的,`typeof`也不能正常工作.更好:`return(Object(instance)=== instance)?实例:objPrototype)` (2认同)

Abi*_*bid 7

new运营商需要一个功能Farguments:new F(arguments...).它有三个简单的步骤:

  1. 创建类的实例.它是一个空属性,其 __proto__属性设置为F.prototype.初始化实例.

  2. 使用传递的参数调用函数F,并将其设置为实例.

  3. 返回实例

现在我们了解了new运算符的作用,我们可以在Javascript中实现它.

    function New (f) {
/*1*/  var n = { '__proto__': f.prototype };
       return function () {
/*2*/    f.apply(n, arguments);
/*3*/    return n;
       };
     }
Run Code Online (Sandbox Code Playgroud)

只是一个小测试,看它是否有效.

function Point(x, y) {
  this.x = x;
  this.y = y;
}
Point.prototype = {
  print: function () { console.log(this.x, this.y); }
};

var p1 = new Point(10, 20);
p1.print(); // 10 20
console.log(p1 instanceof Point); // true

var p2 = New (Point)(10, 20);
p2.print(); // 10 20
console.log(p2 instanceof Point); // true
Run Code Online (Sandbox Code Playgroud)