Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 11.02.2011, 12:32
Новичок на форуме
Отправить личное сообщение для stnw Посмотреть профиль Найти все сообщения от stnw
 
Регистрация: 13.11.2010
Сообщений: 7

область видимости переменных в prototype (тупой вопрос))
Добрый день!

Пытаюсь разобраться по прочтении статьи о наследовании (http://javascript.ru/tutorial/object/inheritance). Как я понял, методы и свойства объявленные в прототипе класса становятся общие для всех объектов. И в статье даже приводится пример:

В него я добавил лишь одно дополнительное свойство something. Но почему-то в другом объекте оно осталось прежним. Получается, что свойство something создалось для каждого объекта.

function Hamster() {  }
Hamster.prototype = {
    food: [],
    something: 'no',
    found: function(something) {
        this.food.push(something)
		this.something = something;
    }
}
speedy = new Hamster()
lazy = new Hamster()
 
speedy.found("apple")
speedy.found("orange")
 
alert(speedy.food.length) // 2
alert(lazy.food.length) // 2 (!??)

alert(speedy.something) // orange
alert(lazy.something) // no //почему no???


Просьба простить за глупый вопрос и наставить на путь истинный.
Заранее благодарен!
Ответить с цитированием
  #2 (permalink)  
Старый 11.02.2011, 15:49
Аватар для B@rmaley.e><e
⊞ Развернуть
Отправить личное сообщение для B@rmaley.e><e Посмотреть профиль Найти все сообщения от B@rmaley.e><e
 
Регистрация: 11.01.2010
Сообщений: 1,810

function Hamster() {  }
Hamster.prototype = {
    food: [],
    something: 'no',
    something1: {p:0},
    found: function(something) {
		this.food.push(something)
		this.something = something;
		this.something1 = {p:Math.random()};
    }
};
speedy = new Hamster();
lazy = new Hamster();
 
speedy.found("apple");
speedy.found("orange");
 
alert([
  'Speedy: ' + speedy.food,
  'Lazy: ' + lazy.food,
  'Prototype: ' + Hamster.prototype.food
].join('\n')); 

alert([
  'Speedy: ' + JSON.stringify(speedy.something1),
  'Lazy: ' + JSON.stringify(lazy.something1),
  'Prototype: ' + JSON.stringify(Hamster.prototype.something1)
].join('\n')); 

alert([
  'Speedy: ' + speedy.something,
  'Lazy: ' + lazy.something,
  'Prototype: ' + Hamster.prototype.something
].join('\n'));
Все дело в том, что food - массив (и, соответственно, объект). При обращении к this.food JS сначала пойдет искать свойство food у самого объекта, а потом, не найдя его, пойдет по цепочке прототипов (напоминаю, что при использовании оператора new ссылка на объект-прототип просто записывается во внутреннее свойство [[Prototype]]). В Hamster.prototype он найдет искомое значение и вернет ссылку на него. Ссылку на food из прототипа (!). Не удивительно, что изменится food в прототипе, а не объекте (в объекте свойства food, вообще говоря, нет).

Рассмотрим подробнее, почему так происходит.
1. JS "считывает" this.food.
2. Применяется оператор доступа к свойству. Мы получаем Refernce-объект с базой this (на самом деле не this, а именно тот объект, на который он ссылается) и именем свойства food.
3. Далее "считывается" .push.
4. Снова тот же оператор, и мы получаем в качестве базы значение предыдущего Reference-объекта и именем свойства push. Теперь подробнее о значении Reference-объекта: в ходе выполнения [[Get]]
JS не находит значения food как собственного свойства объекта и идет в объект-прототип [[Prototype]]. Соответствено, значением Reference-объекта будет объект food прототипа, т.е. [[Prototype]].food.
5. Считываются и обрабатываются аргументы метода, это нам сейчас не важно.
6. Вызывается метод. В качестве this берется база нового Reference-объекта (см. шаг 6). А эта самая база указывает на [[Prototype]].food. Соответственно, и изменения будут проведены над этим объектом.

Казалось бы, почему тогда поведение something отличается? Тут все дело в том, что мы не обращаемся к свойству

1. JS "считывает" this.something.
2. Применяется оператор доступа к свойству. Мы получаем Refernce-объект с базой this и именем свойства something.
3. Далее "считывается" оператор присваивания.
4. В ходе записи значения в Reference вызывается метод [[Put]] объекта, который лежит у нас в базе (а это - тот самый, на кого указывает this), и этот метод записывает присваиваемое значение свойству самого объекта, а не его прототипа. По-сути, его совсем не волнует, что такое something и откуда оно пришло. Он просто запишет нужное свойство. В случае с массивом нам пришлось обратиться к значению this.food, когда мы использовали оператор обращения к свойству.
Ответить с цитированием
  #3 (permalink)  
Старый 11.02.2011, 17:53
Новичок на форуме
Отправить личное сообщение для stnw Посмотреть профиль Найти все сообщения от stnw
 
Регистрация: 13.11.2010
Сообщений: 7

Большое спасибо за подробный ответ, вроде все становится на свои места.

Для закрепления еще вопрос: я правильно понимаю, что если мы используем свойство property как константу, то ее выгодней держать в прототипе (она не будет занимать место в памяти, а каждый раз будет браться из прототипа)? Если же производятся манипуляции с этой переменной в методах класса, то следующие записи будут аналогичны (т.к. свойство все равно каждый раз будет обновляться в самом объекте).

function Class() {
this.property = 0;
}

function Class() {}
Class.prototype.property = 0;

Спасибо заранее.
Ответить с цитированием
  #4 (permalink)  
Старый 11.02.2011, 19:25
Аватар для B@rmaley.e><e
⊞ Развернуть
Отправить личное сообщение для B@rmaley.e><e Посмотреть профиль Найти все сообщения от B@rmaley.e><e
 
Регистрация: 11.01.2010
Сообщений: 1,810

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

Записи аналогичны (функционально, конечно) до тех пор, пока Вы не будете изменять то, что находится в прототипе (как это происходило с массивом food).
Ответить с цитированием
Ответ


Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
область видимости переменных jetli13 Общие вопросы Javascript 3 17.09.2010 11:00
Область видимости внутри функции YISHIMITSY Общие вопросы Javascript 1 25.08.2010 06:50
Область видимости методов mexoboy Общие вопросы Javascript 10 10.08.2010 13:09
Вопрос тупой, как сделать обычное по со списком или combobox иначе ? dennnyk Элементы интерфейса 1 07.07.2010 06:59
можно ли включить функцию в глобальную область видимости из файла maxval Элементы интерфейса 13 04.10.2009 07:11