模拟';新';JavaScript中的运算符
我试着用如下代码在JavaScript中模拟“new”操作符:模拟';新';JavaScript中的运算符,javascript,Javascript,我试着用如下代码在JavaScript中模拟“new”操作符: Function.method('new', function ( ) { var objPrototype = Object.create(this.prototype); var instance = this.apply(objPrototype, arguments); return instance; }); return (typeof instance === 'object' &&
Function.method('new', function ( ) {
var objPrototype = Object.create(this.prototype);
var instance = this.apply(objPrototype, arguments);
return instance;
});
return (typeof instance === 'object' && instance ) || objPrototype;
但是,为了涵盖所有情况,return语句应该如下所示:
Function.method('new', function ( ) {
var objPrototype = Object.create(this.prototype);
var instance = this.apply(objPrototype, arguments);
return instance;
});
return (typeof instance === 'object' && instance ) || objPrototype;
现在进行测试:
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
“新”运营商就是这么做的吗?还有什么需要说明的吗?新的
操作符接受函数F
和参数:新的F(参数…
。它有三个简单的步骤:
创建类的实例。它是一个空对象,具有
\uuuu proto\uuu
属性设置为F.prototype
。初始化实例
使用传递的参数调用函数F,并将其设置为
就是这样
返回实例
现在我们了解了新操作符的功能,可以用Javascript实现它了
function New (f) {
/*1*/ var n = { '__proto__': f.prototype };
return function () {
/*2*/ f.apply(n, arguments);
/*3*/ return n;
};
}
只是一个小测试,看看它是否有效
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
从:
11.2.2新操作员
生产新表达式:new
NewExpression的计算如下:
设ref为计算NewExpression的结果
设构造函数为(ref)
如果(构造函数)不是对象,则引发异常
如果构造函数未实现[[Construct]]内部方法,则引发异常
返回对构造函数调用[[Construct]]内部方法的结果,但不提供任何参数(即参数的空列表)
生产成员表达式:new
MemberExpression参数
评估结果如下:
设ref为计算MemberExpression的结果
设构造函数为(ref)
让argList作为参数求值的结果,生成参数值的内部列表()
如果(构造函数)不是对象,则引发异常
如果构造函数未实现[[Construct]]内部方法,则引发异常
返回对构造函数调用[[Construct]]内部方法的结果,并提供列表argList作为参数值
在任何一种情况下,均正确遵循所有步骤:
var objPrototype = Object.create(this.prototype); // 1-4 1-5
var instance = this.apply(objPrototype, arguments); // 5 6
兴趣点是2。
国家:
当函数对象F的[[Construct]]内部方法为
使用可能为空的参数列表调用,请执行以下步骤
采取的措施如下:
- 将obj设为新创建的本机ECMAScript对象。
代码>
- 让result是调用F的[[Call]]内部属性的结果,提供obj作为this值的值并提供参数列表
作为参数传递到[[Construct]]
- 如果(结果)是对象,则返回结果
- 返回obj
typeof obj
为null
返回的“对象”
,而null
不是对象。但是,由于null
是一个虚假值,因此您的代码也可以按预期工作:
return (typeof instance === 'object' && instance ) || objPrototype;
以下是使用该方法的替代方法。这与OP最初的开始方式一致
function New(fn) {
var newObj = Object.create(fn.prototype);
return function() {
fn.apply(newObj, arguments);
return newObj;
};
}
这是一种更干净的方法,而且它也通过了原型链测试。这里的答案对于标准ES5都是有效的,当它们被编写时就已经存在,但它们不是在所有ES6环境下都能工作的通用解决方案,所以我想对它们进行扩展。简而言之,问题的代码是:
Function.method('new', function ( ) {
var objPrototype = Object.create(this.prototype);
var instance = this.apply(objPrototype, arguments);
return instance;
});
在标准ES6环境中,是否可以更好地实现
Function.method('new', function ( ) {
return Reflect.construct(this, arguments);
});
这无疑简化了事情
Reflect.construct
是作为Proxy
系统的一部分引入ES6的,但它有类似于这种情况的一般用途
现在这是首选方法的原因很简单,.apply
不再适用于所有类型的函数。说明new
调用内部语言函数[[Construct]]
来初始化参数。使用.apply
的方法实质上取代了[[Construct]]
中处理的自动对象创建和调用逻辑,而是手动创建对象,然后调用函数,该函数使用内部方法而不是[[Construct]]
对函数的调用是ES6中更改的一部分。在ES5中,您将要构造的几乎是一个普通的函数Foo(){}
值,因此您可以对此进行假设。在ES6中,引入了类Foo{}
语法,并且由类语法创建的构造函数有更多的限制,因此关于ES5的假设不适用。最重要的是,ES6类被明确禁止使用[[Call]]
。执行以下操作将引发异常:
class Foo {}
Foo();
这与.call
和.apply
的问题相同。它们不是函数构造函数,而是函数调用函数。因此,如果您试图在ES6类上使用它们,它们将抛出异常
Reflect.construct
通过实际调用[[construct]]
而不是[[Call]]]
来避免这些问题,而是通过一个无需新建即可使用的API来公开它。。。使用新的接线员怎么样?这看起来有点像是一个相当旧的轮子的翻版。是的。但我仍然想确切地了解幕后发生了什么。出于教育目的?公平地说…只是玩弄继承可能的JavaScript副本,当涉及到新的操作符时,它与ECMASCript 100%兼容。谢谢你的回答!这个答案忘记了当This.prototype
不是ES对象时的情况。值null
将被对象接受。create
,尽管它应该使用Object.prototype
。实际上,当构造函数返回一个函数对象时,代码是错误的,而typeof
不接受该对象