Javascript объектный литерал: значение инициализации? - PullRequest
8 голосов
/ 22 сентября 2010

Я использовал объектный литерал для создания объекта с методами.
Вот простой пример.

var SizeManager = {
    width : 800,
    height : 600,
    ratio : this.width / this.height,
    resize : function (newWidth) {
        width = newWidth;
        height = newWidth / ratio;
    }
}

Моя проблема в том, что SizeManager.ratio возвращает " NaN ".Я совершенно уверен, что это проблема инициализации.
Есть ли способ получить правильное значение отношения?
Есть ли способ присвоить конструктору или инициализатору литерал объекта?
Определяет конструктор objcetединственный способ?

РЕДАКТИРОВАТЬ: конечно, SizeManager в идеале является одиночным (только один объект), поэтому я использовал объектный литерал.

Ответы [ 3 ]

24 голосов
/ 22 сентября 2010

Да, это проблема инициализации.this не относится к вашему SizeManager объекту в том месте, где вы его используете.(Инициализаторы объектов не изменяют значение this.) this устанавливается в зависимости от того, как вы вызываете функцию, и имеет одинаковое значение в течение всего вызова этой функции.Вы не вызываете каких-либо функций, поэтому this имеет любое значение, которое имело до начала этого кода.

(я указал кое-что о ratio изВаш конкретный пример в самом конце этого, но сначала давайте рассмотрим несколько вариантов для общего случая, который вы подняли.)

Даниэль дал вам хорошее руководство для создания ratio aкроме как он, кажется, не понял, что вы хотите изменить ширину.В качестве альтернативы, если width и height не собираются изменяться, просто рассчитайте его позже:

var SizeManager = {
    width : 800,
    height : 600,
    resize : function (newWidth) {
        this.width = newWidth;
        this.height = newWidth / this.ratio;
    }
};
SizeManager.ratio = SizeManager.width / SizeManager.height;

(Примечание: я добавил this. к свойствам, на которые вы ссылаетесь вresize. Они отсутствовали в вашем оригинале, но они необходимы. Без них вы имеете дело с ужасом неявных глобалов , который является Плохой вещью (tm) .)

Конечно, вы можете инкапсулировать все это в фабрику:

function makeSizeManager(width, height) {
    return {
        width : width,
        height : height,
        ratio : width / height,
        resize : function (newWidth) {
            this.width = newWidth;
            this.height = newWidth / this.ratio;
        }
    };
}
var SizeManager = makeSizeManager(800, 600);

... но тогда вы также можете сделать это реальной функцией конструктора, чтобы вы не• создать множество дублирующих (но идентичных) функций resize:

function SizeManager(width, height) {
    this.width = width;
    this.height = height;
    this.ratio = width / height;
}
SizeManager.prototype.resize = function (newWidth) {
    this.width = newWidth;
    this.height = newWidth / this.ratio;
};
var aSizeManagerInstance = new SizeManager(800, 600);

(Обратите внимание, что я немного изменил имена в этом последнем).

И в качестве последнего замечания:В вашем конкретном примере вам вообще не нужно хранить ratio, вы можете сделать это:

var SizeManager = {
    width : 800,
    height : 600,
    resize : function (newWidth) {
        var ratio = this.width / this.height;
        this.width = newWidth;
        this.height = newWidth / ratio;
    }
};

Но это только для этого конкретного примера, отсюда и обсуждение выше, чтобы поговорить об общемслучай.

5 голосов
/ 22 сентября 2010

Ваше свойство ratio на самом деле должно быть методом, если вы хотите изменить его, основываясь на изменениях width и height:

var SizeManager = {
    width : 800,
    height : 600,
    ratio : function() {
      return this.width / this.height;
    },
    resize : function (newWidth) {
        width = newWidth;
        height = newWidth / ratio;
    }
}

Кроме того, вы, вероятно, хотите сослаться на this.width и this.height вместо width и height в методе resize.

0 голосов
/ 22 сентября 2010

В литерале объекта this относится только к самому литералу объекта, когда он находится внутри функции.Вы можете попробовать нечто подобное вместо литерала объекта;this будет ссылаться на объект, который вы создаете как внутри, так и снаружи функций.

var SizeManager = new function(){
    this.width = 800;
    this.height = 600;
    this.ratio = this.width / this.height;
    this.resize = function (newWidth) {
        this.width = newWidth;
        this.height = newWidth / this.ratio;
    }
}

Это будет работать для одноэлементного шаблона.Если вам нужно более одного SizeManager, сделайте его функцией конструктора вместо объекта.

function SizeManager (w, h){
  w && (this.width=w);
  h && (this.height=h);
  this.ratio = this.width / this.height;
}
SizeManager.prototype={ 
  width: 800,
  height: 600,
  resize: function (newWidth) {
    this.width = newWidth;
    this.height = newWidth / this.ratio;
  }
}
...