Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #21 (permalink)  
Старый 23.07.2015, 18:29
Аватар для Lemme
Профессор
Отправить личное сообщение для Lemme Посмотреть профиль Найти все сообщения от Lemme
 
Регистрация: 15.07.2015
Сообщений: 511

tysonfury2015, надеюсь, когда нибудь ты отойдешь от той "хрени", которую ты употребляешь, ибо такую ересь можно "нести" только в нетрезвом состоянии.

По делу:

tsigel, попробовал учесть все ваши замечания, кроме методов в 3-4 строки =). Ну и немного изменил хранилище данных (точнее его наполнение), ибо столкнулся с проблемой его переполнения.

class Tysonfury2015_idi_mimo{
	/**
	 * @constructor
	 * @param  {Object} config{url: 'path/to/json', perPage: Integer, output: { container: 'element class/id'}}
	 */
	constructor(config){
		this.config = config;
		this.init();
		this.storageToken = 'Data__' + Math.round(new Date().getTime() / 1000);
	}
	/**
	 * Получет данные в формате JSON по адресу this.config.url
	 * 
	 * @param  {Callback}
	 */
	getData(success){
		fetch(this.config.url)
			.then((response)=>{
				if (response.status !== 200){
					console.error('Response error! Status - '+response.status);
					return;
				}
				response.json().then((response)=>{
					success(response);
				});
			})
		.catch((error)=>{
			console.error(error);
		});
	}
	/**
	 * Рабиваем массив с данными по страницам 
	 * 
	 * @param  {Array}
	 */
	splitDataByPages(data){
		let	pages		= [],
			header  	= data.shift(),
			numPages	= Math.ceil(data.length / this.config.perPage);


		for (let i = 0; i < numPages; i++){
			pages[i] = [];
			for(let j = 0; j < this.config.perPage; j++){
				if (data.length === 0) break;
				pages[i].push(data.shift());
			}
		}

		this.putDataToStorage({header, pages});
	}
	/**
	 * Добавляет данные в sessionStorage
	 * 
	 * @param data
	 */
	putDataToStorage(data){
		sessionStorage.setItem(this.storageToken, JSON.stringify(data));
	}
	/**
	 * Возвращает данные из sessionStorage
	 * 
	 * @return data
	 */
	getDataFromStorage(){
		return JSON.parse(sessionStorage.getItem(this.storageToken));
	}
	/**
	 * Удаляет все данные из sessionStorage , которые относятся к этому классу
	 */
	clearStorage(){
		Object.keys(sessionStorage)
		.filter((key)=>{
			return /^Data__\d+$/.test(key);
		})
		.forEach((key)=>{
			sessionStorage.removeItem(key);
		});
	}
	/**
	 * Генерирует основную структуру таблицы
	 * Таблица (table), заголовок(thead)
	 */
	makeTable(){
		let table	= document.createElement('table'),
			thead	= document.createElement('thead'),
			tr		= document.createElement('tr'),
			header	= this.getDataFromStorage().header;

		for (let item of header){
			let td = document.createElement('td');
			td.innerHTML = item.title;
			tr.appendChild(td);
		}

		thead.appendChild(tr);
		table.appendChild(thead);

		this.table = table;
	}
	/**
	 * Генерирует таблицу (tbody) по странице num
	 * 
	 * @param {Number} num - текущая страница
	 */
	setPage(num = 1){
		num = num < 1 || typeof num !== 'number' ? 1 : num >= this.getDataFromStorage().pages.length ? this.getDataFromStorage().pages.length : num;

		let page 	= this.getDataFromStorage().pages[num - 1],
			tbody 	= document.querySelector(this.config.output.container+' table tbody');
			
		if (!tbody){
			tbody = document.createElement('tbody');
		}
		else {
			tbody.innerHTML = '';
		}
		page.forEach((row)=>{
			let tr = document.createElement('tr');
			row.forEach((cell)=>{
				let td = document.createElement('td');
				td.innerHTML = cell;
				tr.appendChild(td);
			});
			tbody.appendChild(tr);
		});
		this.table.appendChild(tbody);
	}
	/**
	 * Генерирует структуру постраничной навигации
	 */
	makePagination(){
		let numPages = this.getDataFromStorage().pages.length;

		if (numPages <= 1) return;

		let items = document.createElement('ul');

		for (let i = 0; i < numPages; i++){
			let item = document.createElement('li');
			item.innerHTML = i+1;
			items.appendChild(item);
		}

		items.firstChild.classList.add('active');
		this.pagination = items;
	}
	/**
	 * Устанавливает слушателей событий
	 */
	setListeners(){
		if (this.pagination){
			this.pagination.addEventListener('click', (e)=>{
				if (e.target.tagName !== 'LI' || e.target.classList.contains('active')) return false;

				document.querySelector(this.config.output.container+' ul .active').classList.remove('active');
				e.target.classList.add('active');

				this.setPage(+e.target.innerHTML);
			});
		}
	}
	/**
	 *  Последовательно вызывает методоы необходимые для генерации, обработки таблицы и навигации по ней
	 */
	init(){
		this.clearStorage();
		this.getData((data)=>{
			this.splitDataByPages(data);
			this.makeTable();
			this.setPage(1);
			this.makePagination();
			
			let container = document.querySelector(this.config.output.container);
			container.appendChild(this.table);
			if (this.pagination){
				container.appendChild(this.pagination);
			}
			
			this.setListeners();
		});
	}
}


Если я Вас правильно понял и улучшил код, то, если не сложно, подскажите, что еще можно исправить/улучшить?

Последний раз редактировалось Lemme, 23.07.2015 в 18:36.
Ответить с цитированием
  #22 (permalink)  
Старый 23.07.2015, 18:55
Профессор
Отправить личное сообщение для tsigel Посмотреть профиль Найти все сообщения от tsigel
 
Регистрация: 12.12.2012
Сообщений: 1,398

Lemme,
Судя по коду вы не используете ide (по крайней мере при reformatCode не осталось бы выравненных присвоений). Это не плохо но с ide удонее. Мне нравится этот гайд по стилю кода.

Стало лучше. Мне не ясно зачем тут localStorage? потому как если данные тянутся с сервера то их должно быть не много. И они должны тянуться постронично. На сколько я понимаю это просто для себя. Ок.

clearStorage - удалить ключи можно в 1 проход.
getData - зачем колбек если у вас есть промис? Возвращайте промис, красиво же!

Вы много используете красивых итераторов, но по данным бежите обчсным фором. Почему? В коде должно быть единообразие по максимому. Допустимы сильные отличия в пользу производительности там где она нужна.

по возможности действия метода должны нести описательный характер, например в setPage вы проверяете валидность индекса, но намного лучше это вынести в отдельный метод это в 10 раз повысит читабельность метода

Я на практике убедился что много однострочных методов - это хорошо, и условия тоже хорошо бывыносить. Это позволяет не вникать в скобки и прочее, а сразу понять суть проверки по названию метода.
Ответить с цитированием
  #23 (permalink)  
Старый 23.07.2015, 19:02
Аватар для nerv_
junior
Отправить личное сообщение для nerv_ Посмотреть профиль Найти все сообщения от nerv_
 
Регистрация: 29.11.2011
Сообщений: 3,924

Lemme, тебя не смущает, что твоя таблица (Table) работает со страницами?

splitByPages
switchPage
pagination



Это из серии

car.cookBorsch();
rabbit.fly();
window.swim()
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
Ответить с цитированием
  #24 (permalink)  
Старый 23.07.2015, 19:26
Аватар для Lemme
Профессор
Отправить личное сообщение для Lemme Посмотреть профиль Найти все сообщения от Lemme
 
Регистрация: 15.07.2015
Сообщений: 511

Цитата:
Судя по коду вы не используете ide (по крайней мере при reformatCode не осталось бы выравненных присвоений). Это не плохо но с ide удонее. Мне нравится этот гайд по стилю кода.
Нет, ide не использую, использую sublime text. Посмотрел гайд, очень ко многому придется привыкать, но, думаю, постепенно буду соблюдать=)

Цитата:
Стало лучше. Мне не ясно зачем тут localStorage? потому как если данные тянутся с сервера то их должно быть не много. И они должны тянуться постронично. На сколько я понимаю это просто для себя. Ок.
Задумка в том, чтоб получить данные сервера, а ковырять уже на клиенте, localStorage для того, что б дальше работать с данными.

Цитата:
clearStorage - удалить ключи можно в 1 проход.
так?
for (let key in sessionStorage){
	if (/^Data__\d+$/.test(key)){
		sessionStorage.removeItem(key);
	}
}

Цитата:
getData - зачем колбек если у вас есть промис? Возвращайте промис, красиво же!
А вот этого, к сожалению, не понял
Цитата:
Вы много используете красивых итераторов, но по данным бежите обчсным фором. Почему? В коде должно быть единообразие по максимому. Допустимы сильные отличия в пользу производительности там где она нужна.
Потому, что тут циклы работают с цифрами.

по возможности действия метода должны нести описательный характер, например в setPage вы проверяете валидность индекса, но намного лучше это вынести в отдельный метод это в 10 раз повысит читабельность метода

Я на практике убедился что много однострочных методов - это хорошо, и условия тоже хорошо бывыносить. Это позволяет не вникать в скобки и прочее, а сразу понять суть проверки по названию метода.

Возьму на заметку, спасибо.

Последний раз редактировалось Lemme, 23.07.2015 в 19:42.
Ответить с цитированием
  #25 (permalink)  
Старый 23.07.2015, 19:27
Аватар для Lemme
Профессор
Отправить личное сообщение для Lemme Посмотреть профиль Найти все сообщения от Lemme
 
Регистрация: 15.07.2015
Сообщений: 511

Сообщение от nerv_ Посмотреть сообщение
Lemme, тебя не смущает, что твоя таблица (Table) работает со страницами?

splitByPages
switchPage
pagination



Это из серии

car.cookBorsch();
rabbit.fly();
window.swim()
То все мелочи
Ответить с цитированием
  #26 (permalink)  
Старый 23.07.2015, 19:55
Профессор
Отправить личное сообщение для tsigel Посмотреть профиль Найти все сообщения от tsigel
 
Регистрация: 12.12.2012
Сообщений: 1,398

Сообщение от Lemme
Потому, что тут циклы работают с цифрами.
Это отмазка. Вы автор кода и вы создаете формат, можете написать так чтобы не было цифр и были массивы.

Сообщение от Lemme
так?
for (let key in sessionStorage){
    if (/^Data__\d+$/.test(key)){
        sessionStorage.removeItem(key);
    }
}
Например, или так:
var reg = /^Data__\d+$/;
Object.keys(sessionStorage).forEach((key) => {
   if (reg.test(key)) {
      sessionStorage.removeItem(key);
   }
});

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

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

Ну на примере того же setPage (мне нравится typescript пример будет на нем)

public setPage(index:number):void {
   if (this.hasPage(index)) {
      this.changeCurrentPage(index);
      this.render();
   }
}

public render():void {
   this.clear();
   this.createBody();
}

private changeCurrentPage(index:number):void {
   this.currentPage = index;
}


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

Последний раз редактировалось tsigel, 23.07.2015 в 20:26.
Ответить с цитированием
  #27 (permalink)  
Старый 23.07.2015, 19:58
Профессор
Отправить личное сообщение для tsigel Посмотреть профиль Найти все сообщения от tsigel
 
Регистрация: 12.12.2012
Сообщений: 1,398

Lemme,
Оптимизации и красивости кода должны гармонировать, не стоит писать лишний проход по массиву если его можно не писать и код будет красив, но при этом если массив заведомо мал, а метод используется редко и за один проход выглядит не красиво - не надо пытаться свалить все в 1 кучу (ну то есть не надо пытаться отфильтровать и отмапить и отсортировать в 1 проход массив из 5 элементов, профита вы не увидите).
Ответить с цитированием
  #28 (permalink)  
Старый 23.07.2015, 20:15
Аватар для Lemme
Профессор
Отправить личное сообщение для Lemme Посмотреть профиль Найти все сообщения от Lemme
 
Регистрация: 15.07.2015
Сообщений: 511

tsigel, спасибо за помощь=)
Ответить с цитированием
  #29 (permalink)  
Старый 23.07.2015, 20:25
Профессор
Отправить личное сообщение для tsigel Посмотреть профиль Найти все сообщения от tsigel
 
Регистрация: 12.12.2012
Сообщений: 1,398

Lemme,
Перебирая объекты не забывайте про hasOwnProperty
Сообщение от Lemme
А вот этого, к сожалению, не понял
Зачем getData принимает коллбек? пусть возвращает промис!

getData() {
   var promise = fetch(this.config.url);
   promise.catch(...);
   returm promise.then(...);
}

init() {
  this.getData().then((data) => {
    ...
  });
}
Ответить с цитированием
  #30 (permalink)  
Старый 23.07.2015, 20:39
Аватар для Lemme
Профессор
Отправить личное сообщение для Lemme Посмотреть профиль Найти все сообщения от Lemme
 
Регистрация: 15.07.2015
Сообщений: 511

Сообщение от tsigel Посмотреть сообщение
Lemme,
Перебирая объекты не забывайте про hasOwnProperty


Зачем getData принимает коллбек? пусть возвращает промис!

getData() {
   var promise = fetch(this.config.url);
   promise.catch(...);
   returm promise.then(...);
}

init() {
  this.getData().then((data) => {
    ...
  });
}
А вот это красиво =)
Ответить с цитированием
Ответ



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

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


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Преобразование ТАБЛИЦЫ с родителями в json объекты Patr56 Общие вопросы Javascript 5 28.07.2014 12:30
Не могу распарсить JSON. gorenie jQuery 3 29.11.2013 22:26
JSON - отобразить данные таблицы oracle / mssql / mysql ecivgamer Javascript под браузер 3 14.11.2012 18:17
json данные не грузятся в windows XP но грузятся в w7 rustamaha Элементы интерфейса 2 28.11.2011 12:35
JSON или JSONP для запросов на другой сервер? Метод GET, для длинных сообщений? Kotakota jQuery 5 23.08.2011 23:12