Какие значения может вернуть конструктор, чтобы избежать возврата?
Каковы точные обстоятельства, при которых оператор return в Javascript может возвращать значение, отличное от this
, когда конструктор вызывается с использованием ключевого слова new
?
Пример:
function Foo () {
return something;
}
var foo = new Foo ();
Если я не ошибаюсь, если something
является нефункциональным примитивом, возвращается this
. В противном случае возвращается something
. Правильно ли это?
IOW, какие значения могут something
принимать, чтобы вызвать (new Foo () instanceof Foo) === false
?
Ответы
Ответ 1
Точное условие описано во внутреннем свойстве [[Construct]]
, которое используется оператором new
:
Из ECMA-262 3-й. Спецификация издания:
13.2.2 [[Construct]]
Когда свойство [[Construct]]
для объекта Function
F
имеет значение вызваны следующие шаги:
- Создайте новый собственный объект ECMAScript.
- Установите для свойства
[[Class]]
Result(1)
значение "Object"
.
- Получите значение свойства prototype из
F
.
- Если
Result(3)
является объектом, установите для свойства [[Prototype]]
элемента Result(1)
значение Result(3)
.
- Если
Result(3)
не является объектом, установите для свойства [[Prototype]]
Result(1)
исходный объект-прототип Object
как описано в 15.2.3.1.
- Вызовите свойство
[[Call]]
F
, указав Result(1)
в качестве значения this
, и предоставление списка аргументов, переданного в [[Construct]]
как значения аргумента.
- Если
Type(Result(6))
Object
затем верните Result(6)
.
- Вернитесь
Result(1)
.
Посмотрите на шаги 7 и 8, новый объект будет возвращен, только если
тип Result(6)
(значение, возвращаемое конструктором F
функция) не является объектом.
Ответ 2
Конкретные примеры
http://jsbin.com/zivivucahi/1/edit?html,js,console,output
/*
ECMA 262 v 5
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
"4.3.2
primitive value
member of one of the types Undefined, Null, Boolean, Number, Symbol, or String as defined in clause 6"
*/
var Person = function(x){
return x;
};
console.log(Person.constructor);
console.log(Person.prototype.constructor);
console.log(typeof(Person));
console.log(typeof(Person.prototype));
function log(x){
console.log(x instanceof Person);
console.log(typeof x);
console.log(typeof x.prototype);
}
log(new Person(undefined));
log(new Person(null));
log(new Person(true));
log(new Person(2));
log(new Person(""));
//returns a function not an object
log(new Person(function(){}));
//implementation?
//log(new Person(Symbol('%')));
Ответ 3
Я не мог найти никакой документации по этому вопросу, но я думаю, что вы правы. Например, вы можете вернуть new Number(5)
из конструктора, но не буквенный 5
(который игнорируется, а this
возвращается вместо этого).
Ответ 4
Попытка выразить несколько слов более простыми словами.
В JavaScript, когда вы используете ключевое слово new
для функции и если
- функция ничего не возвращает, она вернет намеченный объект
function User() {
this.name = 'Virat'
}
var user = new User();
console.log(user.name); //=> 'Virat'
Ответ 5
В качестве побочного примечания возвращаемое значение или this
является лишь частью уравнения.
Например, рассмотрим следующее:
function Two() { return new Number(2); }
var two = new Two;
two + 2; // 4
two.valueOf = function() { return 3; }
two + 2; // 5
two.valueOf = function() { return '2'; }
two + 2; // '22'
Как вы можете видеть, .valueOf()
используется внутри и может использоваться для удовольствия и прибыли. Вы даже можете создавать побочные эффекты, например:
function AutoIncrementingNumber(start) {
var n = new Number, val = start || 0;
n.valueOf = function() { return val++; };
return n;
}
var auto = new AutoIncrementingNumber(42);
auto + 1; // 43
auto + 1; // 44
auto + 1; // 45
Я могу себе представить, что это должно иметь какое-то практическое применение. И это не обязательно должно быть явно Number
, если вы добавите .valueOf
к любому объекту, который может вести себя как число:
({valueOf: function() { return Math.random(); }}) + 1; // 1.6451723610516638
Вы можете использовать это, чтобы создать объект, который всегда возвращает новый GUID, например.
Ответ 6
Когда вы используете ключевое слово new
, создается объект. Затем вызывается функция для инициализации объекта.
Нет ничего, что могла бы сделать функция, чтобы предотвратить создание объекта, как это делается до вызова функции.