Выяснить, что функция вызвана в режиме конструктора
Есть идеи, как внутри 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]]. |
я не вижу возможного решения.
т.е. как разделить эти два вызова ?
function F(){ this.a=function(){}; }
var a = new F;
var b = new F;
a.a();
// и
F.call( b ).a();
|
Ну решение есть:
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-свойство в каждом объекте. |
Цитата:
|
Да смысл, надо будет помнить о дополнительных проверках для старых браузеров.
|
Цитата:
|
а зачем их отличать? constructor - обычный метод, который предназначен для инициализации объекта. запись ( new F( 1, 2, 3 ) ) - это просто грубо говоря более короткая запись следующей ( var obj= {}; obj.__proto__= F.prototype; return obj.constructor( 1, 2, 3 ) || obj )
|
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
*/!*
|
В конкретном примере было бы уместно проверять, передан ли аргумент:
if (this.constructor == F && arguments.length > 0) {
|
Обыграть то, что в случае вызова через 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
|
В третьем сообщении я привел такой же пример решения с помощью дополнительного свойства.
|
Цитата:
function F(x) {
if (this.constructor == F && !F.i) {
F.i = 1;
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
|
Так конструктор будет одноразовый
|
тфу, чуть не так хотел.
function F(x) {
if (this.constructor == F && !this.constructor.i) {
this.constructor.i = 1;
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
|
Так в этом случае
Цитата:
|
точно. забыл что конструктор это ссылка.
|
ну, пожалуй, последний мой вариант:):
function isEmptyObj(obj) {
var a; for(a in obj) {return false;}
return true;
}
function F(x) {
if (this.constructor == F && isEmptyObj(this)) {
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
|
Только hasOwnProperty надо добавить.
|
| Часовой пояс GMT +3, время: 06:34. |