我可以不使用new关键字构造JavaScript对象吗?

我可以不使用new关键字构造JavaScript对象吗?,javascript,inheritance,prototype,constructor,Javascript,Inheritance,Prototype,Constructor,以下是我想做的: 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 可能吗?我可以通过将a连接到原型链中,很容易地使b成为a的一个实例,但是我必须做新的b,这是我试图避免的。我想要的

以下是我想做的:

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
可能吗?我可以通过将a连接到原型链中,很容易地使b成为a的一个实例,但是我必须做新的b,这是我试图避免的。我想要的可能吗

更新:我觉得明智地使用b.。uuuu proto_uuuu=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
更新3:我在a中找到了我想要的东西,一旦我添加了基本的b.。_proto__;=a.prototype行:


您可以在不使用新操作符的情况下创建实例,这是Douglas Crockford撰写的一篇关于这一点的伟大文章。但是它不会帮助您处理故事的实例。

使用新关键字有什么问题

无论如何,听起来最好的办法是阅读Javascript继承:
有人在这个问题上发表了道格拉斯·克罗克福德的一篇文章,这篇文章准确地解释了你的问题

根据Crockford文章Zoidberg间接链接到的“如果你想让继承和instanceof工作,你就不能在一般情况下避免新的,而不走极端”,但话说回来,你为什么想要或需要这样做

我能想到的唯一避免它的原因是,如果您试图将构造函数传递给另一段不知道它是构造函数的代码。在这种情况下,只需将其封装在工厂函数中:

function b() {
    // ...
}
function makeB() {
    return new b();
}
var c = makeB();

你具体问题的简单答案是:不

这将帮助您确定为什么要避免新的问题。也许其他答案中提到的模式会有所帮助。但是,它们都不会在测试中返回true

新的行动主要是:

var x = (function(fn) { var r = {}; fn.call(r); return r;}(b);

但是有一点不同,就是构造fn是使用一些内部属性附加到对象的。是的,您可以使用构造函数获得它,但是设置它没有相同的效果。让instanceof按预期工作的唯一方法是使用new关键字。

让instanceof工作的唯一方法是使用new关键字。由new建立的漏洞利用实例(proto).

您可以使用以下模式:

function SomeConstructor(){
   if (!(this instanceof SomeConstructor)){
        return new SomeConstructor();
   }
   //the constructor properties and methods here
}
之后,您可以执行以下操作:

var myObj = SomeConstructor();
除了这个相当古老的答案:您可以使用创建对象:

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
以下是我使用该模式创建的一些日期功能的示例。

是的,您可以这样做

var User = function() {
  var privateMethod = function() {
    alert('hello');
  }

  return {
    sayHello : function() {
      privateMethod();
      this.done = true;
    }
  }
}

var user1 = User();

这个方法有什么问题吗?

在javascript bookmarklet中,您可以使用evalunescape。。。要在不使用新操作符的情况下创建对象,请执行以下操作:

javascript:xhr=eval(unescape('new\x20XMLHttpRequest();'));alert(xhr);
function sampleClass() {
    this.cname = "sample";
}

sampleClass.prototype.getCname = function() {
    return this.cname;
}

const newPolyfill = function(fname) {
    if (typeof fname !== "function")
    throw Error("can't call new on non-functional input");

    let newFun = {};
    newFun.__proto__ = Object.assign(fname.prototype);
    fname.prototype.constructor();

    for (let key in fname.prototype) {
        if (typeof fname.prototype[key] !== "function") {
        newFun[key] = fname.prototype[key];
        delete newFun.__proto__[key];
        delete fname.__proto__[key];
       }
    }

    return newFun;
}

let newObj = new sampleClass();
console.log("new obj", newObj);
console.log("new cname", newObj.getCname());//sample
let newPolyObj = newPolyfill(sampleClass);
console.log("new poly obj", newPolyObj);
console.log("newPly cname", newPolyObj.getCname());//sample
console.log(newPolyObj instanceof(sampleClass)) // true

对于那些像我这样通过谷歌可能会发现这一点的人,我进一步开发了原始解决方案,以实现更好的通用性:

var myObject=函数{};//提示:Chrome调试器将把创建的项命名为“myObject” var对象=函数本身,父对象{ 还我自己,家长{ ifparent{ 自我原型=父母; } myObject.prototype=我自己.prototype; 返回新的myObject; }; }; a=功能RG{ var me=objecta; me.param=arg; 还我; }; b=功能RG{ var parent=aarg, me=objectb,父对象 ; 还我; }; var instance1=a; var instance2=此处的bhi; console.log-------------- console.log'instance1instanceofa:'+instance1instanceofa console.log'instance2 instanceof b:'+instance2 instanceof b console.log'instance2 instance of a:'+instance2 instanceof a console.log'a:'的一个实例+a的一个实例 console.loginstance1.param console.loginstance2.param使用Object.create和经典函数.prototype。正确设置原型链,可以保留instanceof关键字的正常功能,而不使用任何新关键字

函数_newclassConstructor,…args{ var obj=Object.createclassConstructor.prototype; classConstructor.callobj,…args; 返回obj; } 新功能测试{ 函数TestClassname,位置{ 这个。_name=name; 这个。_位置=位置; this.getName=函数{ 返回此。\u名称; } } TestClass.prototype.getLocation=函数{ 返回此位置。\u; } TestClass.prototype.setName=functionnewName{ 这个。_name=newName; } 常数a=新的测试类'anil','hyderabad'; 常数b=_newTestClass,'anil','hyderabad'; const assert=console.assert TestClass的asserta实例 TestClass的assertb实例 asserta.constructor.name=='TestClass'; assertb.constructor.name=='TestClass'; asserta.getName==b.getName; asserta.getLocation==b.getLocation; a、 设置名称“库马尔”; b、 设置名称“库马尔”; asserta.getName==b.getName; 控制台。记录“一切正常” }
测试新操作员的Polyfill

javascript:xhr=eval(unescape('new\x20XMLHttpRequest();'));alert(xhr);
function sampleClass() {
    this.cname = "sample";
}

sampleClass.prototype.getCname = function() {
    return this.cname;
}

const newPolyfill = function(fname) {
    if (typeof fname !== "function")
    throw Error("can't call new on non-functional input");

    let newFun = {};
    newFun.__proto__ = Object.assign(fname.prototype);
    fname.prototype.constructor();

    for (let key in fname.prototype) {
        if (typeof fname.prototype[key] !== "function") {
        newFun[key] = fname.prototype[key];
        delete newFun.__proto__[key];
        delete fname.__proto__[key];
       }
    }

    return newFun;
}

let newObj = new sampleClass();
console.log("new obj", newObj);
console.log("new cname", newObj.getCname());//sample
let newPolyObj = newPolyfill(sampleClass);
console.log("new poly obj", newPolyObj);
console.log("newPly cname", newPolyObj.getCname());//sample
console.log(newPolyObj instanceof(sampleClass)) // true

对。如果您不想使用“new”关键字,只需使用prototype,并在co中返回一些内容即可 构造函数函数

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

构造函数中的“this”关键字应该引用函数本身,而不是通常引用的父对象,如果在全局范围内声明此函数,则父对象将是窗口对象

对于在新创建的对象/实例上未找到的所有失败的查找obj属性,请检查原始构造函数的prototype属性

因此,对于新的:

没有新的:



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

我很好奇:您为什么要避免使用新属性?我正在创建Scala案例类的Javascript版本:github.com/pr1001/caseclass。js@pr1001:不明白为什么这需要您处理新关键字。而且,proto不能帮助你跨浏览器。这只是语法上的糖分,没有别的。然而,我认为这仍然是一个有趣的挑战。可能的重复不是关于通用的新用途,而是关于你可以避免它的特定位置,例如使用对象{}代替,数组使用[],特别是函数。问题是,如果可能的话。这篇文章解释说,是的,这是可能的,它还涵盖了为什么它有用的一些方面。@nemisj:不,它没有。它谈论的是不要像新函数{…}那样不恰当地使用新函数,而不是一般地避免使用它。事实上,这篇文章根本没有谈到继承。@t.J.克劳德:我的错误是,我没有注意到c实例a背后的想法:多么。。。。有趣的方法。如果它不能做到这一点,那就扔掉新的和这个。有点极端,但显示了语言的强大。instanceof不会返回问题中所需的结果。那么我可以对proto赋值吗?当然,proto是下划线proto下划线proto。是的,愚蠢的格式。在Rhino和Chrome调试器中,proto似乎不是只读的;我在某个地方读到,proto被弃用了。考虑到不同浏览器所采用的方法不同,这可能是一个很难实现的策略。我刚刚尝试了这个,看起来很有希望。这是允许构造函数在没有新代码的情况下工作的惯用用法。注释1:但是…但是…但是…它仍然使用新代码。我看不出这有什么意义,这只是一个工厂方法,如果用户愿意,它也允许用户使用新的。这只会导致团队中的一些成员使用新的,而其他成员则不使用;维修噩梦。支持一种或另一种模式,例如,如果作者没有(或确实)使用new调用构造函数,则包含为生产而删除的调试代码会引发异常,但不能同时使用两者。注释2:如果要使用此模式,请确保使用示例中的命名函数,并使用函数名,而不是参数。被调用者-例如:if!这是某个构造函数的实例。使用arguments.callee会显著降低函数速度2-10倍,具体取决于JavaScript引擎,并且会在JavaScript新的严格模式下引发异常。抱歉,T.J.,如果我不清楚,但我正在寻找最终用户而不是库创建者避免使用new的代码。无论如何,请阅读Crockford。他见多识广,富有教育性。但不要把克罗克福德当作福音书来读,至少是因为他以前的一些文章!促进效率极低的编程实践。我并没有立即看到Crockford关于在JavaScript中模拟经典继承的文章,现在他认为这是一个错误,与OP发布的实用性问题有关。
    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);
    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);