it-swarm.com.de

Wie erkennt man, ob eine Funktion als Konstruktor aufgerufen wird?

Gegeben eine Funktion:

function x(arg) { return 30; }

Sie können es auf zwei Arten nennen:

result = x(4);
result = new x(4);

Die erste gibt 30 zurück, die zweite ein Objekt.

Wie können Sie erkennen, auf welche Weise die Funktion in der Funktion selbst aufgerufen wurde?

Was auch immer Ihre Lösung ist, sie muss auch mit dem folgenden Aufruf funktionieren:

var Z = new x(); 
Z.lolol = x; 
Z.lolol();

Alle Lösungen glauben derzeit, dass Z.lolol() es als Konstruktor bezeichnet.

98
Claudiu

HINWEIS: Dies ist jetzt in ES2015 und später möglich. Siehe Antwort von Daniel Weiner .

Ich glaube nicht, was Sie wollen, ist möglich [vor ES2015]. Es gibt einfach nicht genug Informationen innerhalb der Funktion, um einen zuverlässigen Rückschluss zu ermöglichen.

Wenn Sie sich die Spezifikation der dritten Auflage von ECMAScript ansehen, werden beim Aufruf von new x() im Wesentlichen folgende Schritte ausgeführt:

  • Erstellen Sie ein neues Objekt
  • Weisen Sie der Prototyp-Eigenschaft von x ihre interne Eigenschaft [[Prototyp]] zu.
  • Rufen Sie x wie normal auf und übergeben Sie das neue Objekt als this.
  • Wenn der Aufruf von x ein Objekt zurückgegeben hat, geben Sie es zurück, andernfalls das neue Objekt

Dem aufgerufenen Code wird nichts Nützliches für den Aufruf der Funktion zur Verfügung gestellt. Die einzige Möglichkeit, die in x getestet werden kann, ist der this-Wert. Dies ist, was alle Antworten hier tun. Wie Sie festgestellt haben, ist eine neue Instanz von * x beim Aufruf von x als Konstruktor nicht zu unterscheiden von einer bereits vorhandenen Instanz von x, die als this übergeben wird, wenn Sie x als Funktion aufrufen, sofern, dem Sie eine Eigenschaft zuweisen jedes neue Objekt, das von x erstellt wird, wenn es erstellt wird:

function x(y) {
    var isConstructor = false;
    if (this instanceof x // <- You could use arguments.callee instead of x here,
                          // except in in EcmaScript 5 strict mode.
            && !this.__previouslyConstructedByX) {
        isConstructor = true;
        this.__previouslyConstructedByX = true;
    }
    alert(isConstructor);
}

Offensichtlich ist dies nicht ideal, da Sie jetzt für jedes von x erstellte Objekt eine zusätzliche unbrauchbare Eigenschaft haben, die überschrieben werden könnte, aber ich denke, es ist das Beste, was Sie tun können.

(*) "Instanz von" ist ein ungenauer Begriff, aber nahe genug und präziser als "Objekt, das durch Aufruf von x als Konstruktor erstellt wurde"

85
Tim Down

Dies ist ab ECMAScript 6 mit new.target möglich. new.target wird gesetzt, wenn die Funktion mit new (oder mit Reflect.construct, die sich wie new verhält) aufgerufen wird, andernfalls undefined.

function Foo() {
    if (new.target) {
       console.log('called with new');
    } else {
       console.log('not called with new');
    }
}

new Foo(); // "called with new"
Foo(); // "not called with new"
Foo.call({}); // "not called with new"
59
Daniel Weiner

1) Sie können this.constructor überprüfen:

function x(y)
{
    if (this.constructor == x)
        alert('called with new');
    else
         alert('called as function');
}

2) Ja, der Rückgabewert wird nur verworfen, wenn er im Kontext new verwendet wird

51
Greg

HINWEIS: Diese Antwort wurde in 2008 geschrieben, als Javascript noch in ES3 von 1999 war. Seitdem wurden viele neue Funktionen hinzugefügt, sodass es jetzt bessere Lösungen gibt. Diese Antwort wird aus historischen Gründen aufbewahrt. 

Der folgende Code hat den Vorteil, dass Sie den Namen der Funktion nicht zweimal angeben müssen, und er funktioniert auch für anonyme Funktionen. 

function x() {
    if ( (this instanceof arguments.callee) ) {
      alert("called as constructor");
    } else {
      alert("called as function");
    }
}

Update Wie claudiu in einem Kommentar unten ausgeführt hat, funktioniert der obige Code nicht, wenn Sie den Konstruktor demselben Objekt zuweisen, das er erstellt hat. Ich habe noch nie einen Code geschrieben, der das tut, und neueren gesehen, wie jemand anderes das besser macht. 

Claudius Beispiel:

var Z = new x();
Z.lolol = x;
Z.lolol();

Durch das Hinzufügen einer Eigenschaft zum Objekt kann erkannt werden, ob das Objekt initialisiert wurde. 

function x() {
    if ( (this instanceof arguments.callee && !this.hasOwnProperty("__ClaudiusCornerCase")) ) {
        this.__ClaudiusCornerCase=1;
        alert("called as constructor");
    } else {
        alert("called as function");
    }
}

Sogar der Code oben wird beschädigt, wenn Sie die hinzugefügte Eigenschaft löschen. Sie können es jedoch mit jedem beliebigen Wert überschreiben, einschließlich undefined, und es funktioniert immer noch. Wenn Sie es jedoch löschen, wird es beschädigt.

Es gibt derzeit keine systemeigene Unterstützung in ecmascript zur Erkennung, ob eine Funktion als Konstruktor aufgerufen wurde. Dies ist die nächste Sache, die ich bisher gefunden habe, und es sollte funktionieren, wenn Sie die Eigenschaft nicht löschen.

19
some

Zwei Möglichkeiten, im Wesentlichen die gleiche unter der Haube. Sie können testen, was der Umfang von this ist, oder Sie können testen, was this.constructor ist.

Wenn Sie eine Methode als Konstruktor aufgerufen haben, ist this eine neue Instanz der Klasse. Wenn Sie die Methode als Methode aufrufen, ist this das Kontextobjekt der Methode. In ähnlicher Weise ist der Konstruktor eines Objekts die Methode selbst, wenn sie als new aufgerufen wird, und der System-Objektkonstruktor ansonsten. Das ist klar wie Schlamm, aber das sollte helfen:

var a = {};

a.foo = function () 
{
  if(this==a) //'a' because the context of foo is the parent 'a'
  {
    //method call
  }
  else
  {
    //constructor call
  }
}

var bar = function () 
{
  if(this==window) //and 'window' is the default context here
  {
    //method call
  }
  else
  {
    //constructor call
  }
}

a.baz = function ()
{
  if(this.constructor==a.baz); //or whatever chain you need to reference this method
  {
    //constructor call
  }
  else
  {
    //method call
  }
}
8
annakata

Nach dem Instanztyp von [this] im Konstruktor zu suchen, ist der richtige Weg. Das Problem ist, dass dieser Ansatz ohne weiteres fehleranfällig ist. Es gibt jedoch eine Lösung.

Nehmen wir an, wir haben es mit der Funktion ClassA () zu tun. Der rudimentäre Ansatz ist:

    function ClassA() {
        if (this instanceof arguments.callee) {
            console.log("called as a constructor");
        } else {
            console.log("called as a function");
        }
    }

Es gibt mehrere Möglichkeiten, dass die oben genannte Lösung nicht wie erwartet funktioniert. Betrachten Sie nur diese beiden:

    var instance = new ClassA;
    instance.classAFunction = ClassA;
    instance.classAFunction(); // <-- this will appear as constructor call

    ClassA.apply(instance); //<-- this too

Um dies zu überwinden, schlagen einige vor, entweder a) einige Informationen in ein Feld in der Instanz einzufügen, wie "ConstructorFinished", und überprüfen Sie es erneut, oder b) behalten Sie die erstellten Objekte in einer Liste. Beides ist mir unangenehm, da das Ändern jeder ClassA-Instanz zu invasiv und zu teuer ist, damit ein typbezogenes Feature funktioniert. Das Sammeln aller Objekte in einer Liste kann zu Speicherbereinigungs- und Ressourcenproblemen führen, wenn ClassA über viele Instanzen verfügt.

Der beste Weg ist, die Ausführung Ihrer ClassA-Funktion steuern zu können. Der einfache Ansatz lautet:

    function createConstructor(typeFunction) {
        return typeFunction.bind({});
    }

    var ClassA = createConstructor(
        function ClassA() {
            if (this instanceof arguments.callee) {
                console.log("called as a function");
                return;
            }
            console.log("called as a constructor");
        });

    var instance = new ClassA();

Dies verhindert effektiv alle Versuche, den [this] -Wert auszutricksen. Eine gebundene Funktion behält immer ihren ursprünglichen [this] -Kontext, sofern Sie sie nicht mit dem Operator new aufrufen. 

Die erweiterte Version bietet die Möglichkeit, den Konstruktor auf beliebige Objekte anzuwenden. Einige Anwendungen könnten den Konstruktor als Typkonverter verwenden oder eine aufrufbare Kette von Basisklassenkonstruktoren in Vererbungsszenarien bereitstellen.

    function createConstructor(typeFunction) {
        var result = typeFunction.bind({});
        result.apply = function (ths, args) {
            try {
                typeFunction.inApplyMode = true;
                typeFunction.apply(ths, args);
            } finally {
                delete typeFunction.inApplyMode;
            }
        };
        return result;
    }

    var ClassA = createConstructor(
        function ClassA() {
            if (this instanceof arguments.callee && !arguments.callee.inApplyMode) {
                console.log("called as a constructor");
            } else {
                console.log("called as a function");
            }
        });
5

eigentlich ist die Lösung sehr einfach und einfach ... verstehe nicht, warum so viele Wörter für so ein kleines Ding geschrieben wurden

UPDATE: dank TwilightSun ist die Lösung nun abgeschlossen, auch für den Test Claudiu wird vorgeschlagen! Danke Jungs!!!

function Something()
{
    this.constructed;

    if (Something.prototype.isPrototypeOf(this) && !this.constructed)
    {
        console.log("called as a c'tor"); this.constructed = true;
    }
    else
    {
        console.log("called as a function");
    }
}

Something(); //"called as a function"
new Something(); //"called as a c'tor"

hier gezeigt: https://jsfiddle.net/9cqtppuf/

4
ymz

Es gibt keine zuverlässige Methode, um zu unterscheiden, wie eine Funktion im JavaScript-Code aufgerufen wird.1

Einem Funktionsaufruf wird jedoch this dem globalen Objekt zugewiesen, während einem Konstruktor this ein neues Objekt zugewiesen wird. Dieses neue Objekt kann nicht immer das globale Objekt sein, denn selbst wenn Sie mit einer Implementierung das globale Objekt festlegen können, hatten Sie noch keine Gelegenheit dazu.

Sie können das globale Objekt abrufen, indem Sie eine Funktion als Funktion (heh) aufrufen, die this zurückgibt.

Meine Intuition ist, dass Konstruktoren, die ein definiertes Verhalten haben, wenn sie als Funktion aufgerufen werden, in der Spezifikation von ECMAScript 1.3 unterscheiden, wie sie mit diesem Vergleich aufgerufen wurden:

function MyClass () {
    if ( this === (function () { return this; })() ) {
        // called as a function
    }
    else {
        // called as a constructor
    }
}

Jedenfalls kann jeder call oder apply einer Funktion oder eines Konstruktors verwenden und this auf irgendetwas setzen. Auf diese Weise können Sie jedoch vermeiden, das globale Objekt "zu initialisieren":

function MyClass () {
    if ( this === (function () { return this; })() ) {
        // Maybe the caller forgot the "new" keyword
        return new MyClass();
    }
    else {
        // initialize
    }
}

Der Host (alias Implementierung) kann den Unterschied möglicherweise erkennen, wenn er das Äquivalent zu den internen Eigenschaften [[Call]] und [[Construct]] implementiert. Ersteres wird für Funktions- oder Methodenausdrücke aufgerufen, während letzteres für new-Ausdrücke aufgerufen wird.

3
acelent

Bis ich diesen Thread gesehen habe, habe ich nie gedacht, dass der Konstruktor eine Eigenschaft einer Instanz sein könnte, aber ich denke, der folgende Code deckt diesen seltenen Fall ab.

// Store instances in a variable to compare against the current this
// Based on Tim Down's solution where instances are tracked
var Klass = (function () {
    // Store references to each instance in a "class"-level closure
    var instances = [];

    // The actual constructor function
    return function () {
        if (this instanceof Klass && instances.indexOf(this) === -1) {
            instances.Push(this);
            console.log("constructor");
        } else {
            console.log("not constructor");
        }
    };
}());

var instance = new Klass();  // "constructor"
instance.klass = Klass;
instance.klass();            // "not constructor"

In den meisten Fällen überprüfe ich vielleicht einfach die Instanz von.

3

Die Gregs-Lösung erweitert sich perfekt mit den von Ihnen bereitgestellten Testfällen:

function x(y) {
    if( this.constructor == arguments.callee && !this._constructed ) {
        this._constructed = true;
        alert('called with new');
    } else {
        alert('called as function');
    }
}

BEARBEITEN: Hinzufügen einiger Testfälle

x(4);             // OK, function
var X = new x(4); // OK, new

var Z = new x();  // OK, new
Z.lolol = x; 
Z.lolol();        // OK, function

var Y = x;
Y();              // OK, function
var y = new Y();  // OK, new
y.lolol = Y;
y.lolol();        // OK, function
3
Frunsi

Von John Resig:

function makecls() {

   return function(args) {

        if( this instanceof arguments.callee) {
            if ( typeof this.init == "function")
                this.init.apply(this, args.callee ? args : arguments)
        }else{
            return new arguments.callee(args);
        }
    };
}

var User = makecls();

User.prototype.init = function(first, last){

    this.name = first + last;
};

var user = User("John", "Resig");

user.name
2
haijin

Wenn Sie gehackt werden, ist instanceof die Minimallösung nach new.target wie bei anderen Antworten. Die Verwendung der Lösung instanceof würde jedoch mit diesem Beispiel fehlschlagen:

let inst = new x;
x.call(inst);

In Kombination mit der @ TimDown-Lösung können Sie die WeakSet von ES6 verwenden, wenn Sie mit älteren ECMAScript-Versionen kompatibel sein möchten, um zu verhindern, dass Eigenschaften in Instanzen gesetzt werden. Nun, WeakSet wird verwendet, um ungenutzte Objekte abholen zu können. new.target ist im selben Quellcode nicht kompatibel, da es sich um eine Syntaxfunktion des ES6 handelt. ECMAScript gibt an, dass Bezeichner nicht eines der reservierten Wörter sein dürfen und new ist sowieso kein Objekt.

(function factory()
{
    'use strict';
    var log = console.log;

    function x()
    {
        log(isConstructing(this) ?
            'Constructing' :
            'Not constructing'
        );
    }

    var isConstructing, tracks;
    var hasOwnProperty = {}.hasOwnProperty;

    if (typeof WeakMap === 'function')
    {
        tracks = new WeakSet;
        isConstructing = function(inst)
        {
            if (inst instanceof x)
            {
                return tracks.has(inst) ?
                    false : !!tracks.add(inst);
            }
            return false;
        }
    } else {
        isConstructing = function(inst)
        {
            return inst._constructed ?
                false : inst._constructed = true;
        };
    }
    var z = new x; // Constructing
    x.call(z)      // Not constructing
})();

Der Operator instanceof von ECMAScript 3 ist angegeben als:

11.8.6 Der Instanzoperator
--- Die Produktion RelationalExpression: RelationalExpression beispielvon ShiftExpression wird ausgewertet wie folgt:
--- 1. Bewerten Sie RelationalExpression.
--- 2. Rufen Sie GetValue (Ergebnis (1)) auf.
--- 3. ShiftExpression auswerten.
--- 4. Rufen Sie GetValue auf (Ergebnis (3)).
--- 5. Wenn Ergebnis (4) kein Objekt ist, werfen Sie ein TypeError Ausnahme.
--- 6. Wenn Ergebnis (4) keine [[HasInstance]] - Methode hat, werfen Sie a TypeError Ausnahme.
--- 7. Rufen Sie die Methode [[HasInstance]] von Result (4) mit dem Parameter Result (2) auf.
--- 8. Rückgabeergebnis (7) .
15.3.5.3 [[HasInstance]] (V)
--- Angenommen, F ist ein Funktionsobjekt.
--- Wenn die Methode [[HasInstance]] von F mit dem Wert V aufgerufen wird, werden folgende Schritte ausgeführt:
--- 1. Wenn V kein Objekt ist, kehren Sie zurück false.
--- 2. Rufen Sie die Methode [[Get]] von F mit dem Namen der Eigenschaft auf "Prototyp".
--- 3. Sei O das Ergebnis (2).
--- 4. Wenn O kein Objekt ist, werfen Sie ein TypeError Ausnahme.
--- 5. Sei V der Wert der [Prototyp] -Eigenschaft von V.
--- 6. Wenn V ** NULL ** ist, zurückgeben false.
--- 7. Wenn sich O und V auf dasselbe Objekt beziehen oder sich auf miteinander verbundene Objekte beziehen (13.1.2), kehren Sie zurück wahr.
--- 8. Fahren Sie mit Schritt 5 fort.

Das bedeutet, dass der Wert der linken Seite rekursiert wird, nachdem er zu seinem Prototyp gegangen ist, bis er kein Objekt ist oder bis er dem Prototyp des Objekts auf der rechten Seite mit der angegebenen [[HasInstance]]-Methode entspricht. Was bedeutet, dass geprüft wird, ob die linke Seite eine Instanz der rechten Seite ist und alle internen Prototypen der linken Seite verbraucht.

function x() {
    if (this instanceof x) {
        /* Probably invoked as constructor */
    } else return 30;
}
2
hydroper

vielleicht bin ich falsch, aber (auf Kosten eines Parasiten) scheint der folgende Code eine Lösung zu sein:

function x(arg) {
    //console.debug('_' in this ? 'function' : 'constructor'); //WRONG!!!
    //
    // RIGHT(as accepted)
    console.debug((this instanceof x && !('_' in this)) ? 'function' : 'constructor');
    this._ = 1;
    return 30;
}
var result1 = x(4),     // function
    result2 = new x(4), // constructor
    Z = new x();        // constructor
Z.lolol = x; 
Z.lolol();              // function
1
fedeghe

In meinem Test für http://packagesinjavascript.wordpress.com/ habe ich festgestellt, dass der Test if (this == window) in allen Fällen browserübergreifend funktioniert, also ist es der, den ich am Ende verwendet habe.

-Stijn

1
Stijn

Verwenden Sie this instanceof arguments.callee (optional ersetzen Sie arguments.callee durch die Funktion, die die Funktion unterstützt, wodurch die Leistung verbessert wird), um zu prüfen, ob etwas als Konstruktor aufgerufen wird. Nicht verwenden Sie this.constructor, da dies leicht geändert werden kann.

0
Eli Grey

Ich hatte das gleiche Problem, als ich versuchte, eine Funktion zu implementieren, die eine Zeichenfolge anstelle eines Objekts zurückgibt.

Es scheint genug zu sein, um zu überprüfen, ob "this" am Anfang Ihrer Funktion vorhanden ist:

function RGB(red, green, blue) {
    if (this) {
        throw new Error("RGB can't be instantiated");
    }

    var result = "#";
    result += toHex(red);
    result += toHex(green);
    result += toHex(blue);

    function toHex(dec) {
        var result = dec.toString(16);

        if (result.length < 2) {
            result = "0" + result;
        }

        return result;
    }

    return result;
}

Am Ende habe ich mich jedoch entschieden, meine RGB () - Pseudoklasse in eine rgb () - Funktion umzuwandeln, also werde ich einfach nicht versuchen, sie zu instanziieren, sodass ich keinerlei Sicherheitsüberprüfung brauche. Aber das würde davon abhängen, was Sie zu tun versuchen.

0
Diogo Schneider

Oben in der Frage wird der Fehler durch den folgenden Code automatisch behoben, falls die Funktion ohne new aufgerufen wird.

function Car() {

    if (!(this instanceof Car)) return new Car();

    this.a = 1;
    console.log("Called as Constructor");

}
let c1 = new Car();
console.log(c1);
0
Sumer
function createConstructor(func) {
    return func.bind(Object.create(null));
}

var myClass = createConstructor(function myClass() {
    if (this instanceof myClass) {
        console.log('You used the "new" keyword');
    } else {
        console.log('You did NOT use the "new" keyword');
        return;
    }
    // constructor logic here
    // ...
});
0
Joshua Wise

Obwohl dieser Thread uralt ist, bin ich überrascht, dass niemand erwähnt hat, dass der Standardwert this einer Funktion im strikten Modus ( 'use strict' ) undefiniert ist, anstatt wie bisher auf global/window gesetzt zu sein. Prüfen Sie also, ob new nicht ist verwendet einfach testet auf falsey Wert von !this - Z.B:

function ctor() { 'use strict';
  if (typeof this === 'undefined') 
    console.log('Function called under strict mode (this == undefined)');
  else if (this == (window || global))
    console.log('Function called normally (this == window)');
  else if (this instanceof ctor)
    console.log('Function called with new (this == instance)');
  return this; 
}

Wenn Sie diese Funktion in der vorliegenden Form testen, werden Sie aufgrund der 'use strict'-Direktive am Anfang der Funktion als this-Wert definiert. Wenn der strikte Modus bereits aktiviert ist, ändert sich dies natürlich nicht, wenn Sie die 'use strict'-Direktive entfernen. Andernfalls wird der this-Wert auf window oder global..__ gesetzt. Wenn Sie new verwenden, wird die Funktion aufgerufen dann stimmt der Wert von this mit der Prüfung der Instanz überein (obwohl Sie die anderen Dinge geprüft haben, ist die Instanz die letzte Option. Diese Prüfung ist nicht erforderlich und sollte vermieden werden, wenn Sie die Instanzen trotzdem erben möchten.)

function ctor() { 'use strict';
  if (!this) return ctor.apply(Object.create(ctor.prototype), arguments);
  console.log([this].concat([].slice.call(arguments)));
  return this;
}

Dadurch werden der this-Wert und alle an die Funktion übergebenen Argumente an die Konsole protokolliert und der this-Wert zurückgegeben. Wenn der this-Wert falsey ist, erstellt er eine neue Instanz mit Object.create(ctor.prototype) und ruft den Konstruktor mit Function.apply() mit den gleichen Parametern, aber mit der korrekten Instanz als this auf. Wenn der Wert this etwas anderes als falsey ist, wird davon ausgegangen, dass es sich um eine gültige Instanz handelt und zurückgegeben wird.

0
BoB

Tim Down finde ich richtig. Ich denke, sobald Sie an den Punkt gelangen, an dem Sie glauben, dass Sie zwischen den beiden aufrufenden Modi unterscheiden müssen, sollten Sie das Schlüsselwort "this" nicht verwenden. this ist unzuverlässig und könnte das globale Objekt oder ein völlig anderes Objekt sein. Tatsache ist, dass es nicht wünschenswert ist, eine Funktion mit diesen verschiedenen Aktivierungsmodi zu haben, von denen einige wie beabsichtigt funktionieren, andere etwas total Wildes tun. Ich denke, vielleicht versuchst du das aus diesem Grund herauszufinden.

Es gibt eine idiomatische Methode, eine Konstruktorfunktion zu erstellen, die sich unabhängig von ihrem Aufruf gleich verhält. ob es wie Thing (), neues Thing () oder foo.Thing () ist. Es geht so:

function Thing () {
   var that = Object.create(Thing.prototype);
   that.foo="bar";
   that.bar="baz";
   return that;
}

dabei ist Object.create eine neue Standardmethode von ecmascript 5, die in normalem Javascript wie folgt implementiert werden kann:

if(!Object.create) {
    Object.create = function(Function){
        // WebReflection Revision
       return function(Object){
           Function.prototype = Object;
           return new Function;
    }}(function(){});
}

Object.create nimmt ein Objekt als Parameter und gibt ein neues Objekt mit dem übergebenen Objekt als Prototyp zurück. 

Wenn Sie jedoch wirklich versuchen, eine Funktion anders zu gestalten, je nachdem, wie sie aufgerufen wird, sind Sie eine schlechte Person, und Sie sollten keinen Javascript-Code schreiben.

0
Breton

Wenn Sie keine __previouslyConstructedByX-Eigenschaft in das Objekt einfügen möchten, da dies die öffentliche Schnittstelle des Objekts verschmutzt und leicht überschrieben werden kann, geben Sie einfach keine Instanz von x zurück:

function x() {

    if(this instanceof x) {
        console.log("You invoked the new keyword!");
        return that;
    }
    else {
        console.log("No new keyword");
        return undefined;
    }

}

x();
var Z = new x(); 
Z.lolol = x; 
Z.lolol();
new Z.lolol();

Die x-Funktion gibt jetzt nie ein Objekt vom Typ x zurück, daher wird this instanceof x nur (wahr) ausgewertet, wenn die Funktion mit dem Schlüsselwort new aufgerufen wird.

Der Nachteil ist, dass dies das Verhalten von instanceof effektiv verschlechtert - aber je nachdem, wie viel Sie es verwenden (ich neige nicht dazu), ist das möglicherweise kein Problem.


Wenn Sie in beiden Fällen 30 zurückgeben möchten, können Sie anstelle von Number eine Instanz von x zurückgeben:

function x() {

    if(this instanceof x) {
        console.log("You invoked the new keyword!");
        var that = {};
        return new Number(30);
    }
    else {
        console.log("No new");
        return 30;
    }

}

console.log(x());
var Z = new x();
console.log(Z);
Z.lolol = x;
console.log(Z.lolol());
console.log(new Z.lolol());
0