minor renovations, beautify round 2 (final)
This commit is contained in:
parent
fad6615c42
commit
8410ce6421
212 changed files with 1981 additions and 1717 deletions
|
@ -104,16 +104,16 @@ elem.menu = menu; // такая привязка или что-то подобн
|
|||
var elem = document.createElement('div'); // любой элемент
|
||||
|
||||
function leak() {
|
||||
|
||||
elem.innerHTML = '<table><tr><td>1</td></tr></table>';
|
||||
|
||||
elem.innerHTML = '<table><tr><td>1</td></tr></table>';
|
||||
|
||||
*!*
|
||||
elem.firstChild.rows[0]; // просто доступ через rows[] приводит к утечке
|
||||
// при том, что мы даже не сохраняем значение в переменную
|
||||
elem.firstChild.rows[0]; // просто доступ через rows[] приводит к утечке
|
||||
// при том, что мы даже не сохраняем значение в переменную
|
||||
*/!*
|
||||
|
||||
elem.removeChild(elem.firstChild); // удалить таблицу (*)
|
||||
// alert(elem.childNodes.length) // выдал бы 0, elem очищен, всё честно
|
||||
elem.removeChild(elem.firstChild); // удалить таблицу (*)
|
||||
// alert(elem.childNodes.length) // выдал бы 0, elem очищен, всё честно
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -132,7 +132,7 @@ function leak() {
|
|||
|
||||
```js
|
||||
function empty(elem) {
|
||||
while(elem.firstChild) elem.removeChild(elem.firstChild);
|
||||
while (elem.firstChild) elem.removeChild(elem.firstChild);
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -146,12 +146,12 @@ function empty(elem) {
|
|||
|
||||
```js
|
||||
function leak() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.open('GET', '/server.do', true);
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if(xhr.readyState == 4 && xhr.status == 200) {
|
||||
if (xhr.readyState == 4 && xhr.status == 200) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
@ -181,12 +181,12 @@ function leak() {
|
|||
function leak() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.open('GET', 'something.js?'+Math.random(), true);
|
||||
xhr.open('GET', 'something.js?' + Math.random(), true);
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState != 4) return;
|
||||
|
||||
if(xhr.status == 200) {
|
||||
if (xhr.status == 200) {
|
||||
document.getElementById('test').innerHTML++;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
Например:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
// присвоить
|
||||
$(document).data('prop', { anything: "любой объект" })
|
||||
|
||||
|
@ -27,13 +28,14 @@ jQuery-вызов `elem.data(prop, val)` делает следующее:
|
|||
<li>Элемент получает уникальный идентификатор, если у него такого еще нет:
|
||||
|
||||
```js
|
||||
elem[ jQuery.expando ] = id = ++jQuery.uuid; // средствами jQuery
|
||||
elem[jQuery.expando] = id = ++jQuery.uuid; // средствами jQuery
|
||||
```
|
||||
|
||||
`jQuery.expando` -- это случайная строка, сгенерированная jQuery один раз при входе на страницу. Уникальное свойство, чтобы ничего важного не перезаписать.</li>
|
||||
<li>...А сами данные сохраняются в специальном объекте `jQuery.cache`:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
jQuery.cache[id]['prop'] = { anything: "любой объект" };
|
||||
```
|
||||
|
||||
|
@ -55,20 +57,37 @@ jQuery.cache[id]['prop'] = { anything: "любой объект" };
|
|||
|
||||
## Примеры утечек в jQuery
|
||||
|
||||
Следующий код создает jQuery-утечку во всех браузерах:
|
||||
Следующая функция `leak` создает jQuery-утечку во всех браузерах:
|
||||
|
||||
```js
|
||||
$('<div/>')
|
||||
.html(new Array(1000).join('text')) // div с текстом, возможна AJAX-загрузка
|
||||
.click(function() { })
|
||||
.appendTo('#data')
|
||||
|
||||
document.getElementById('data').innerHTML = ''; // (*)
|
||||
```html
|
||||
<!--+ run -->
|
||||
<script src="http://code.jquery.com/jquery.min.js"></script>
|
||||
|
||||
<div id="data"></div>
|
||||
|
||||
<script>
|
||||
function leak() {
|
||||
|
||||
*!*
|
||||
$('<div/>')
|
||||
.html(new Array(1000).join('text'))
|
||||
.click(function() {})
|
||||
.appendTo('#data');
|
||||
|
||||
document.getElementById('data').innerHTML = '';
|
||||
*/!*
|
||||
|
||||
}
|
||||
|
||||
var interval = setInterval(leak, 10)
|
||||
</script>
|
||||
|
||||
Утечка идёт...
|
||||
|
||||
<input type="button" onclick="clearInterval(interval)" value="stop" />
|
||||
```
|
||||
|
||||
Полный пример:
|
||||
|
||||
[codetabs src="jquery-leak"]
|
||||
|
||||
Утечка происходит потому, что обработчик события в jQuery хранится в данных элемента. В строке `(*)` элемент удален очисткой родительского `innerHTML`, но в `jQuery.cache` данные остались.
|
||||
|
||||
|
@ -79,9 +98,9 @@ document.getElementById('data').innerHTML = ''; // (*)
|
|||
Этот код также создает утечку:
|
||||
|
||||
```js
|
||||
function go() {
|
||||
function leak() {
|
||||
$('<div/>')
|
||||
.click(function() { })
|
||||
.click(function() {})
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="http://code.jquery.com/jquery.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div id="data"></div>
|
||||
|
||||
<script>
|
||||
function go() {
|
||||
|
||||
$('<div/>')
|
||||
.html(new Array(1000).join('text'))
|
||||
.click(function() {})
|
||||
.appendTo('#data');
|
||||
|
||||
document.getElementById('data').innerHTML = '';
|
||||
|
||||
}
|
||||
|
||||
var interval = setInterval(go, 10)
|
||||
</script>
|
||||
|
||||
Утечка идёт...
|
||||
|
||||
<input type="button" onclick="clearInterval(interval)" value="stop" />
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -89,7 +89,7 @@ dot -Tsvg my.dot -o my.svg
|
|||
function User(name) {
|
||||
|
||||
this.sayHi = function() {
|
||||
alert(name);
|
||||
alert( name );
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -139,13 +139,14 @@ var minIEVersion = 8;
|
|||
|
||||
```js
|
||||
function test(a, b) {
|
||||
run(a, 'my'+'string', 600*600*5, 1 && 0, b && 0)
|
||||
run(a, 'my' + 'string', 600 * 600 * 5, 1 && 0, b && 0)
|
||||
}
|
||||
```
|
||||
|
||||
После:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function test(a,b){run(a,"mystring",18E5,0,b&&0)};
|
||||
```
|
||||
|
||||
|
@ -169,6 +170,7 @@ function sayHi(*!*name*/!*, *!*message*/!*) {
|
|||
После оптимизации:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function sayHi(a,b){alert(a+" сказал: "+b)};
|
||||
```
|
||||
|
||||
|
@ -186,13 +188,14 @@ function sayHi(a,b){alert(a+" сказал: "+b)};
|
|||
function test(nodeId) {
|
||||
var elem = document.getElementsById(nodeId);
|
||||
var parent = elem.parentNode;
|
||||
alert(parent);
|
||||
alert( parent );
|
||||
}
|
||||
```
|
||||
|
||||
После оптимизации GCC:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function test(a){a=document.getElementsById(a).parentNode;alert(a)};
|
||||
```
|
||||
|
||||
|
@ -210,22 +213,23 @@ function test(a){a=document.getElementsById(a).parentNode;alert(a)};
|
|||
```js
|
||||
function test(node) {
|
||||
var parent = node.parentNode;
|
||||
|
||||
|
||||
if (0) {
|
||||
alert("Привет с параллельной планеты");
|
||||
alert( "Привет с параллельной планеты" );
|
||||
} else {
|
||||
alert("Останется только один");
|
||||
alert( "Останется только один" );
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
alert(1);
|
||||
alert( 1 );
|
||||
}
|
||||
```
|
||||
|
||||
После оптимизации:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function test(){alert("Останется только один")}
|
||||
```
|
||||
|
||||
|
@ -244,25 +248,26 @@ function test(){alert("Останется только один")}
|
|||
```js
|
||||
var i = 0;
|
||||
while (i++ < 10) {
|
||||
alert(i);
|
||||
alert( i );
|
||||
}
|
||||
|
||||
if (i) {
|
||||
alert(i);
|
||||
alert( i );
|
||||
}
|
||||
|
||||
if (i=='1') {
|
||||
alert(1);
|
||||
} else if(i == '2') {
|
||||
alert(2);
|
||||
if (i == '1') {
|
||||
alert( 1 );
|
||||
} else if (i == '2') {
|
||||
alert( 2 );
|
||||
} else {
|
||||
alert(i);
|
||||
alert( i );
|
||||
}
|
||||
```
|
||||
|
||||
После оптимизации:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
for(var i=0;10>i++;)alert(i);i&&alert(i);"1"==i?alert(1):"2"==i?alert(2):alert(i);
|
||||
```
|
||||
|
||||
|
@ -299,9 +304,9 @@ function sayHi(message) {
|
|||
После оптимизации (переводы строк также будут убраны):
|
||||
|
||||
```js
|
||||
function sayHi(b){
|
||||
var a=document.createElement("div");
|
||||
a.innerHTML=b;
|
||||
function sayHi(b) {
|
||||
var a = document.createElement("div");
|
||||
a.innerHTML = b;
|
||||
document.body.appendChild(a)
|
||||
};
|
||||
```
|
||||
|
@ -323,43 +328,44 @@ function sayHi(b){
|
|||
|
||||
window.sayHi = function() {
|
||||
if (isVisible) {
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
alert(hi);
|
||||
}
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
alert( hi );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})();
|
||||
```
|
||||
|
||||
После оптимизации:
|
||||
|
||||
```js
|
||||
(function(){
|
||||
window.sayHi=function(){
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
alert("Привет вам из JavaScript");
|
||||
};
|
||||
}})();
|
||||
(function() {
|
||||
window.sayHi = function() {
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
alert( "Привет вам из JavaScript" );
|
||||
};
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
<ul>
|
||||
|
@ -385,6 +391,7 @@ function sayHi(b){
|
|||
<li>Убираются лишние кавычки у ключей
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
{"prop" : "val" } => {prop:"val"}
|
||||
```
|
||||
|
||||
|
@ -392,6 +399,7 @@ function sayHi(b){
|
|||
<li>Упрощаются простые вызовы `Array/Object`
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
a = new Array() => a = []
|
||||
o = new Object() => o = {}
|
||||
```
|
||||
|
@ -414,6 +422,7 @@ o = new Object() => o = {}
|
|||
Рассмотрим код:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function changePosition(style) {
|
||||
var position, test;
|
||||
|
||||
|
@ -432,6 +441,7 @@ function changePosition(style) {
|
|||
Можно ли в такой ситуации заменить локальную переменную на более короткую? Очевидно, нет:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function changePosition(style) {
|
||||
var a, b;
|
||||
|
||||
|
@ -446,6 +456,7 @@ function changePosition(style) {
|
|||
Такая же опасность для сжатия кроется в использованном `eval`. Ведь `eval` может обращаться к локальным переменным:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function f(code) {
|
||||
var myVar;
|
||||
|
||||
|
@ -481,32 +492,22 @@ function f(code) {
|
|||
|
||||
```js
|
||||
//+ run
|
||||
var isIE /*@cc_on =true@*/;
|
||||
var isIE /*@cc_on =true@*/ ;
|
||||
|
||||
alert(isIE); // true в IE.
|
||||
alert( isIE ); // true в IE10-
|
||||
```
|
||||
|
||||
Там же доступны и дополнительные директивы: `@_jscript_version`, `@if` и т.п., но речь здесь не о том.
|
||||
|
||||
Для минификаторов этот "условный" комментарий -- всего лишь обычный комментарий. Они его удалят. Получится, что код не поймёт, где же IE.
|
||||
|
||||
Что делать?
|
||||
|
||||
<ol>
|
||||
<li>Первое и наиболее корректное решение -- не использовать условную компиляцию.</li>
|
||||
<li>Второе, если уж очень надо -- применить хак, завернуть его в `eval` или `new Function` (чтобы сжиматель не ругался):
|
||||
Можно хитро сделать, чтобы комментарий остался, например так:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var isIE = new Function('', '/*@cc_on return true@*/')();
|
||||
|
||||
alert(isIE); // true в IE.
|
||||
alert( isIE ); // true в IE.
|
||||
```
|
||||
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
Ещё раз заметим, что в современных IE11+ эта компиляция не работает в любом случае.
|
||||
...Однако, с учётом того, что в современных IE11+ эта компиляция не работает в любом случае, лучше избавиться от неё вообще.
|
||||
|
||||
В следующих главах мы посмотрим, какие продвинутые возможности есть в минификаторах, как сделать сжатие более эффективным.
|
||||
|
||||
|
|
|
@ -28,12 +28,12 @@
|
|||
function User(firstName, lastName) {
|
||||
var fullName = firstName + ' ' + lastName;
|
||||
|
||||
this.sayHi = function() {
|
||||
this.sayHi = function() {
|
||||
showMessage(fullName);
|
||||
}
|
||||
|
||||
function showMessage(msg) {
|
||||
alert('**' + msg + '**');
|
||||
alert( '**' + msg + '**' );
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -46,13 +46,13 @@ function User(firstName, lastName) {
|
|||
this._lastName = lastName;
|
||||
}
|
||||
|
||||
User.prototype.sayHi = function() {
|
||||
User.prototype.sayHi = function() {
|
||||
this._showMessage(this._fullName);
|
||||
}
|
||||
|
||||
|
||||
User.prototype._showMessage = function(msg) {
|
||||
alert('**' + msg + '**');
|
||||
User.prototype._showMessage = function(msg) {
|
||||
alert( '**' + msg + '**' );
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -71,21 +71,21 @@ User.prototype._showMessage = function(msg) {
|
|||
Проще всего это сделать локальной переменной в модуле:
|
||||
|
||||
```js
|
||||
(function($) {
|
||||
(function($) {
|
||||
|
||||
*!*
|
||||
/** @const */
|
||||
var platform = 'IE';
|
||||
/** @const */
|
||||
var platform = 'IE';
|
||||
*/!*
|
||||
|
||||
// .....
|
||||
|
||||
if (platform == 'IE') {
|
||||
alert('IE');
|
||||
} else {
|
||||
alert('NON-IE');
|
||||
}
|
||||
|
||||
// .....
|
||||
|
||||
if (platform == 'IE') {
|
||||
alert( 'IE' );
|
||||
} else {
|
||||
alert( 'NON-IE' );
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
```
|
||||
|
||||
|
@ -108,16 +108,16 @@ UglifyJS и GCC позволяют задать значение глобаль
|
|||
```js
|
||||
// my.js
|
||||
if (isIE) {
|
||||
alert("Привет от IE");
|
||||
} else {
|
||||
alert("Не IE :)");
|
||||
alert( "Привет от IE" );
|
||||
} else {
|
||||
alert( "Не IE :)" );
|
||||
}
|
||||
```
|
||||
|
||||
Сжатие вызовом `uglifyjs -d isIE my.js` даст:
|
||||
|
||||
```js
|
||||
alert("Привет от IE");
|
||||
alert( "Привет от IE" );
|
||||
```
|
||||
|
||||
..Ну а чтобы код работал в обычном окружении, нужно определить в нём значение переменной по умолчанию. Это обычно делается в каком-то другом файле (на весь проект), так как если объявить `var isIE` в этом, то флаг `-d isIE` не сработает.
|
||||
|
@ -147,24 +147,24 @@ var uglify = require('uglify-js');
|
|||
var pro = uglify.uglify;
|
||||
|
||||
function ast_squeeze_console(ast) {
|
||||
var w = pro.ast_walker(),
|
||||
walk = w.walk,
|
||||
scope;
|
||||
return w.with_walkers({
|
||||
"stat": function(stmt) {
|
||||
if(stmt[0] === "call" && stmt[1][0] == "dot" && stmt[1][1] instanceof Array && stmt[1][1][0] == 'name' && stmt[1][1][1] == "log") {
|
||||
return ["block"];
|
||||
}
|
||||
return ["stat", walk(stmt)];
|
||||
},
|
||||
"call": function(expr, args) {
|
||||
if(expr[0] == "dot" && expr[1] instanceof Array && expr[1][0] == 'name' && expr[1][1] == "console") {
|
||||
return ["atom", "0"];
|
||||
}
|
||||
}
|
||||
}, function() {
|
||||
return walk(ast);
|
||||
});
|
||||
var w = pro.ast_walker(),
|
||||
walk = w.walk,
|
||||
scope;
|
||||
return w.with_walkers({
|
||||
"stat": function(stmt) {
|
||||
if (stmt[0] === "call" && stmt[1][0] == "dot" && stmt[1][1] instanceof Array && stmt[1][1][0] == 'name' && stmt[1][1][1] == "log") {
|
||||
return ["block"];
|
||||
}
|
||||
return ["stat", walk(stmt)];
|
||||
},
|
||||
"call": function(expr, args) {
|
||||
if (expr[0] == "dot" && expr[1] instanceof Array && expr[1][0] == 'name' && expr[1][1] == "console") {
|
||||
return ["atom", "0"];
|
||||
}
|
||||
}
|
||||
}, function() {
|
||||
return walk(ast);
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ java -jar compiler.jar --compilation_level ADVANCED_OPTIMIZATIONS --js my.js
|
|||
|
||||
```js
|
||||
function test(n) {
|
||||
alert("this is my test number " + n);
|
||||
alert( "this is my test number " + n );
|
||||
}
|
||||
test(1);
|
||||
test(2);
|
||||
|
@ -121,13 +121,17 @@ first:2 --module second:1:first
|
|||
Например:
|
||||
|
||||
```js
|
||||
document.onkeyup = function(event) { alert(event.type) }
|
||||
document.onkeyup = function(event) {
|
||||
alert(event.type)
|
||||
}
|
||||
```
|
||||
|
||||
После продвинутого сжатия:
|
||||
|
||||
```js
|
||||
document.onkeyup = function(a) { alert(a.type) }
|
||||
document.onkeyup = function(a) {
|
||||
alert(a.type)
|
||||
}
|
||||
```
|
||||
|
||||
Как видите, переименованной оказалась только переменная `event`. Такое переименование заведомо безопасно, т.к. `event` -- локальная переменная.
|
||||
|
@ -135,13 +139,17 @@ document.onkeyup = function(a) { alert(a.type) }
|
|||
Почему компилятор не тронул остального? Попробуем другой вариант:
|
||||
|
||||
```js
|
||||
document.blabla = function(event) { alert(event.megaProperty) }
|
||||
document.blabla = function(event) {
|
||||
alert(event.megaProperty)
|
||||
}
|
||||
```
|
||||
|
||||
После компиляции:
|
||||
|
||||
```js
|
||||
document.a = function(a) { alert(a.b) }
|
||||
document.a = function(a) {
|
||||
alert(a.b)
|
||||
}
|
||||
```
|
||||
|
||||
Теперь компилятор переименовал и <code>blabla</code> и <code>megaProperty</code>.
|
||||
|
@ -175,9 +183,9 @@ window.a = function(a) {
|
|||
|
||||
```js
|
||||
window['User'] = function(name, type, age) {
|
||||
this.name = name
|
||||
this.type = type
|
||||
this.age = age
|
||||
this.name = name
|
||||
this.type = type
|
||||
this.age = age
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -253,9 +261,9 @@ SayWidget.prototype = {
|
|||
init: function() {
|
||||
this.elem.style.display = 'none'
|
||||
},
|
||||
|
||||
|
||||
setSayHandler: function() {
|
||||
this.elem.onclick = function() {
|
||||
this.elem.onclick = function() {
|
||||
alert("hi")
|
||||
};
|
||||
}
|
||||
|
@ -268,6 +276,7 @@ SayWidget.prototype['setSayHandler'] = SayWidget.prototype.setSayHandler;
|
|||
После сжатия:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function a(b) {
|
||||
this.a = b;
|
||||
this.b()
|
||||
|
@ -428,6 +437,7 @@ MyFramework.publicOne();
|
|||
Результат компиляции в обычном режиме:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
// java -jar compiler.jar --js myframework.js --formatting PRETTY_PRINT
|
||||
(function(a) {
|
||||
a = a.MyFramework = {};
|
||||
|
|
|
@ -51,7 +51,7 @@ function f1(id) {
|
|||
}
|
||||
|
||||
/** @param {string} id */
|
||||
function f2(id) { }
|
||||
function f2(id) {}
|
||||
```
|
||||
|
||||
Такой вызов приведёт к предупреждению со стороны минификатора:
|
||||
|
@ -122,13 +122,13 @@ required: (Node|null)
|
|||
/** @param {!Node} node */
|
||||
*/!*
|
||||
function removeNode(node) {
|
||||
node.parentNode.removeChild(node)
|
||||
node.parentNode.removeChild(node)
|
||||
}
|
||||
```
|
||||
|
||||
Восклицательный знак означает, что параметр обязатален.
|
||||
|
||||
Найти описания встроенных типов и объектов javascript вы можете в файле экстернов: <code>externs.zip</code> находится в корне архива <code>compiler.jar</code>, или в соответствующей директории SVN: <a href="http://closure-compiler.googlecode.com/svn/trunk/externs/">http://closure-compiler.googlecode.com/svn/trunk/externs/</a>.
|
||||
Найти описания встроенных типов и объектов javascript вы можете в файле экстернов: <code>externs.zip</code> находится в корне архива <code>compiler.jar</code>.
|
||||
|
||||
## Интеграция с проверками типов из Google Closure Library
|
||||
|
||||
|
@ -138,7 +138,9 @@ Google Closure Compiler знает о них и понимает, что вну
|
|||
|
||||
```js
|
||||
var goog = {
|
||||
isFunction: function(f) { return typeof f == 'function' }
|
||||
isFunction: function(f) {
|
||||
return typeof f == 'function'
|
||||
}
|
||||
}
|
||||
|
||||
if (goog.isFunction(func)) {
|
||||
|
@ -168,7 +170,7 @@ required: (Object|null|undefined)
|
|||
|
||||
Также можно указывать количество и тип параметров функции, ключевого слова <code>this</code>, объявлять классы, приватные методы и интерфейсы.
|
||||
|
||||
Проверка типов javascript, предоставляемая Google Closure Compiler - пожалуй, самая продвинутая из существующих на сегодняшний день.
|
||||
Проверка типов javascript, предоставляемая Google Closure Compiler -- пожалуй, самая продвинутая из существующих на сегодняшний день.
|
||||
|
||||
C ней аннотации, документирующие типы и параметры, становятся не просто украшением, а реальным средством проверки, уменьшающим количество ошибок на production.
|
||||
|
||||
|
|
|
@ -36,9 +36,9 @@ var COMPILED = false;
|
|||
|
||||
```js
|
||||
goog.require = function(rule) {
|
||||
// ...
|
||||
// ...
|
||||
if (!COMPILED) {
|
||||
// основное тело функции
|
||||
// основное тело функции
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -49,14 +49,14 @@ goog.require = function(rule) {
|
|||
/** @define {boolean} */
|
||||
var COMPILED = false
|
||||
|
||||
Framework = { }
|
||||
Framework = {}
|
||||
|
||||
Framework.sayCompiled = function() {
|
||||
if (!COMPILED) {
|
||||
alert("Not compressed")
|
||||
} else {
|
||||
alert("Compressed")
|
||||
}
|
||||
if (!COMPILED) {
|
||||
alert("Not compressed")
|
||||
} else {
|
||||
alert("Compressed")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -65,7 +65,7 @@ Framework.sayCompiled = function() {
|
|||
```js
|
||||
Framework = {};
|
||||
Framework.sayCompiled = Framework.a = function() {
|
||||
alert("Compressed");
|
||||
alert( "Compressed" );
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -102,13 +102,12 @@ Google Closure Library умеет преобразовывать классы CS
|
|||
Например, следующая функция задает такой список.
|
||||
|
||||
```js
|
||||
|
||||
goog.setCssNameMapping({
|
||||
goog.setCssNameMapping({
|
||||
"goog-menu": "a",
|
||||
"goog-menu-disabled": "a-b",
|
||||
"CSS_LOGO": "b",
|
||||
"hidden": "c"
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Тогда следующий вызов преобразуется в "a a-b":
|
||||
|
@ -151,9 +150,8 @@ Google Closure Compiler производит соответствующие пр
|
|||
|
||||
```js
|
||||
/** @export */
|
||||
function Widget() {
|
||||
}
|
||||
/** @export */
|
||||
function Widget() {}
|
||||
/** @export */
|
||||
Widget.prototype.hide = function() {
|
||||
this.elem.style.display = 'none'
|
||||
}
|
||||
|
@ -162,8 +160,7 @@ Widget.prototype.hide = function() {
|
|||
После компиляции в продвинутом режиме:
|
||||
|
||||
```js
|
||||
function a() {
|
||||
}
|
||||
function a() {}
|
||||
goog.d("Widget", a);
|
||||
a.prototype.a = function() {
|
||||
this.b.style.display = "none"
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
```html
|
||||
<html>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<ul>
|
||||
|
@ -17,6 +18,7 @@
|
|||
Сосед
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
|
@ -75,9 +77,9 @@ document.body.innerHTML = "";
|
|||
var list = document.getElementsByTagName('ul')[0];
|
||||
document.body.innerHTML = ''; // удалили DIV
|
||||
|
||||
alert(list.parentNode); // цела ли ссылка UL -> DIV ?
|
||||
alert(list.nextSibling); // живы ли соседи UL ?
|
||||
alert(list.children.length); // живы ли потомки UL ?
|
||||
alert( list.parentNode ); // цела ли ссылка UL -> DIV ?
|
||||
alert( list.nextSibling ); // живы ли соседи UL ?
|
||||
alert( list.children.length ); // живы ли потомки UL ?
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue