[JS] левые кросс-объектные поля (а-ля static var в классе)
От: DPP Россия  
Дата: 22.11.06 00:51
Оценка:
Hi!

Не приятная фишка Все браузеры дают одно, так что это фишка а не баг...
может кто-нибудь объяснить вывод этого скрипта?
<script>

function cl(x){
    alert(this.i[0]+','+this.j[0]);

    this.i.push(x);
}
cl.prototype={
    i:[],
    j:[0]
}

var a=new cl(1);
var b=new cl(2);

</script>

undefined,0
1,0
Обнаружил чисто случайно. после того как раз 20 все переписал с нуля, увершал все что можно затычками и пр. Очень забавно получилось — управляешь одним объектом, а реагирует другой только по тому и нашел.


Попутно задам вопрос: вы как пишите (если пишите много)?
// 1 (-) очень много писанины, довольно слепо
//   (-) конструктор создает все поля объекта, а не берет готовый объект и инициализирует его.
function cl(){
  this.a=0;
  this.f=f;
  // объявили все поля в начале, потом конструктор и вложенные функции
  function f(){}
}


// 2 (-) ни хрена не понятно :) но чаще всего именно так
function cl(){
  this.a=0;
  // где надо там и создали поле
  this.f=function(){}
}


// 3 (+) минимум писанины, предельно структурированно и понятно
//   (-) debuger часто не может поставить breakpoint на середину функции f() (получается на весть cl.prototype=...)
//   (-) в debuger в стеке вызовов надписи про анонимную функцию, а не ее имя.
//   (-) пока это туго понимают редакторы 
//   (?) если бы ни штука о которой я писал выше, то так бы было удобнее всего. а так - прийдется переписывать 60кб убористого кода 15 классов... :crash: 
function cl(){ this._construct(); }
cl.prototype={
  a:0;
  f:function(){}
}
Re: [JS] левые кросс-объектные поля (а-ля static var в класс
От: Alexey Shtokalo Россия http://alexey.shtokalo.net
Дата: 22.11.06 07:59
Оценка: 3 (2)
Здравствуйте, DPP, Вы писали:

На самом деле описанные пример совсем не фишка и даже не ошибка, а вполне закономерные результат.
Сравним со следующим примером, чтобы понять почему произошла описанная ситуация:


<script>

function mycl(x)
{
    this.i = [];
    this.j = [0];
    alert(this.i[0]+','+this.j[0]);
    this.i.push(x);
}

var a=new mycl(1);
var b=new mycl(2);

</script>


Данные код создает два объекта a и b с полями i = [], j = [0]. Обращаю внимание что эти
объекты отличаются от объектов в исходном примере. И отличаются они ровно своими полями.
В исходном примере поля i и j создавались на этапе объявления прототипа объекта. Это
значит что сколько бы экземпляров мы не создавали — эти поля изначально будут ссылаться
на одни и те же объекты — массивы. В моем примере мы создаем поля в конструкторе и
следовательно сам прототип ничего не знает об этих полях, хотя они и есть в объектах.

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

Ответ на вопрос, о том кто и как пишет.. Это конечно на любителя, но я пишу так:


function A(x, y, z)
{
    this.x = x;
    this.y = y;
    this.z = z;
}

A.prototype.xy = function()
{
    return x * y;
}

A.prototype.yz = function()
{
    return y * z;
}


Почему так, а не иначе:
1) Объявление полей в конструкторе позволяет избежать ситуации описанной в исходном примере,
если подобное поведение не является необходимым.
2) Отдельное объявление каждого метода — наверное спорно, но мне кажется так легче читать код,
особенно когда методы большие и их много — сразу понятно чей это метод. И еще один аргумент —
при таком подходе очень легко выдергивать некоторые методы из основного кода и выносить их в
отдельные файлы или дописывать новые методы и подключать их из дополнительных файлов. При этом
весь код, и основной, и в дополнительных файлах выглядит одинаково, что упрощает его чтение.
Re: [JS] левые кросс-объектные поля (а-ля static var в класс
От: Zeroglif  
Дата: 22.11.06 08:07
Оценка: 2 (1)
Здравствуйте!

Несмотря на то, что вы создаёте два разных экземпляра, внутри конструктора вы "управляете" общим для них обоих объектом-прототипом, его свойствами, т.к. непосредственно у экземпляров нет своих "собственных" свойств с именами i и j. Всё стандартно.

— При первом вызове конструктора массив i пустой, поэтому в алерте undefined.
— Перед выходом из конструктора заталкиваем в массив i элемент со значением 1.
— При втором вызове конструктора в алерте виден тот самый первый элемент со значением 1.

Пара ссылок на эту тему и на тему подходов к созданию экземпляров:
http://weblogs.asp.net/bleroy/archive/2006/10/07/Careful-with-that-prototype_2C00_-Eugene.aspx
http://weblogs.asp.net/bleroy/archive/2006/10/11/From-closures-to-prototypes_2C00_-part-1.aspx
http://weblogs.asp.net/bleroy/archive/2006/10/14/From-closures-to-prototypes_2C00_-part-2.aspx
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.