Выяснить, что функция вызвана в режиме конструктора
Есть идеи, как внутри 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, время: 18:50. |