您可以使用呼叫或与新申请
can you use call or apply with new?
与如何使用调用或应用调用javascript构造函数有关?
但不一样,我试图将 SO 答案应用于 John Resig 在未正确调用时强制构造函数。
function User(first, last){
if ( !(this instanceof User) )
// the line I want to replace, or remove the redundancy from:
return new User(first, last);
this.name = first + " " + last;
}
var name = "Resig";
var user = User("John", name);
assert( user, "This was defined correctly, even if it was by mistake." );
assert( name == "Resig", "The right name was maintained." );
目标代码行意味着每次构造函数更改时,都必须有人记住更改内部自调用参数。在过去的 3 天里,我已经就这个问题进行了 3 次项目旅行。
链接问题中的所有示例都谈到了传递constructor
,但是在这种情况下constructor
是什么?它甚至还没有完成定义。
但到目前为止,所有尝试都没有通过测试,或者抛出堆栈溢出。
如何确保被调用的构造函数即使在没有 new
关键字的情况下调用也能正确响应instanceof User
,同时消除参数参数的重复?
一些选项,全部使用 Object.create
:
选项 1:
function User(first, last){
var rv;
if ( !(this instanceof User) ) {
// They called us without `new`: Create an object backed by `User.prototype`:
rv = Object.create(User.prototype);
// Now, call this function applying the arguments
User.apply(rv, arguments);
// Return the object
return rv;
}
// Normal constructor stuff
this.name = first + " " + last;
}
当然,不必为您创建的每个构造函数重复所有这些逻辑,您可以使用帮助程序函数:
function constructWith(obj, ctor, args) {
if (obj instanceof ctor) {
return null;
}
obj = Object.create(ctor.prototype);
ctor.apply(obj, args);
return obj;
}
然后
function User(first, last){
var rv;
if ((rv = constructWith(this, User, arguments)) != null) {
return rv;
}
// Normal constructor stuff
this.name = first + " " + last;
}
选项 2:不要过多使用this
:
function User(first, last){
var rv;
if (this instanceof User) {
// They (probably) used `new`, all is good, use `this`
rv = this;
} else {
// They didn't use `new`, create an object backed by `User.prototype`
rv = Object.create(User.prototype);
}
// ...use `rv`, not `this`, from here on
rv.name = first + " " + last;
// This is important for the case where they didn't use `new`, and harmless
// in the case where they did.
return rv;
}
如您所见,这要简单得多,但是如果您真的喜欢语法突出显示(说真的,我有一个客户,this
跳出来真的很重要)等等......
当然,您可以将其包含在帮助程序中:
function useOrConstruct(obj, ctor) {
return obj instanceof ctor ? obj : Object.create(ctor.prototype);
}
然后
function User(first, last){
var rv = useOrConstruct(this, User);
// ...use `rv`, not `this`, from here on
rv.name = first + " " + last;
// This is important for the case where they didn't use `new`, and harmless
// in the case where they did.
return rv;
}
选项 3:constructOMatic
当然,如果我们要定义助手,也许我们应该全猪:
function User() {
return constructOMatic(this, User, arguments, function(first, last) {
this.name = first + " " + last;
});
}
。constructOMatic
在哪里:
function constructOMatic(obj, ctor, args, callback) {
var rv;
if (!(obj instanceof ctor)) {
obj = Object.create(ctor.prototype);
}
rv = callback.apply(obj, args);
return rv !== null && typeof rv === "object" ? rv : obj;
}
现在,您可以在回调中尽情使用this
。摆弄rv
与 最后return
obj
是模拟new
的行为(new
表达式的结果是由new
运算符创建的对象,除非构造函数返回非null
对象引用,在这种情况下优先)。
Object.create
是所有现代浏览器上的 ES5 功能,但上面使用的单参数版本可以用于过时的浏览器:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw "The two-argument version of Object.create cannot be shimmed.";
}
function ctor() { }
ctor.prototype = proto;
return new ctor; // Yes, you really don't need () (but put them on if you prefer)
};
}
复制和粘贴非常简单,代码很干净。你不需要改变它。
如果你接受eval
,你可以这样做:
function User(first, last){
if ( !(this instanceof arguments.callee) ) {
var name = arguments.callee.name;
var param = [].map.call(arguments,function(e,i){return 'arguments['+i+']';});
return eval('new '+name+'('+ param +')');
}
this.name = first + " " + last;
}
//test
var user1 = User("John", "Resig");
var user2 = new User("John", "Resig");
没有eval
,你可以这样做:
function instantiate(C,a){
switch(a.length){
case 0: return new C();
case 1: return new C(a[0]);
case 2: return new C(a[0],a[1]);
case 3: return new C(a[0],a[1],a[2]);
case 4: return new C(a[0],a[1],a[2],a[3]);
default : throw("too many arguments");
}
}
function User(first, last){
if ( !(this instanceof arguments.callee) ) {
return instantiate(arguments.callee, arguments);
}
this.name = first + " " + last;
}
//test
var user1 = User("John", "Resig");
var user2 = new User("John", "Resig");
在 ECMAScript 6 中,你可以使用 spread 运算符将带有 new 关键字的构造函数应用于参数数组:
"use strict";
function User(first, last){
if ( !(this instanceof User) ) {
return new User(...arguments);
}
this.name = first + " " + last;
}
- 创建一个类似链接的按钮,并通过Javascript函数打开一个新的弹出窗口
- 防止Iframe窗体在新窗口中打开
- 让文本输入幻灯片显示输入时的新文本输入?然后向后滑动
- 动态地改变“”的URL;添加新项目”;链接使用javascript/jquery
- Firebase迁移-简单的Firebase.set没有'不再工作了——旧的还是新的
- 通过js在新选项卡中有条件地打开url
- 使用jquery将mysql数据获取到新的表行中
- 触摸移动时切换到新元素
- 如何从rails中的代码中删除新行( )
- 拆分文本以每隔n个字符添加一行新行,并注意空格
- 操作员”;新的“;根据我想在几个JavaScript文件中使用的类,在JavaScript中使用
- chrome在WebSocket握手期间获取新错误
- AngularJs指令,该指令创建内部有数据对象的新指令
- 新选项卡被弹出窗口阻止程序阻止
- 将按钮添加到新元素中
- 创建新属性后的 JSON 空属性
- Javascript 新的 Array 和 join() 方法
- javascript处理一个对象数组以获得一个新的对象数组
- 如何在新选项卡中打开弹出窗口,但将用户保留在呼叫者选项卡上
- 您可以使用呼叫或与新申请