renovations
This commit is contained in:
parent
e706693c7e
commit
24171550ae
23 changed files with 196 additions and 76 deletions
|
@ -11,21 +11,19 @@ true + false = 1
|
||||||
"4" - 2
= 2
|
"4" - 2
= 2
|
||||||
"4px" - 2
= NaN
|
"4px" - 2
= NaN
|
||||||
7 / 0
= Infinity
|
7 / 0
= Infinity
|
||||||
parseInt("09")
= "0" или "9" // (3)
|
|
||||||
" -9\n" + 5 = " -9\n5"
|
" -9\n" + 5 = " -9\n5"
|
||||||
" -9\n" - 5 = -14
|
" -9\n" - 5 = -14
|
||||||
5 && 2
= 2
|
5 && 2
= 2
|
||||||
2 && 5
= 5
|
2 && 5
= 5
|
||||||
5 || 0
= 5
|
5 || 0
= 5
|
||||||
0 || 5 = 5
|
0 || 5 = 5
|
||||||
null + 1 = 1 // (4)
|
null + 1 = 1 // (3)
|
||||||
undefined + 1 = NaN // (5)
|
undefined + 1 = NaN // (4)
|
||||||
```
|
```
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>Оператор `"+"` в данном случае прибавляет `1` как строку, и затем `0`.</li>
|
<li>Оператор `"+"` в данном случае прибавляет `1` как строку, и затем `0`.</li>
|
||||||
<li>Оператор `"-"` работает только с числами, так что он сразу приводит `""` к `0`.</li>
|
<li>Оператор `"-"` работает только с числами, так что он сразу приводит `""` к `0`.</li>
|
||||||
<li>В некоторых браузерах `parseInt` без второго аргумента интерпретирует `09` как восьмиричное число.</li>
|
|
||||||
<li>`null` при численном преобразовании становится `0`</li>
|
<li>`null` при численном преобразовании становится `0`</li>
|
||||||
<li>`undefined` при численном преобразовании становится `NaN`</li>
|
<li>`undefined` при численном преобразовании становится `NaN`</li>
|
||||||
</ol>
|
</ol>
|
|
@ -15,7 +15,6 @@ true + false
|
||||||
"4" - 2
|
"4" - 2
|
||||||
"4px" - 2
|
"4px" - 2
|
||||||
7 / 0
|
7 / 0
|
||||||
parseInt("09")
|
|
||||||
" -9\n" + 5
|
" -9\n" + 5
|
||||||
" -9\n" - 5
|
" -9\n" - 5
|
||||||
5 && 2
|
5 && 2
|
||||||
|
|
|
@ -17,3 +17,12 @@ function getSecondsToday() {
|
||||||
alert( getSecondsToday() );
|
alert( getSecondsToday() );
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Альтернативное решение -- получить часы/минуты/секунды и преобразовать их все в секунды:
|
||||||
|
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
function getSecondsToday(){
|
||||||
|
var d = new Date();
|
||||||
|
return d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds();
|
||||||
|
};
|
||||||
|
```
|
|
@ -14,4 +14,3 @@ function getSecondsToTomorrow() {
|
||||||
return Math.round(diff / 1000); // перевести в секунды
|
return Math.round(diff / 1000); // перевести в секунды
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,7 @@ function work() {
|
||||||
```html
|
```html
|
||||||
<!--+ run -->
|
<!--+ run -->
|
||||||
<p>Подключим библиотеку</p>
|
<p>Подключим библиотеку</p>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
|
|
||||||
<p>Функция <code>_.defaults()</code> добавляет отсутствующие свойства.</p>
|
<p>Функция <code>_.defaults()</code> добавляет отсутствующие свойства.</p>
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -30,4 +30,4 @@ alert( [1,[0],2][1] );
|
||||||
Квадратные скобки после массива/объекта обозначают не другой массив, а взятие элемента.
|
Квадратные скобки после массива/объекта обозначают не другой массив, а взятие элемента.
|
||||||
</li>
|
</li>
|
||||||
<li>Каждый объект преобразуется к примитиву. У встроенных объектов `Object` нет подходящего `valueOf`, поэтому используется `toString`, так что складываются в итоге строковые представления объектов.</li>
|
<li>Каждый объект преобразуется к примитиву. У встроенных объектов `Object` нет подходящего `valueOf`, поэтому используется `toString`, так что складываются в итоге строковые представления объектов.</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
|
@ -234,5 +234,29 @@ if ( value ) {
|
||||||
Полный алгоритм преобразований есть в спецификации EcmaScript, смотрите пункты [11.8.5](http://es5.github.com/x11.html#x11.8.5), [11.9.3](http://es5.github.com/x11.html#x11.9.3), а также [9.1](http://es5.github.com/x9.html#x9.1) и [9.3](http://es5.github.com/x9.html#x9.3).
|
Полный алгоритм преобразований есть в спецификации EcmaScript, смотрите пункты [11.8.5](http://es5.github.com/x11.html#x11.8.5), [11.9.3](http://es5.github.com/x11.html#x11.9.3), а также [9.1](http://es5.github.com/x9.html#x9.1) и [9.3](http://es5.github.com/x9.html#x9.3).
|
||||||
|
|
||||||
|
|
||||||
|
Заметим, для полноты картины, что некоторые тесты знаний в интернет предлагают вопросы типа:
|
||||||
|
```js
|
||||||
|
{}[0] // чему равно?
|
||||||
|
{} + {} // а так?
|
||||||
|
```
|
||||||
|
|
||||||
|
Если вы запустите эти выражения в консоли, то результат может показаться странным. Подвох здесь в том, что если фигурные скобки `{...}` идут не в выражении, а в основном потоке кода, то JavaScript считает, что это не объект, а "блок кода" (как `if`, `for`, но без оператора, просто группировка команд вместе, используется редко).
|
||||||
|
|
||||||
|
Вот блок кода с командой:
|
||||||
|
```js
|
||||||
|
//+run
|
||||||
|
{
|
||||||
|
alert("Блок")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
А если команду изъять, то будет пустой блок `{}`, который ничего не делает. Два примера выше как раз содержат пустой блок в начале, который ничего не делает. Иначе говоря:
|
||||||
|
```js
|
||||||
|
{}[0] // то же что и: [0]
|
||||||
|
{} + {} // то же что и: + {}
|
||||||
|
```
|
||||||
|
|
||||||
|
То есть, такие вопросы -- не на преобразование типов, а на понимание, что если `{ ... }` находится вне выражений, то это не объект, а блок.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ function f() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = {
|
var user = {
|
||||||
g: bind(f, "Hello")
|
g: f.bind("Hello")
|
||||||
}
|
}
|
||||||
|
|
||||||
user.g();
|
user.g();
|
||||||
|
|
|
@ -10,7 +10,7 @@ function f() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = {
|
var user = {
|
||||||
g: bind(f, "Hello")
|
g: f.bind("Hello")
|
||||||
}
|
}
|
||||||
|
|
||||||
user.g();
|
user.g();
|
||||||
|
|
|
@ -116,25 +116,57 @@ function bind(func, context) {
|
||||||
Посмотрим, что она делает, как работает, на таком примере:
|
Посмотрим, что она делает, как работает, на таком примере:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var oldSayHi = user.sayHi;
|
//+ run
|
||||||
var sayHi = bind(oldSayHi, user);
|
function f() { alert(this); }
|
||||||
|
|
||||||
|
var g = bind(f, "Context");
|
||||||
|
g(); // Context
|
||||||
```
|
```
|
||||||
|
|
||||||
Результатом `bind(oldSayHi, user)`, как видно из кода, будет анонимная функция `(*)`, вот она отдельно:
|
То есть, `bind(f, "Context")` привязывает `"Context"` в качестве `this` для `f`.
|
||||||
|
|
||||||
|
Посмотрим, за счёт чего это происходит.
|
||||||
|
|
||||||
|
Результатом `bind(f, "Context")`, как видно из кода, будет анонимная функция `(*)`.
|
||||||
|
|
||||||
|
Вот она отдельно:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
function() { // (*)
|
function() { // (*)
|
||||||
return oldSayHi.apply(user, arguments);
|
return func.apply(context, arguments);
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
Она запишется в переменную `sayHi`.
|
Если подставить наши конкретные аргументы, то есть `f` и `"Context"`, то получится так:
|
||||||
|
|
||||||
Далее, если её вызвать с какими-то аргументами, например `sayHi("Петя")`, то она "передаёт вызов" в `oldSayHi` -- используется `.apply(user, arguments)`, чтобы передать в качестве контекста `user` (он будет взят из замыкания) и текущие аргументы `arguments`.
|
```js
|
||||||
|
function() { // (*)
|
||||||
|
return f.apply("Context", arguments);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
Иными словами, в результате вызова `bind(func, context)` мы получаем "функцию-обёртку", которая прозрачно передаёт вызов в `func`, с теми же аргументами, но фиксированным контекстом `context`.
|
Эта функция запишется в переменную `g`.
|
||||||
|
|
||||||
Пример с `bind`:
|
Далее, если вызвать `g`, то вызов будет передан в `f`, причём `f.apply("Context", arguments)` передаст в качестве контекста `"Context"`, который и будет выведен.
|
||||||
|
|
||||||
|
Если вызвать `g` с аргументами, то также будет работать:
|
||||||
|
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
function f(a, b) {
|
||||||
|
alert(this);
|
||||||
|
alert(a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
var g = bind(f, "Context");
|
||||||
|
g(1, 2); // Context, затем 3
|
||||||
|
```
|
||||||
|
|
||||||
|
Аргументы, которые получила `g(...)`, передаются в `f` также благодаря методу `.apply`.
|
||||||
|
|
||||||
|
**Иными словами, в результате вызова `bind(func, context)` мы получаем "функцию-обёртку", которая прозрачно передаёт вызов в `func`, с теми же аргументами, но фиксированным контекстом `context`.**
|
||||||
|
|
||||||
|
Вернёмся к `user.sayHi`. Вариант с `bind`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
|
@ -158,15 +190,17 @@ setTimeout( bind(user.sayHi, user), 1000 );
|
||||||
|
|
||||||
Теперь всё в порядке!
|
Теперь всё в порядке!
|
||||||
|
|
||||||
Вызов `bind(user.sayHi, user)` возвращает такую функцию-обёртку, которая гарантированно вызовет `user.sayHi` в контексте `user`. В данном случае, через 1000мс.
|
Вызов `bind(user.sayHi, user)` возвращает такую функцию-обёртку, которая привязывает вызовет `user.sayHi` к контексту `user`. Она будет вызвана через 1000мс.
|
||||||
|
|
||||||
Причём, если вызвать обёртку с аргументами -- они пойдут в `user.sayHi` без изменений, фиксирован лишь контекст.
|
Полученную обёртку можно вызвать и с аргументами -- они пойдут в `user.sayHi` без изменений, фиксирован лишь контекст.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
//+ run
|
//+ run
|
||||||
var user = {
|
var user = {
|
||||||
firstName: "Вася",
|
firstName: "Вася",
|
||||||
sayHi: function(who) {
|
*!*
|
||||||
|
sayHi: function(who) { // здесь у sayHi есть один аргумент
|
||||||
|
*/!*
|
||||||
alert(this.firstName + ": Привет, " + who);
|
alert(this.firstName + ": Привет, " + who);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -174,6 +208,7 @@ var user = {
|
||||||
var sayHi = bind(user.sayHi, user);
|
var sayHi = bind(user.sayHi, user);
|
||||||
|
|
||||||
*!*
|
*!*
|
||||||
|
// контекст Вася, а аргумент передаётся "как есть"
|
||||||
sayHi("Петя"); // Вася: Привет, Петя
|
sayHi("Петя"); // Вася: Привет, Петя
|
||||||
sayHi("Маша"); // Вася: Привет, Маша
|
sayHi("Маша"); // Вася: Привет, Маша
|
||||||
*/!*
|
*/!*
|
||||||
|
@ -187,9 +222,26 @@ sayHi("Маша"); // Вася: Привет, Маша
|
||||||
|
|
||||||
В современном JavaScript (или при подключении библиотеки [es5-shim](https://github.com/kriskowal/es5-shim) для IE8-) у функций уже есть встроенный метод [bind](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind), который мы можем использовать.
|
В современном JavaScript (или при подключении библиотеки [es5-shim](https://github.com/kriskowal/es5-shim) для IE8-) у функций уже есть встроенный метод [bind](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind), который мы можем использовать.
|
||||||
|
|
||||||
Он позволяет получить обёртку, которая привязывает функцию не только к нужному контексту но, если нужно, то и к аргументам.
|
Он работает примерно так же, как `bind`, который описан выше.
|
||||||
|
|
||||||
Синтаксис `bind`:
|
Изменения очень небольшие:
|
||||||
|
|
||||||
|
```js
|
||||||
|
//+ run
|
||||||
|
function f(a, b) {
|
||||||
|
alert(this);
|
||||||
|
alert(a + b);
|
||||||
|
}
|
||||||
|
|
||||||
|
*!*
|
||||||
|
// вместо
|
||||||
|
// var g = bind(f, "Context");
|
||||||
|
var g = f.bind("Context");
|
||||||
|
*/!*
|
||||||
|
g(1, 2); // Context, затем 3
|
||||||
|
```
|
||||||
|
|
||||||
|
Синтаксис встроенного `bind`:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var wrapper = func.bind(context[, arg1, arg2...])
|
var wrapper = func.bind(context[, arg1, arg2...])
|
||||||
|
@ -199,7 +251,7 @@ var wrapper = func.bind(context[, arg1, arg2...])
|
||||||
<dt>`func`</dt>
|
<dt>`func`</dt>
|
||||||
<dd>Произвольная функция</dd>
|
<dd>Произвольная функция</dd>
|
||||||
<dt>`context`</dt>
|
<dt>`context`</dt>
|
||||||
<dd>Обертка `wrapper` будет вызывать функцию с контекстом `this = context`.</dd>
|
<dd>Контекст, который привязывается к `func`</dd>
|
||||||
<dt>`arg1`, `arg2`, ...</dt>
|
<dt>`arg1`, `arg2`, ...</dt>
|
||||||
<dd>Если указаны аргументы `arg1, arg2...` -- они будут прибавлены к каждому вызову новой функции, причем встанут *перед* теми, которые указаны при вызове.</dd>
|
<dd>Если указаны аргументы `arg1, arg2...` -- они будут прибавлены к каждому вызову новой функции, причем встанут *перед* теми, которые указаны при вызове.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
@ -227,6 +279,14 @@ setTimeout( user.sayHi.bind(user), 1000 ); // аналог через встро
|
||||||
|
|
||||||
Далее мы будем использовать именно встроенный метод `bind`.
|
Далее мы будем использовать именно встроенный метод `bind`.
|
||||||
|
|
||||||
|
[warn header="bind не похож call/apply"]
|
||||||
|
Методы `bind` и `call/apply` близки по синтаксису, но есть важнейшее отличие.
|
||||||
|
|
||||||
|
Методы `call/apply` вызывают функцию с заданным контекстом и аргументами.
|
||||||
|
|
||||||
|
А `bind` не вызывает функцию. Он только возвращает "обёртку", которую мы можем вызвать позже, и которая передаст вызов в исходную функцию, с привязанным контекстом.
|
||||||
|
[/warn]
|
||||||
|
|
||||||
[smart header="Привязать всё: `bindAll`"]
|
[smart header="Привязать всё: `bindAll`"]
|
||||||
Если у объекта много методов и мы планируем их активно передавать, то можно привязать контекст для них всех в цикле:
|
Если у объекта много методов и мы планируем их активно передавать, то можно привязать контекст для них всех в цикле:
|
||||||
|
|
||||||
|
@ -241,6 +301,7 @@ for(var prop in user) {
|
||||||
В некоторых JS-фреймворках есть даже встроенные функции для этого, например [_.bindAll(obj)](http://lodash.com/docs#bindAll).
|
В некоторых JS-фреймворках есть даже встроенные функции для этого, например [_.bindAll(obj)](http://lodash.com/docs#bindAll).
|
||||||
[/smart]
|
[/smart]
|
||||||
|
|
||||||
|
|
||||||
## Карринг
|
## Карринг
|
||||||
|
|
||||||
До этого мы говорили о привязке контекста. Теперь пойдём на шаг дальше. Привязывать можно не только контекст, но и аргументы. Используется это реже, но бывает полезно.
|
До этого мы говорили о привязке контекста. Теперь пойдём на шаг дальше. Привязывать можно не только контекст, но и аргументы. Используется это реже, но бывает полезно.
|
||||||
|
|
|
@ -2,32 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<style>
|
<link rel="stylesheet" href="style.css">
|
||||||
body
|
|
||||||
{
|
|
||||||
font: 14px/14px Arial, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
input
|
|
||||||
{
|
|
||||||
font: 14px/14px Arial, sans-serif;
|
|
||||||
|
|
||||||
width: 12em;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#placeholder
|
|
||||||
{
|
|
||||||
font: 14px/14px Arial, sans-serif;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
|
|
||||||
margin: -1.2em 0 0 0.2em;
|
|
||||||
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
body {
|
||||||
|
font: 14px/14px Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
font: 14px/14px Arial, sans-serif;
|
||||||
|
width: 12em;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#placeholder {
|
||||||
|
font: 14px/14px Arial, sans-serif;
|
||||||
|
position: absolute;
|
||||||
|
margin: -1.2em 0 0 0.2em;
|
||||||
|
color: red;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
body {
|
||||||
|
font: 14px/14px Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
font: 14px/14px Arial, sans-serif;
|
||||||
|
width: 12em;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#placeholder {
|
||||||
|
font: 14px/14px Arial, sans-serif;
|
||||||
|
position: absolute;
|
||||||
|
margin: -1.2em 0 0 0.2em;
|
||||||
|
color: red;
|
||||||
|
}
|
|
@ -3,8 +3,7 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<script src="https://cdn.polyfill.io/v1/polyfill.js?features=Element.prototype.closest"></script>
|
<script src="https://cdn.polyfill.io/v1/polyfill.js?features=Element.prototype.closest"></script>
|
||||||
|
|
||||||
<script src="menu.js"></script>
|
<script src="menu.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="menu.css">
|
<link rel="stylesheet" href="menu.css">
|
||||||
<script src="http://code.jquery.com/jquery.min.js"></script>
|
<script src="http://code.jquery.com/jquery.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
<script src="menu.js"></script>
|
<script src="menu.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="menu.css">
|
<link rel="stylesheet" href="menu.css">
|
||||||
<script src="http://code.jquery.com/jquery.min.js"></script>
|
<script src="http://code.jquery.com/jquery.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
<script src="menu.js"></script>
|
<script src="menu.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
С первой группой виджетов -- вопросов нет. Добавляем обработчики, и дело сделано.
|
С первой группой виджетов -- вопросов нет. Добавляем обработчики, и дело сделано.
|
||||||
|
|
||||||
Интересно начинается со второй группы, и совсем интересно -- с третьей группой.
|
Здесь нам интересна вторая группа. Третья -- это по существу оптимизация с едиными шаблонами на клиенте и сервере, рассмотрим её позже.
|
||||||
|
|
||||||
## Зачем нужны шаблоны?
|
## Зачем нужны шаблоны?
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ var template = document.getElementById('menu-template').innerHTML;
|
||||||
```html
|
```html
|
||||||
<!--+ run height=150 -->
|
<!--+ run height=150 -->
|
||||||
<!-- библиотека LoDash -->
|
<!-- библиотека LoDash -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
|
|
||||||
<!-- шаблон для списка от 1 до count -->
|
<!-- шаблон для списка от 1 до count -->
|
||||||
<script *!*type="text/template"*/!* id="list-template">
|
<script *!*type="text/template"*/!* id="list-template">
|
||||||
|
@ -408,11 +408,11 @@ function Menu(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
var elemHtml = options.template({title: options.title});
|
var html = options.template({title: options.title});
|
||||||
|
|
||||||
elem = document.createElement('div');
|
elem = document.createElement('div');
|
||||||
elem.innerHTML = elemHTML;
|
elem.innerHTML = html;
|
||||||
elem = elem.firstChild;
|
elem = elem.firstElementChild;
|
||||||
|
|
||||||
elem.onmousedown = function() {
|
elem.onmousedown = function() {
|
||||||
return false;
|
return false;
|
||||||
|
@ -509,12 +509,32 @@ function(obj) {
|
||||||
|
|
||||||
Нои здесь можно кое-что отладить. При ошибке, если она не синтаксическая, отладчик при этом останавливается где-то посередине "страшной" функции.
|
Нои здесь можно кое-что отладить. При ошибке, если она не синтаксическая, отладчик при этом останавливается где-то посередине "страшной" функции.
|
||||||
|
|
||||||
При этом, особенно если шаблонов много и компилируются они где-то раньше по коду -- бывает совершенно неочевидно, из какого шаблона она получена.
|
|
||||||
|
|
||||||
Попробуйте сами запустить пример с открытыми инструментами разработчика и включённой опцией "остановка при ошибке":
|
Попробуйте сами запустить пример с открытыми инструментами разработчика и *включённой* опцией "остановка при ошибке":
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!--+ run src="index.html" -->
|
<!--+ run -->
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
|
|
||||||
|
<script type="text/template" id="menu-template">
|
||||||
|
<div class="menu">
|
||||||
|
<span class="title"><%-title%>
|
||||||
|
<ul>
|
||||||
|
<% items.forEach(function(item) { %>
|
||||||
|
<li><%-item%></li>
|
||||||
|
<% }); %>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var tmpl = document.getElementById('menu-template').innerHTML;
|
||||||
|
|
||||||
|
var compiled = _.template(tmpl);
|
||||||
|
var result = compiled({ title: "Заголовок" });
|
||||||
|
|
||||||
|
document.write(result);
|
||||||
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
В шаблоне допущена ошибка, поэтому отладчик остановит выполнение.
|
В шаблоне допущена ошибка, поэтому отладчик остановит выполнение.
|
||||||
|
@ -523,13 +543,13 @@ function(obj) {
|
||||||
|
|
||||||
<img src="template-debugger.png">
|
<img src="template-debugger.png">
|
||||||
|
|
||||||
**LoDash пытается нам помочь. Он добавляет к шаблонам специальный идентификатор [sourceURL](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl), который служит аналогом "имени файла". На картинке он отмечен красным.**
|
Библиотека LoDash пытается нам помочь, подсказать, в каком именно шаблоне произошла ошибка. Ведь из функции это может быть неочевидно.
|
||||||
|
|
||||||
|
Для этого она добавляет к шаблонам специальный идентификатор [sourceURL](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl), который служит аналогом "имени файла". На картинке он отмечен красным.
|
||||||
|
|
||||||
По умолчанию `sourceURL` имеет вид `/lodash/template/source[N]`, где `N` -- постоянно увеличивающийся номер шаблона. В данном случае мы можем понять, что эта функция получена при самой первой компиляции.
|
По умолчанию `sourceURL` имеет вид `/lodash/template/source[N]`, где `N` -- постоянно увеличивающийся номер шаблона. В данном случае мы можем понять, что эта функция получена при самой первой компиляции.
|
||||||
|
|
||||||
**Это, конечно, лучше чем ничего, но, как правило, его имеет смысл заменить `sourceURL` на свой.**
|
Это, конечно, лучше чем ничего, но, как правило, его имеет смысл заменить `sourceURL` на свой, указав при компиляции дополнительный параметр `sourceURL`:
|
||||||
|
|
||||||
Это делается при компиляции дополнительным параметром `sourceURL`:
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
...
|
...
|
||||||
|
@ -537,7 +557,7 @@ var compiled = _.template(tmpl, null, {sourceURL: '/template/menu-template'});
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
Попробуйте запустить [исправленный пример](/tutorial/widgets/template-error-sourceurl/) и вы увидите в качестве имени файла `/template/menu-template`.
|
Попробуйте запустить [исправленный пример](template-error-sourceurl/) и вы увидите в качестве имени файла `/template/menu-template`.
|
||||||
|
|
||||||
[warn header="Не определена переменная -- ошибка"]
|
[warn header="Не определена переменная -- ошибка"]
|
||||||
Кстати говоря, а в чём же здесь ошибка?
|
Кстати говоря, а в чём же здесь ошибка?
|
||||||
|
@ -551,7 +571,7 @@ var compiled = _.template(tmpl, null, {sourceURL: '/template/menu-template'});
|
||||||
|
|
||||||
Шаблоны полезны для того, чтобы отделить HTML от кода. Это упрощает разработку и поддержку.
|
Шаблоны полезны для того, чтобы отделить HTML от кода. Это упрощает разработку и поддержку.
|
||||||
|
|
||||||
В этой главе подробно разобрана система шаблонизации из библиотеки [LoDash](https://github.com/bestiejs/lodash).
|
В этой главе подробно разобрана система шаблонизации из библиотеки [LoDash](https://lodash.com).
|
||||||
|
|
||||||
Теперь, когда мы с ней знакомы, мы можем как использовать её в своих проектах, так и перейти к более глобальному рассмотрению подходов к шаблонизации.
|
Теперь, когда мы с ней знакомы, мы можем как использовать её в своих проектах, так и перейти к более глобальному рассмотрению подходов к шаблонизации.
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="menu.css">
|
<link rel="stylesheet" href="menu.css">
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
|
<script src="https://cdn.polyfill.io/v1/polyfill.js?features=Element.prototype.closest"></script>
|
||||||
<script src="menu.js"></script>
|
<script src="menu.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -7,11 +7,11 @@ function Menu(options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
var elemHtml = options.template({title: options.title});
|
var html = options.template({title: options.title});
|
||||||
|
|
||||||
elem = document.createElement('div');
|
elem = document.createElement('div');
|
||||||
elem.innerHTML = elemHTML;
|
elem.innerHTML = html;
|
||||||
elem = elem.firstChild;
|
elem = elem.firstElementChild;
|
||||||
|
|
||||||
elem.onmousedown = function() {
|
elem.onmousedown = function() {
|
||||||
return false;
|
return false;
|
||||||
|
|
4
2-ui/5-widgets/4-template-lodash/index.html → 2-ui/5-widgets/4-template-lodash/template-error-sourceurl.view/index.html
Executable file → Normal file
4
2-ui/5-widgets/4-template-lodash/index.html → 2-ui/5-widgets/4-template-lodash/template-error-sourceurl.view/index.html
Executable file → Normal file
|
@ -2,7 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
|
|
||||||
<script type="text/template" id="menu-template">
|
<script type="text/template" id="menu-template">
|
||||||
<div class="menu">
|
<div class="menu">
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
<script>
|
<script>
|
||||||
var tmpl = document.getElementById('menu-template').innerHTML;
|
var tmpl = document.getElementById('menu-template').innerHTML;
|
||||||
|
|
||||||
var compiled = _.template(tmpl);
|
var compiled = _.template(tmpl, null, {sourceURL: '/template/menu-template'});
|
||||||
var result = compiled({ title: "Заголовок" });
|
var result = compiled({ title: "Заголовок" });
|
||||||
|
|
||||||
document.write(result);
|
document.write(result);
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<script src="http://code.jquery.com/jquery.min.js"></script>
|
<script src="http://code.jquery.com/jquery.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
<script src="menu.js"></script>
|
<script src="menu.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<script src="http://code.jquery.com/jquery.min.js"></script>
|
<script src="http://code.jquery.com/jquery.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js"></script>
|
||||||
<script src="eventMixin.js"></script>
|
<script src="eventMixin.js"></script>
|
||||||
<script src="menu.js"></script>
|
<script src="menu.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue