我可以在不使用new关键字的情况下构造JavaScript对象吗?

pr1*_*001 17 javascript inheritance constructor prototype

这是我想做的事情:

function a() {
  // ...
}
function b() {
  //  Some magic, return a new object.
}
var c = b();

c instanceof b // -> true
c instanceof a // -> true
b instanceof a // -> true
Run Code Online (Sandbox Code Playgroud)

可能吗?我可以通过挂钩到它的原型链b来成为一个a容易的实例a但是我必须这样做new b(),这就是我想要避免的.我想要的是什么?

更新:我觉得有可能明智地使用b.__proto__ = a.prototype.我下班后要去做更多的实验.

更新2:下面是你可以得到的最接近的,这对我来说已经足够了.谢谢所有有趣的答案.

function a() {
  // ...
}
function b() {
  if (!(this instanceof arguments.callee)) {
    return new arguments.callee();
  }
}
b.__proto__ = a.prototype

var c = b();
c instanceof b // -> true
c instanceof a // -> false
b instanceof a // -> true
Run Code Online (Sandbox Code Playgroud)

更新3:一旦我添加了必要的一行,我就在'power constructors'博客文章中找到了我想要的内容b.__proto__ = a.prototype:

var object = (function() {
     function F() {}
     return function(o) {
         F.prototype = o;
         return new F();
     };
})();

function a(proto) {
  var p = object(proto || a.prototype);
  return p;
}

function b(proto) {
  var g = object(a(proto || b.prototype));
  return g;
}
b.prototype = object(a.prototype);
b.__proto__ = a.prototype;

var c = b();
c instanceof b // -> true
c instanceof a // -> true
b instanceof a // -> true
a() instanceof a // -> true
Run Code Online (Sandbox Code Playgroud)

Koo*_*Inc 29

您可以使用此模式:

function SomeConstructor(){
   if (!(this instanceof SomeConstructor)){
        return new SomeConstructor();
   }
   //the constructor properties and methods here
}
Run Code Online (Sandbox Code Playgroud)

之后你可以这样做:

var myObj = SomeConstructor();
Run Code Online (Sandbox Code Playgroud)

除了这个(相当古老的)答案:您可以使用模块模式来创建对象:

function Person(name, age, male) {
  name = name || 'unknown';
  age = age || 0;
  function get() {
    return ['This person is called ', name,
            (!male ? ', her' : ', his'),' age is ',
            age].join('');
  }
  function setAge(nwage) {
     age = nwage;
  }
  return Object.freeze({get: get, setAge: setAge});
}
// usage
var jane =  Person('Jane', 23)
   ,charles = Person('Charles', 32, 1)
   ,mary = Person('Mary', 16);

console.log(jane.get()); //=> This person is called Jane, her age is 23
mary.setAge(17);
console.log(mary.get()); //=> This person is called Mary, her age is 17
Run Code Online (Sandbox Code Playgroud)

这是我使用该模式创建的一些函数的jsFiddleDate.

  • +1这是允许构造函数在没有"new"的情况下工作的通常习惯用法. (4认同)
  • 评论#1:但是......但......但它仍然使用`new`.我在这里没有看到这一点,它只是一种工厂方法,**允许用户使用`new`,如果他们愿意的话.这只会导致团队的一些成员使用"new"而其他人不使用; 维护噩梦.支持一个或另一个(例如,通过包含您为生产删除的调试代码,如果作者没有 - 或者确实 - 使用`new`来调用构造函数,则抛出异常),但不是两者. (4认同)
  • 注释#2:如果要使用此模式,请确保使用命名函数(如示例中所示)并使用函数名称,而不是`arguments.callee` - 例如:`if(!(this instanceof SomeConstructor) )`.使用`arguments.callee`会大大减慢你的函数**(2-10x,取决于JavaScript引擎),并会在JavaScript的新"严格"模式中抛出异常. (3认同)

Mat*_*all 10

使用new关键字有什么问题?

无论如何,听起来最好的事情是阅读Javascript继承:http: //javascript.crockford.com/inheritance.html

  • 无论如何,请阅读Crockford.他的知识和教育.但是不要把克罗克福德看作福音,尤其是因为他早期的一些文章(至少!)促进了极其低效的编程实践.我并没有立即看到Crockford关于在JavaScript中模拟经典继承的文章(现在被他视为"错误")与OP发布的实用问题有关. (4认同)

ken*_*orr 5

是的。如果您不想使用“new”关键字,只需使用原型,并在构造函数中返回一些内容。

使用“new”只是告诉构造函数:

  1. 构造函数中的“this”关键字应该引用函数本身,而不是父对象(像往常一样),如果该函数在全局范围内声明,则父对象将是窗口对象。

  2. 对于新创建的对象/实例上所有失败的查找(未找到 obj 属性),请检查原始构造函数的原型属性。

所以有了新的

    function Point(x, y) {
       this.x = x;
       this.y = y;
    }
    Point.prototype.getDistance = function(otherPoint){
       var Dx = (this.x - otherPoint.x) ** 2;
       var Dy = (this.y - otherPoint.y) ** 2;
       var d = Dx + Dy;
       d = Math.sqrt(d);
       return d
    }
    var pointA = new Point(3, 6);
    var pointB = new Point(5, 8);
    var distanceAB = pointA.getDistance(pointB);
Run Code Online (Sandbox Code Playgroud)

没有新的:

    function Point(x, y) {
       let d = Object.create(Point.prototype);
       d.x = x;
       d.y = y;
       return d
    }
    Point.prototype.getDistance = function(otherPoint){
       var Dx = (this.x - otherPoint.x) ** 2;
       var Dy = (this.y - otherPoint.y) ** 2;
       var d = Dx + Dy;
       d = Math.sqrt(d);
       return d
    }
    var pointA = Point(3, 6);
    var pointB = Point(5, 8);
    var distanceAB = pointA.getDistance(pointB);
Run Code Online (Sandbox Code Playgroud)

尝试添加删除第一个示例中的“new”,您将看到“this”不再引用构造函数,而是引用窗口对象。您将提供窗口 x 和 y 属性,这可能不是您想要的。