Если вы собираетесь взломать, то instanceof
- это минимальное решение после new.target
, как и в других ответах. Но при использовании решения instanceof
в этом примере произойдет сбой:
let inst = new x;
x.call(inst);
В сочетании с решением @TimDown вы можете использовать ES6 WeakSet
, если вам нужна совместимость со старыми версиями ECMAScript, чтобы предотвратить помещение свойств внутри экземпляров. Хорошо, WeakSet
будет использоваться для того, чтобы разрешить сбор неиспользуемых объектов. new.target
не будет совместимым в том же исходном коде, так как это синтаксическая функция ES6. ECMAScript указывает, что идентификаторы не могут быть одним из зарезервированных слов, и, в любом случае, new
не является объектом.
(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
})();
Оператор ECMAScript 3 instanceof
имеет значение , указанное как:
11.8.6 Оператор instanceof
--- Производится выражение RelationalExpression: выражение RelationalExpression instanceof ShiftExpression
следующим образом:
--- 1. Оцените RelationalExpression.
--- 2. Вызвать GetValue (Результат (1)).
--- 3. Оценить ShiftExpression.
--- 4. Вызвать GetValue (Результат (3)).
--- 5. Если Result (4) не является объектом, выведите исключение TypeError .
--- 6. Если в Результате (4) нет метода [[HasInstance]], выведите исключение TypeError .
--- 7. Вызвать метод [[HasInstance]] Результата (4) с параметром Результат (2).
--- 8. Вернуть результат (7).
15.3.5.3 [[HasInstance]] (V)
--- Предположим, что F является объектом Function.
--- Когда метод [[HasInstance]] для F вызывается со значением V, предпринимаются следующие шаги:
--- 1. Если V не является объектом, вернуть false .
--- 2. Вызвать метод [[Get]] для F с именем свойства "prototype" .
--- 3. Пусть O будет результатом (2).
--- 4. Если O не является объектом, выдать исключение TypeError .
--- 5. Пусть V будет значением свойства [[Prototype]] для V.
--- 6. Если V ** ноль **, вернуть false .
--- 7. Если O и V ссылаются на один и тот же объект или если они ссылаются на объекты, соединенные друг с другом (13.1.2), верните true .
--- 8. Перейти к шагу 5.
И это означает, что оно будет возвращать значение левой стороны после перехода к его прототипу, пока оно не станет объектом или пока оно не станет равным прототипу объекта правой стороны с указанным методом [[HasInstance]]
. Что означает, что он проверит, является ли левая сторона экземпляром правой стороны, хотя и потребляет все внутренние прототипы левой стороны.
function x() {
if (this instanceof x) {
/* Probably invoked as constructor */
} else return 30;
}