如何从Javascript中使用new调用的构造函数返回null

How to return null from a constructor called with new in Javascript?

本文关键字:调用 构造函数 返回 null new Javascript      更新时间:2023-09-26

我试图使构造函数中止对象的建设,如果有什么失败,例如,它不能得到画布的控制。

但是当我使用new时,我看到class()总是返回this,无论任何返回null或任何其他值,我可以围绕此工作以返回null吗?

现在我想到,解决方案可能是在class()中创建新实例并返回该实例或null,而不是使用new,是否有更好的解决方案?

function klass( canvas_id ) {
    var canvas = document.getElementById( canvas_id );
    if( ! ( canvas && canvas.getContext ) ) {
        return null;
    }   
}
var instance = new klass( 'wrong_id' );
console.log( instance, typeof instance );

您可以创建一个"工厂函数"或"静态工厂方法":

Foo.CreateFoo = function() {
  // not to confuse with Foo.prototype. ...
  if (something) {
    return null;
  }
  return new Foo();
};
// then instead of new Foo():
var obj = Foo.CreateFoo();

使用新的类语法也是一样的:

class Foo {
  static CreateFoo() {
    if (something) {
      return null;
    }
    return new Foo();
  }
}

更好的解决方案是抛出一个错误:

function klass(canvas_id) {
    var canvas = document.getElementById( canvas_id );
    if( ! ( canvas && canvas.getContext ) ) {
        throw new Error('Not a canvas');
    }  
}
// later...
try {
    var c = new klass("canvas_id");
} catch(E) {
    // error caught
}

EDIT:构造函数可以"强制"不返回实例:

function Foo() {
   var canvas = ...;
   if ('undefined' == '' + Foo.CANVAS_CHECK)
      Foo.CANVAS_CHECK = ( canvas && canvas.getContext );
   if (!Foo.CANVAS_CHECK)
      return []; // the constructor will actually return an empty array
   // passed; initialize instance here
}

// later on...
var foo;
if (!((foo = new Foo()) instanceof Foo)) {
   // Failed. Canvas is unsupported.
}
// You happy now, am not i am?  ;-)
然而,奇怪的是,如果一个"构造函数"返回一个数字、字符串、truefalse等,它实际上确实返回一个实例。第二种解决方案仅在构造函数返回空数组[]或空对象{}时有效。

您可以使用John Resig文章中描述的技术在一个函数中组合工厂和构造函数。例子:

function Person(name) {
    var me = arguments.callee;
    if (!(this instanceof me)) {
        // factory code
        // validate parameters....
        if(!name.match(/^[a-z]+$/))
            return null;
        // ...and call the constructor
        return new me(arguments);
    } else {
        // constructor code
        this.name = name;       
    }
}

a = Person("joe")   // ok 
b = Person("bob")   // ok
c = Person("R2D2")  // null

不幸的是,你不能:原因在这个答案中:

构造函数可以返回哪些值来避免返回此值?

正如我在上面的评论中所说的…

function klass( canvas_id ) {
    var canvas = document.getElementById( canvas_id );
    if( ! ( canvas && canvas.getContext ) ) {
        return new Boolean;
    }   
}
var instance1 = new klass( 'wrong_id' );
if(!(instance1 instanceof klass))
    console.log( 'Canvas is not suppored' );
var instance2 = new klass( 'wrong_id' ).valueOf();
console.log( instance2, typeof instance2 );
if(instance2 !== false)
    console.log( 'Canvas is supported, yeah' );

我用这个技巧解决了同样的问题:

  ...
  function MyConstructor () 
  { ...
    let Null = { valueOf: ()=>null }
    return Null;
  } 

构造函数不能返回null。但是它可以返回任何Object所以它可以返回上面定义的Object 'Null'。构造函数的调用者只需要在使用结果之前调用valueOf():

let maybeNull = (new MyConstructor (maybeArg)) . valueOf();

这样做是因为valueOf()是一个内置的JavaScript方法默认情况下,除了盒装数字之外的所有内容都是这样装箱字符串和装箱布尔值各自返回。

您可以为任何对象重写valueOf(),就像我上面所做的那样