оцените такой подход создания классов
Сабж. Насколько такой подход уместен в JS? Какие могут быть проблемы?
var popupObject = {
// URL обработчика
url: null,
// Данные для запроса
data: {},
// Функция, которая будет выполнена в случае выполнения запроса
success: function(data, textStatus, jqXHR){
// Пустая функция, не надо сюда ничего писать
},
/**
* Конструктор объекта.
*
* @param string url путь к обработчику запроса
* @param object data данные для запроса
* @param function success функция, которая выполнится в случае выполнения запроса
* @return object this
*/
constuctor: function(url, data, success){
this.url = url;
this.data = data !== undefined ? data : this.data;
this.success = success !== undefined ? success : this.success;
return this;
},
/**
* Основной метод, выполняющий запрос, прорисовывающий данные из ответа и
* исполняющий метод success
*/
run: function() {
$j.ajax({
type: "POST",
url: this.url,
data: this.data,
cache: false,
context: this,
success: function(data, textStatus, jqXHR){
if (data.status.toLowerCase() === 'ok') {
this.embed(data);
this.success(data, textStatus, jqXHR);
} else {
if (window.console && window.console.log) {
// console.log(data);
}
}
}
});
},
/**
* Метод, выполняющий вставку данных из ответа куда-либо.
* В нашем случае - в попап.
* Данный метод можно перегрузить и вставлять данные куда угодно, в любое мето в DOM-дереве.
*
* @param array data response данные
*/
embed: function(data) {
var unique_id = 'unique_' + this.rand();
var full_id = unique_id + '_for_popup';
$j('<div id="' + full_id + '" style="display:none"></div>').appendTo('body').append(data.content);
openStaticPopup(unique_id);
$j('#' + full_id).remove();
},
rand: function() {
return Math.floor(Math.random() * 1000);
}
};
|
Василий Б., и как этим пользоваться?
|
danik.js,
success = function(data){
// функция исполнится после успешного выполнения ajax запроса, аналог success в API jQuery
}
var popup = popupObject.constuctor('/ajax/popup_delivery.php', {id: 123}, success);
popup.run();
// или
popupObject.constuctor('/ajax/popup_delivery.php', {id: 123}, success).run();
типа того. просто как пример класса, что он делает - не так уж и важно (получает html из json и рендит его либо в попап, либо в любое место в DOM структуре). Меня просто интересовало, подобный подход чем-то отличается от подхода, когда мы объявляем функцию со свойствами и методами через this, вот так:
function foo() {
this.var1 = 123;
this.bar = function(){
// do
}
}
|
А каким боком это класс? Как можно создать два экземпляра этого класса?
|
ага, ща допишем...
|
Цитата:
создавать экземпляры нельзя, но вот наследовать его можно : var popupMastaa = Object.create(popupObject); вуаля, у нас есть новый объект, прототипом которого является popupObject. |
Вот только нафига метод constructor. Какой же это конструктор.
|
melky,
а что должно быть в create методе? Чисто так, для любопытства спрашиваю.. Назначить прототипом Object мой объект popupObject? Цитата:
/**
* Конструктор объекта.
*
* @param string url путь к обработчику запроса
* @param object data данные для запроса
* @param function success функция, которая выполнится в случае выполнения запроса
* @return object this
*/
constuctor: function(url, data, success){
this.url = url;
this.data = data !== undefined ? data : this.data;
this.success = success !== undefined ? success : this.success;
// Поскольку в JS нет классов, то мы создаем копию данного объекта (this)
// и возвращаем его, что бы иметь возможность создавать несколько экземпляров объекта popupObject.
var o = new Object();
for (var i in this) {
if (this.hasOwnProperty(i)) {
o[i] = this[i];
}
}
return o;
},
и это работает, я пробовал создать два класса с разными параметрами. Ура! Только я от не понял одного - я пытался изначально написать код клонирования объекта так:
var o = new Object();
for (var i in this) {
if (this.hasOwnProperty(i)) {
console.log(i + ' ' + this.i);
}
}
вот что мне выдало в консоли: Цитата:
this.i- undefined. В упор не понимаю, почему так происходит. По идее, в i у меня содержится имя свойства. Почему я через точку не могу получить доступ к свойствам? |
Цитата:
Цитата:
Вопрос - с какой целью ты пытаешься изобрести классы? Ради экспериментов? Или свято веришь что что-то изобретешь новое? Или просто не знаешь основ JS и пытаешься по не знанию создать свой велосипед? Цитата:
|
Цитата:
что значит постоянно изменяться? я создаю отдельный объект с какими-то свойствами. с помощью клонирования объекта я могу создать два разных объекта, у них разные свойства. это то, что мне нужно - эмуляция классов. Вопрос - с какой целью ты пытаешься изобрести классы?ради удобства разработки. да я и не пытаюсь изобрести классы. |
var popup = popupObject.constuctor('/ajax/popup_delivery.php', {id: 123}, success);
console.log(popupObject.url); // что выдаст? Зачем это свойство хранится? Цитата:
|
Цитата:
function foo()
{
this.prop = ...
}
? Цитата:
popupObject.constructor(...) Вы что предлагаете? Сделать "uset" или.. вообще не писать в popupObject? Вот так:
constuctor: function(url, data, success){
// Поскольку в JS нет классов, то мы создаем копию данного объекта (this)
// и возвращаем его, что бы иметь возможность создавать несколько экземпляров объекта popupObject.
var o = new Object();
for (var i in this) {
if (this.hasOwnProperty(i)) {
o[i] = this[i];
}
}
// свойства назначаем только конкретному объекту
o.url = url;
o.data = data !== undefined ? data : this.data;
o.success = success !== undefined ? success : this.success;
return o;
},
Так? |
Цитата:
это ... как из дивана пытаться делать завод по изготовлению мебели. надеюсь, меня поняли :) Цитата:
рекомендую открыть learn.javascript.ru и почитать про способы создание объектов ... там уже есть вся инфа :) Цитата:
Цитата:
еще раз рекомендую открыть learn.javascript.ru :)
function Blah () {
}
var myBlah = new Blah();
|
да читал я 20 раз это все уже. меня интересует оптимальный подход создания объектов а-ля класс.
Конструкторы мне не нравятся. Они не логичны что ли... вот я на конструкторе писал класс для работы с Аякс:
function Ajax()
{
/**
* Экземпляр XMLHttpRequest.
*
* @access private
* @var object XMLHttpRequest
*/
var req;
/**
* HTTP-заголовки
*
* @access private
* @var array
*/
var httpHeaders = {"If-Modified-Since" : "Sat, 1 Jan 2000 00:00:00 GMT"}
/**
* Описания статусов readyState
*
* @access private
* @var array
*/
var statuses = ['Не инициализиован',
'Метод open() вызван, запрос не отправлен',
'Запрос был передан',
'Ответ сервера принят частично',
'Данные приняты, соединение закрыто'];
this.addUniqueQS = false;
/**
* Создает объект XMLHttpRequest
*
* @param void
* @return XMLHttpRequest|null
*/
(function()
{
if (window.XMLHttpRequest) {
try {
req = new XMLHttpRequest();
} catch (e){}
}
// only IE 6 =<
else if (window.ActiveXObject) {
try {
var aVersions = ["MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0",
"MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp",
"Msxml2.XMLHTTP", 'Microsoft.XMLHTTP'];
for (var j in aVersions)
{
try {
req = new ActiveXObject(aVersions[j]);
break;
} catch (e){}
}
} catch (e){}
}
if (!req)
{
throw new Krugozor_Exception(_CONFIG.messages[_CONFIG.lang].ajax.xmlhttprequest_not_found);
}
})();
/**
* Метод принимает в качестве аргумента анонимную функцию,
* которая привязывается к обработчику onreadystatechange.
* Функция должна иметь интерфейс для принятия двух объектов:
* - первый объект - ссылка на Ajax объект
* - второй объект - ссылка на объект xmlHttpRequest
*
* @param object
* @return void
*/
this.setObserverState = function(observer_function)
{
var ajax_object = this;
var req_object = req;
this.observerState = function()
{
if (req_object.readyState == 4) {
if (req_object.status == 200) {
observer_function(ajax_object, this);
}
}
}
return this;
}
/**
* Абстрактный предопределяемый метод, привязанный
* к обработчику onreadystatechange.
* Пример предопределения в клиентском скрипте:
*
* var ajax = new Ajax();
* ajax.observerState = function()
* {
* if (ajax.getHttpRequest().readyState == 4) {
* if (ajax.getHttpRequest().status == 200)
* {
* alert(ajax.getHttpRequest().responseText)
* }
* }
* }
*
* @param void
* @return mixed
*/
this.observerState = function()
{
if (req.readyState == 4) {
if (req.status == 200) {
alert('Метод observerState должен быть предопределен перед использованием объекта');
}
}
}
/**
* Отправляет GET-запрос по адресу url
*
* @param string url
* @param boolean синхронность запроса.
* true - асинхронный, false - синхронный
* @return void
*/
this.get = function(url, synchronicity)
{
if (arguments.length == 1)
{
synchronicity = true;
}
if (!!this.addUniqueQS)
{
url += (url.indexOf('?') == -1 ? '?' : '&') + Math.floor(Math.random()*1000);
}
req.open('GET', url, !!synchronicity);
this.sendHeaders();
if (synchronicity)
{
req.onreadystatechange = this.observerState;
}
req.send(null);
return this;
}
/**
* Устанавилвает заголовок HTTP с ключом key
* и значением value.
*
* @access public
* @param key имя HTTP-заголовка
* @param value значение HTTP-заголовка
* @return void
*/
this.setHeader = function(key, value)
{
httpHeaders[key] = value;
}
/**
* Отправляет HTTP-заголовки.
*
* @access private
* @param void
* @return void
*/
this.sendHeaders = function()
{
for (var i in httpHeaders)
{
if (typeof httpHeaders[i] == 'string')
{
req.setRequestHeader(i, httpHeaders[i]);
}
}
}
/* Методы получения ответа (XMLHttpRequest) и результата из ответа */
/**
* Возвращает экземпляр объекта XMLHttpRequest
*
* @param void
* @return object req
*/
this.getHttpRequest = function()
{
return req;
}
/**
* Возвращает статус HTTP
*
* @param void
* @return int
*/
this.getStatus = function()
{
return req.status;
}
/**
* Возвращает стандартный объект JS, который является
* "сериализованным" объектом в виде строки текста ответа - JSON.
*
* @access public
* @param void
* @return object
*/
this.getJson2HashByKey = function()
{
return eval( "(" + req.responseText + ")" );
}
/**
* Возвращает текст ответа сервера
*
* @access public
* @param void
* @return string
*/
this.getText = function()
{
return req.responseText;
}
}
Пример использования:
// Для асинхронных запросов:
var async_ajax = new Ajax();
async_ajax.setObserverState(
function(ajx, xhr) {
alert( ajx.getJson2HashByKey() + ' ' + xhr.responseText);
}
).get("/ajax/country");
Ещё один способ пробовал, но это я так понимаю jQuery стиль и это сингелтон:
var click = (function(){
var prop = '...';
var method = function(){
// do it
}
return {
init: method
}
})();
var myClick = click.init();
и т.д.Этот способ по вашему лучше, чем описанный в первом посте? |
Цитата:
в JavaScript прототипное программирование... а это значит, что вы должны писать таким способом, и более пока никак идти против языка нет смысла - только добавит тормозов конечно, можно заюзать библиотеки для облегчения объектного программирования, но это уже сами :) |
melky,
Цитата:
Я кажется понимаю что такое прототип и чем он отличается от свойства объекта:
function Base(){
this.f11 = function(){alert('call Base::f11')}
};
Base.prototype.f1 = function(){alert('call Base::f1');}
function Parent(){
this.f11 = function(){alert('call Parent::f11')}
}
Parent.prototype.f1 = function(){alert('call Parent::f1')}
Parent.prototype = new Base();
var o = new Parent();
o.f1(); // `call Base::f1` - перезагрузили Parent::f1 методом из прототипа Base?
o.f11(); // `call Parent::f11` - перезагрузки не произошло, т.к. ф-ия f11() - свойство объекта, а не прототипа
правильно ли я понимаю отличие прототипа от свойства объекта? |
Это один и тот же подход. Просто в конструкторе нужно назначать свойства экземпляра (личные), а в прототипе - свойства прототипа (обычно методы). Почитай хотя бы http://learn.javascript.ru/prototype
|
danik.js,
как из можно назвать личными, если
function Base(){
this.f = function(){alert('Base::f')}
};
function Parent(){}
Parent.prototype = new Base();
(new Parent()).f();
метол f доступен в Parent! Не могу понять почему.. метод f - это свойство объекта Parent, а не прототипа Base? |
Под "личными" я не имел ввиду private. Я имел ввиду принадлежащие экземпляру.
Цитата:
|
danik.js,
да читал я материал, читал! Там написано следующее: Цитата:
Цитата:
Свойства ищутся в прототипе объекта. Правильно ли я понимаю, что только при использовании new в дочерний объект подтягиваются ВСЕ свойства объекта-прототипа?
Base = function(){};
Parent = function(){};
Parent.prototype = new Base();
var o = new Parent();
Base.func_as_prop = function(){};
Base.prototype.func_in_proto = function(){};
console.log(o.func_as_prop); // undefined - в объекте o нет свойства, т.к. оно не было подтянуто конструктором
console.log(o.func_in_proto); // function
console.log(Base.func_as_prop); // function
console.log(Base.func_in_proto); // почему undefined? почему не ищет в своем прототипе?
|
Цитата:
в ES5 добавили возможность смотреть на них, и управлять ими
Object.getOwnPropertyDescriptor({ "foo": "bar" }, "foo");
// удобнее смотреть в консоли разработчика
ссылка на MDN как видим, нет параметра "наследуемый", т.е. все свойства в объектах JavaScript по умолчанию публичные. поэтому мы их видим, когда присваиваем прототипу одного объекта другой. |
Цитата:
Вобще, открой консоль, накалякай там ченибудь да поизучай объекты. Я использую Chrome, там консоль как мне кажется самая удачная. |
| Часовой пояс GMT +3, время: 19:54. |