Javascript.RU

Оптимальное ООП с Google Closure Compiler

В javascript есть несколько основных стилей объявления объектов и свойств.
Они основаны на разной структуре кода, и поэтому - по-разному сжимаются компилятором.

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

Сжатие будет осуществляться продвинутым способом: --compilation_level ADVANCED_OPTIMIZATIONS.

Мы рассмотрим различные варианты ООП для виджета SayWidget с двумя приватными методами init, setElemById и публичным методом setSayHandler.

Кроме того, для проверки, как работает удаление недостижимого кода, в виджете будет присутствовать неиспользуемый метод unused

Первый стиль ООП основывается на классическом механизме наследования javascript, при котором свойства и методы берутся из прототипа.

function SayWidget(id) {
	this.setElemById(id)
	this.init()
}

SayWidget.prototype = {
	init: function() {
		this.elem.style.display = 'none'
	},
	setElemById: function(id) {
		this.elem = document.getElementById(elem)
	},
	setSayHandler: function() {
		this.elem.onclick = function() { 
			alert('hi')
		}
	},
	unused: function() { alert("unused") }
}

window['SayWidget'] = SayWidget
SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler

Результат сжатия:

function a(b) {
  this.c(b);
  this.b()
}
a.prototype = {b:function() {
  this.a.style.display = "none"
}, c:function() {
  this.a = document.getElementById(elem)
}, d:function() {
  this.a.onclick = function() {
    alert("hi")
  }
}};
window.SayWidget = a;
a.prototype.setSayHandler = a.prototype.d;

Как видно, все свойства. кроме экстернов, были заменены на короткие.
Что очень кстати, был удален неиспользуемый метод unused.

Этот метод, в принципе, аналогичен предыдущему, но методы добавляются в прототип по одному.

function SayWidget(id) {
	this.setElemById(id)
	this.init()
}

SayWidget.prototype.init = function() {
	this.elem.style.display = 'none'
}	
SayWidget.prototype.setElemById = function(id) {
	this.elem = document.getElementById(id)
}
SayWidget.prototype.setSayHandler = function() {
	this.elem.onclick = function() { 
		alert('hi')
	}
}
SayWidget.prototype.unused = function() { alert("unused") }

window['SayWidget'] = SayWidget
SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler

После сжатия:

function a(b) {
  this.a = document.getElementById(b);
  this.a.style.display = "none"
}
a.prototype.b = function() {
  this.a.onclick = function() {
    alert("hi")
  }
};
window.SayWidget = a;
a.prototype.setSayHandler = a.prototype.b;

А здесь - уже интереснее. Благодаря тому, что каждая функция описана отдельно, Google Closure Compiler может построить граф взаимодействий и заинлайнить функции. Что и произошло: в прототипе осталась только одна функция a.prototype.b (бывшая setSayHandler).

В результате размер существенно уменьшился.

Это - концептуально другой подход: методы записываются не в прототип, а в сам объект во время создания. При этом приватные свойства и методы являются локальными переменными функции-конструктора.

В следующем коде находится два неиспользуемых метода unused: один публичный и один - приватный.

function SayWidget(id) {
    var elem
 
    setElemById(id)
    init()
 
    function init() {
        elem.style.display = 'none'
    }    
 
    function setElemById(id) {
        elem = document.getElementById(id)
    }    

    function unused() {
        alert("unused")
    }    
 
    this.setSayHandler = function() {
        elem.onclick = function() { 
            alert('hi')
        }
    }
    this.unused = function() { 
	alert("unused") 
    }

}
window['SayWidget'] = SayWidget

После сжатия:

function b(c) {
  function d() {
    a.style.display = "none"
  }
  function e(f) {
    a = document.getElementById(f)
  }
  var a;
  e(c);
  d();
  this.a = function() {
    a.onclick = function() {
      alert("hi")
    }
  };
  this.b = function() {
    alert("unused")
  }
}
window.SayWidget = b;

Этот стиль ООП обычно сжимается лучше прототипного, т.к. обычный компрессор (или Google Closure Compiler в безопасном режиме) сжимает только локальные переменные.

Но продвинутый режим Google Closure Compiler уравнивает локальные переменные с обычными (кроме экстернов) - он сжимает и то и другое.

Поэтому никакого преимущества этот стиль ООП не показал. Более того, в данном компилятору не удалось ни заинлайнить вызовы ни удалить неиспользуемый публичный метод.

Последний из рассматриваемых стилей работает без вызова оператора new. Он просто возвращает объект с нужными методами.

// object = sayWidget(id)
function sayWidget(id) {
	var elem
	
	setElemById(id)
	init()
	
	function init() {
		elem.style.display = 'none'
	}

	function setElemById(id) {
		elem = document.getElementById(id)
	}


	function unused() { 
		alert("unused") 
	}

	var me = {  // новый объект
		setSayHandler: function() {
			elem.onclick = function() { 
				alert('hi')
			}
		},
		unused: function() { 
			alert("unused") 
		}
	}
	me['setSayHandler'] = me.setSayHandler

	return me
}
window['sayWidget'] = sayWidget

После сжатия:

function c(a) {
  function d() {
    b.style.display = "none"
  }
  function e(f) {
    b = document.getElementById(f)
  }
  var b;
  e(a);
  d();
  a = {a:function() {
    b.onclick = function() {
      alert("hi")
    }
  }, b:function() {
    alert("unused")
  }};
  a.setSayHandler = a.a;
  return a
}
window.sayWidget = c;

Результат аналогичен предыдущему.

Победил в итоге, вот сюрприз, самый длинный способ - добавление каждого свойства через прототип кодом вида: SayWidget.prototype.methodXXX = ....

Более того, эта победа не случайна. Такой способ позволяет компилятору построить самый полный граф взаимодействий и произвести инлайны.
А определение функций в прототипе вместо замыкания - дает возможность успешно вырезать неиспользуемые символы. В результате - уменьшение размера кода.

В библиотеке Google Closure Library, под которую заточен Closure Compiler, используется именно такой стиль объявления свойств.


Автор: Alex S (не зарегистрирован), дата: 23 апреля, 2010 - 15:28
#permalink

На самом деле можно еще описать класс в таком стиле:

var oop = {};

(function (ns){

function KeyType() {}

/**
* @constructor
*/
function TestObject() {
this._markedObj = new KeyType()
}

TestObject.prototype = {
_markedObj : null,

doIt: function() {
opns.addEvent("keydown", function(obj) {
return obj instanceof KeyType
})
},

getMarked: function() {
return this._markedObj
},

dummy: function(event) {
opns.isEvent(event)
}
}

/* export TestObject */
ns.TestObject = TestObject
})(oop)

В данной записи пространство имен oop будет содержать "публичный" класс TestObject, который в свою очередь использует "приватный" класс KeyType. В данном случае closure сможет убрать, к примеру, метод dummy, если он не используется. И вообще, похоже, closure сможет выполнить все оптимизации за исключением одной - вызов функции вводящей определение TestObject не будет заинлайнен.

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


Автор: Зарегистрирован (не зарегистрирован), дата: 16 ноября, 2011 - 15:57
#permalink

К слову

a.prototype.b = ...;
a.prototype.setSayHandler = a.prototype.b;

- не полный аналог

a.prototype.setSayHandler = ...;

Полный аналог выглядел бы так:

a.prototype.b = ...;
a.prototype.setSayHandler = a.prototype.b;
delete a.prototype.b; // <<<<<

Короче, GCC не просто переименовывает свойства, а дублирует их, что теоретически может выйти боком, когда свойства по ходу дела меняются, или когда делается перебор свойств (например, для сериализации).


Автор: tyrus.mlearner (не зарегистрирован), дата: 2 февраля, 2012 - 13:21
#permalink

А что же делать, если unused - мое API в конструкторе для объекта, и самим объектом не используется, но используется внешним (либо другим js-кодом, либо даже flash'ом)? Получается он его похерит Sad


Автор: picos school (не зарегистрирован), дата: 9 июля, 2021 - 06:30
#permalink

окончательная декомпрессия этой кодовой последовательности с количеством циклов достаточна только для одного файла, если файлов больше, это будет невозможно, поэтому выберите более широкое поле и добавьте код, который автоматически дублирует количество циклов.
picos school


Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 01:23
#permalink

Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 02:08
#permalink

Автор: Гость (не зарегистрирован), дата: 16 апреля, 2022 - 12:49
#permalink

Автор: ichylu (не зарегистрирован), дата: 5 октября, 2022 - 12:28
#permalink

Because all games in free games unblocked are currently unblocked, you might even utilize a smart device like a smartphone, iPad, or PC to play them at work or school.


Автор: allanpetter (не зарегистрирован), дата: 2 ноября, 2022 - 17:26
#permalink

This is a very great post and the way you express all your post details is too good. Thanks for sharing with us this useful post interior painting near me Raleigh NC


Автор: JellyMin (не зарегистрирован), дата: 10 мая, 2023 - 18:46
#permalink

In addition, to test how removing unreachable code works, the widget will have an unused methodunused drywall contractors dallas tx


Автор: kisytd (не зарегистрирован), дата: 15 мая, 2023 - 13:03
#permalink

what are you waiting for snake games? You should click and challenge any players in the world.


Автор: Peter Barnes (не зарегистрирован), дата: 14 июня, 2023 - 06:56
#permalink

There is nothing better than finding yourself a good game and playing at home on hot summer days. I recommend duck life to you.


Автор: oscardooley (не зарегистрирован), дата: 14 июня, 2023 - 07:31
#permalink

I appreciate you sharing the facts and advice, and I will take them into consideration. The game traffic jam 3d is fun which you can try wherever you want.


Автор: Mnlsoa (не зарегистрирован), дата: 14 июня, 2023 - 10:16
#permalink

A nagging sensation in the back of their heads compels them to come to a halt, but Riley is obligated to continue watching the tapes in amanda the adventurer


Автор: takehub (не зарегистрирован), дата: 30 июня, 2023 - 04:39
#permalink

Articles with very interesting topics. 8 ball pool


Автор: Гость (не зарегистрирован), дата: 20 июля, 2023 - 13:36
#permalink

All of the emoji characters are now accessible for you to copy and paste with ease (just copy them and then paste them into the editor of your choice).


Автор: leorasy (не зарегистрирован), дата: 1 августа, 2023 - 04:32
#permalink

Google Closure Compiler works well with modern stumble guys syntax, including classes. Using classes helps organize your code in a more structured and OOP-oriented manner.


Автор: Гость (не зарегистрирован), дата: 9 августа, 2023 - 06:55
#permalink

Excellent piece! This is a fantastic site that I plan on revisiting numerous times throughout the year. I appreciate your informative blog. mini crossword


Автор: JellyMin (не зарегистрирован), дата: 21 августа, 2023 - 17:46
#permalink

Кроме того, для проверки, как работает удаление недостижимого кода, в виджете будет присутствовать неиспользуемый метод unused sacramento ca drywall repair


Автор: Гость (не зарегистрирован), дата: 5 сентября, 2023 - 12:16
#permalink

This is a fantastic site that I plan on revisiting numerous slope


Автор: Binladen (не зарегистрирован), дата: 5 октября, 2023 - 10:48
#permalink

You have created a work that is very enjoyable to read, bringing enlightenment to every topic for us to acquire knowledge happy wheels. Thank you for sharing such information for us to read...


Автор: liam (не зарегистрирован), дата: 4 ноября, 2023 - 10:31
#permalink

I thoroughly enjoyed your article play wordle; it was captivating and made my morning coffee even more delightful. Thank you for sharing such a high-quality piece.


Автор: 먹튀신고 (не зарегистрирован), дата: 14 ноября, 2023 - 07:50
#permalink

Be able to create comparative themes with pleasure! Welcome here and you will discover what it should look like.먹튀신고


Автор: taniyuki (не зарегистрирован), дата: 27 февраля, 2024 - 08:33
#permalink

tiny fishing - Simple, pleasant and so good


Отправить комментарий

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
4 + 9 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние комментарии
Последние темы на форуме
Forum