Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Выяснить, что функция вызвана в режиме конструктора (https://javascript.ru/forum/misc/21065-vyyasnit-chto-funkciya-vyzvana-v-rezhime-konstruktora.html)

Octane 27.08.2011 14:04

Выяснить, что функция вызвана в режиме конструктора
 
Есть идеи, как внутри F различать способы вызова?

function F() {}

new F;
F.call(new F);
F();


обычно делаю так
function F() {
    if (this.constructor == F) {
        return 1;
    }
    return 2;
}


Но понадобилось отделить вариант с F.call(obj), и вот когда obj - это объект, созданный с помощью F, такая проверка не подходит. Нужно отделить способы запуска [[Construct]] и [[Call]].

melky 27.08.2011 14:20

я не вижу возможного решения.

т.е. как разделить эти два вызова ?
function F(){ this.a=function(){}; }

var a = new F;

var b = new F;

a.a();
// и 
F.call( b ).a();

Octane 27.08.2011 14:24

Ну решение есть:
function F() {
	if (this.constructor == F) {
		if (this._constructed) {
			alert("F.call(new F)");
			return null;
		}
		this._constructed = true;
		return this;
	}
	return null;
}

new F;

F.call(new F);

F.call({});

F();

Просто может я торможу и еще как-то проще/лучше/надежнее можно сделать. Не очень хочется иметь ненужное enumerable-свойство в каждом объекте.

melky 27.08.2011 14:36

Цитата:

Сообщение от Octane (Сообщение 122907)
Просто может я торможу и еще как-то проще/лучше/надежнее можно сделать. Не очень хочется иметь ненужное enumerable-свойство в каждом объекте.

Object.defineProperty ? ie9+

Octane 27.08.2011 14:41

Да смысл, надо будет помнить о дополнительных проверках для старых браузеров.

Sweet 27.08.2011 15:00

Цитата:

Сообщение от Octane
Не очень хочется иметь ненужное enumerable-свойство в каждом объекте.

Можно не создавать спецальное свойство, а смотреть на какое-нибудь, какое есть:)

tenshi 27.08.2011 20:13

а зачем их отличать? constructor - обычный метод, который предназначен для инициализации объекта. запись ( new F( 1, 2, 3 ) ) - это просто грубо говоря более короткая запись следующей ( var obj= {}; obj.__proto__= F.prototype; return obj.constructor( 1, 2, 3 ) || obj )

Octane 27.08.2011 20:49

function F(x) {
	if (this.constructor == F) {
		this.x = x;
	}
	return this.x;
}

var f = new F(3), obj = {x: 5};

alert(f.x); //3

alert(F.call(obj)); //5
*!*
alert(F.call(f)); //ожидаем получить 3, а будет undefined
*/!*

Sweet 27.08.2011 21:01

В конкретном примере было бы уместно проверять, передан ли аргумент:
if (this.constructor == F && arguments.length > 0) {

B@rmaley.e><e 27.08.2011 21:49

Обыграть то, что в случае вызова через new F сначала создается пустой объект, а потом уже к нему применяется конструктор. В случае с call'ом к объекту уже применён конструктор.
function F(x) {
	if (this.constructor == F && this.sealed === undefined) {
		this.x = x;
	}
	this.sealed = true;
	return this.x;
}

var f = new F(3), obj = {x: 5};

alert(f.x); //3

alert(F.call(obj)); //5
alert(F.call(f)); //ожидаем получить 3, а будет 3


Часовой пояс GMT +3, время: 22:48.