beautify 1st part of the tutorial
This commit is contained in:
parent
e3dd2cedc0
commit
6444024a9d
327 changed files with 2358 additions and 1986 deletions
|
@ -6,7 +6,9 @@
|
|||
//+ run
|
||||
var arr = ["a", "b"];
|
||||
|
||||
arr.push( function() { alert(this); } )
|
||||
arr.push(function() {
|
||||
alert( this );
|
||||
})
|
||||
|
||||
arr[2](); // "a","b",function
|
||||
```
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
```js
|
||||
var arr = ["a", "b"];
|
||||
|
||||
arr.push( function() { alert(this); } )
|
||||
arr.push(function() {
|
||||
alert( this );
|
||||
})
|
||||
|
||||
arr[2](); // ?
|
||||
arr[2](); // ?
|
||||
```
|
||||
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
```js
|
||||
//+ run
|
||||
var obj = {
|
||||
go: function() { alert(this) }
|
||||
go: function() {
|
||||
alert(this)
|
||||
}
|
||||
}
|
||||
|
||||
(obj.go)() // error!
|
||||
(obj.go)() // error!
|
||||
```
|
||||
|
||||
Причем сообщение об ошибке в большинстве браузеров не даёт понять, что на самом деле не так.
|
||||
|
@ -18,6 +20,7 @@ var obj = {
|
|||
JavaScript игнорирует перевод строки перед скобкой `(obj.go)()` и читает этот код как:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
var obj = { go:... }(obj.go)()
|
||||
```
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
Каков будет результат этого кода?
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
var obj = {
|
||||
go: function() { alert(this) }
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<li>Здесь не просто вызов `obj.method()`, а более сложный вызов вида `(выражение).method()`. Такой вызов работает, как если бы он был разбит на две строки:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
f = obj.go; // сначала вычислить выражение
|
||||
f(); // потом вызвать то, что получилось
|
||||
```
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
Вызовы `(1)` и `(2)` в примере ниже работают не так, как `(3)` и `(4)`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
"use strict"
|
||||
|
||||
var obj, f;
|
||||
|
|
|
@ -6,13 +6,13 @@ var name = "";
|
|||
|
||||
var user = {
|
||||
name: "Василий",
|
||||
|
||||
|
||||
*!*
|
||||
export: this // (*)
|
||||
*/!*
|
||||
};
|
||||
};
|
||||
|
||||
alert(user.export.name);
|
||||
alert( user.export.name );
|
||||
```
|
||||
|
||||
Объявление объекта само по себе не влияет на `this`. Никаких функций, которые могли бы повлиять на контекст, здесь нет.
|
||||
|
|
|
@ -9,10 +9,10 @@ var name = "";
|
|||
|
||||
var user = {
|
||||
name: "Василий",
|
||||
|
||||
export: this
|
||||
};
|
||||
|
||||
alert(user.export.name);
|
||||
export: this
|
||||
};
|
||||
|
||||
alert( user.export.name );
|
||||
```
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ var name = "";
|
|||
|
||||
var user = {
|
||||
name: "Василий",
|
||||
|
||||
export: function() {
|
||||
|
||||
export: function() {
|
||||
return this;
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
alert(user.export().name);
|
||||
alert( user.export().name );
|
||||
```
|
||||
|
||||
|
|
|
@ -9,15 +9,15 @@ var name = "";
|
|||
|
||||
var user = {
|
||||
name: "Василий",
|
||||
|
||||
|
||||
export: function() {
|
||||
return {
|
||||
return {
|
||||
value: this
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
alert(user.export().value.name);
|
||||
alert( user.export().value.name );
|
||||
```
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
</ul>
|
||||
|
||||
```js
|
||||
var calculator = {
|
||||
... ваш код...
|
||||
var calculator = {
|
||||
...ваш код...
|
||||
}
|
||||
|
||||
calculator.read();
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
//+ run
|
||||
var ladder = {
|
||||
step: 0,
|
||||
up: function() {
|
||||
this.step++;
|
||||
up: function() {
|
||||
this.step++;
|
||||
return this;
|
||||
},
|
||||
down: function() {
|
||||
this.step--;
|
||||
down: function() {
|
||||
this.step--;
|
||||
return this;
|
||||
},
|
||||
showStep: function() {
|
||||
alert(this.step);
|
||||
showStep: function() {
|
||||
alert( this.step );
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
ladder.up().up().down().up().down().showStep(); // 1
|
||||
ladder.up().up().down().up().down().showStep(); // 1
|
||||
```
|
||||
|
||||
|
|
|
@ -7,14 +7,14 @@
|
|||
```js
|
||||
var ladder = {
|
||||
step: 0,
|
||||
up: function() { // вверх по лестнице
|
||||
up: function() { // вверх по лестнице
|
||||
this.step++;
|
||||
},
|
||||
down: function() { // вниз по лестнице
|
||||
down: function() { // вниз по лестнице
|
||||
this.step--;
|
||||
},
|
||||
showStep: function() { // вывести текущую ступеньку
|
||||
alert(this.step);
|
||||
alert( this.step );
|
||||
}
|
||||
};
|
||||
```
|
||||
|
@ -31,7 +31,7 @@ ladder.showStep(); // 1
|
|||
Модифицируйте код методов объекта, чтобы вызовы можно было делать цепочкой, вот так:
|
||||
|
||||
```js
|
||||
ladder.up().up().down().up().down().showStep(); // 1
|
||||
ladder.up().up().down().up().down().showStep(); // 1
|
||||
```
|
||||
|
||||
Такой подход называется "чейнинг" (chaining) и используется, например, во фреймворке jQuery.
|
||||
|
|
|
@ -16,7 +16,7 @@ var user = {
|
|||
// метод
|
||||
*/!*
|
||||
sayHi: function() {
|
||||
alert('Привет!');
|
||||
alert( 'Привет!' );
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -101,7 +101,7 @@ admin.sayHi(); // упс! внутри sayHi обращение по старо
|
|||
Через `this` метод может не только обратиться к любому свойству объекта, но и передать куда-то ссылку на сам объект целиком:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var user = {
|
||||
name: 'Василий',
|
||||
|
||||
|
@ -138,7 +138,7 @@ function sayHi() {
|
|||
**Если одну и ту же функцию запускать в контексте разных объектов, она будет получать разный `this`:**
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var user = { firstName: "Вася" };
|
||||
var admin = { firstName: "Админ" };
|
||||
|
||||
|
@ -169,8 +169,8 @@ admin['g'](); // Админ (не важно, доступ к объекту ч
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function func() {
|
||||
alert(this); // выведет [object Window] или [object global]
|
||||
function func() {
|
||||
alert( this ); // выведет [object Window] или [object global]
|
||||
}
|
||||
|
||||
func();
|
||||
|
@ -182,9 +182,9 @@ func();
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function func() {
|
||||
function func() {
|
||||
"use strict";
|
||||
alert(this); // выведет undefined (кроме IE9-)
|
||||
alert( this ); // выведет undefined (кроме IE9-)
|
||||
}
|
||||
|
||||
func();
|
||||
|
@ -199,7 +199,7 @@ func();
|
|||
Любой более хитрый вызов приведёт к потере контекста, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var user = {
|
||||
name: "Вася",
|
||||
hi: function() { alert(this.name); },
|
||||
|
|
|
@ -9,7 +9,7 @@ P.S.
|
|||
|
||||
```js
|
||||
//+ run
|
||||
alert( ['x','y'] == 'x,y' ); // true
|
||||
alert( ['x', 'y'] == 'x,y' ); // true
|
||||
alert( [] == '' ); // true
|
||||
```
|
||||
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
|
||||
```js
|
||||
var foo = {
|
||||
toString: function () {
|
||||
return 'foo';
|
||||
},
|
||||
valueOf: function () {
|
||||
return 2;
|
||||
}
|
||||
toString: function() {
|
||||
return 'foo';
|
||||
},
|
||||
valueOf: function() {
|
||||
return 2;
|
||||
}
|
||||
};
|
||||
|
||||
alert(foo);
|
||||
alert(foo + 1);
|
||||
alert(foo + "3");
|
||||
alert( foo );
|
||||
alert( foo + 1 );
|
||||
alert( foo + "3" );
|
||||
```
|
||||
|
||||
Подумайте, прежде чем ответить.
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
```js
|
||||
//+ run
|
||||
alert( [] == [] ); // false
|
||||
alert( [] == [] ); // false
|
||||
alert( [] == ![] ); // true
|
||||
```
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
new Date(0) - 0 = 0 // (1)
|
||||
new Array(1)[0] + "" = "undefined" // (2)
|
||||
({})[0]
= undefined // (3)
|
||||
|
@ -24,6 +25,7 @@ new Array(1)[0] + "" = "undefined" // (2)
|
|||
Если это непонятно, то посмотрите на такой пример:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
alert( [1,[0],2][1] );
|
||||
```
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
Подумайте, какой результат будет у выражений ниже. Когда закончите -- сверьтесь с решением.
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
new Date(0) - 0
|
||||
new Array(1)[0] + ""
|
||||
({})[0]
|
||||
|
|
|
@ -13,23 +13,25 @@
|
|||
```js
|
||||
//+ run
|
||||
function sum(a) {
|
||||
|
||||
|
||||
var currentSum = a;
|
||||
|
||||
|
||||
function f(b) {
|
||||
currentSum += b;
|
||||
return f;
|
||||
}
|
||||
|
||||
f.toString = function() { return currentSum; };
|
||||
|
||||
|
||||
f.toString = function() {
|
||||
return currentSum;
|
||||
};
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
alert( sum(1)(2) ); // 3
|
||||
alert( sum(5)(-1)(2) ); // 6
|
||||
alert( sum(6)(-1)(-2)(-3) ); // 0
|
||||
alert( sum(0)(1)(2)(3)(4)(5) ); // 15
|
||||
alert( sum(1)(2) ); // 3
|
||||
alert( sum(5)(-1)(2) ); // 6
|
||||
alert( sum(6)(-1)(-2)(-3) ); // 0
|
||||
alert( sum(0)(1)(2)(3)(4)(5) ); // 15
|
||||
```
|
||||
|
||||
При внимательном взгляде на решение легко заметить, что функция `sum` срабатывает только один раз. Она возвращает функцию `f`.
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
```js
|
||||
//+ run
|
||||
if ( {} && [] ) {
|
||||
alert("Все объекты - true!"); // alert сработает
|
||||
if ({} && []) {
|
||||
alert( "Все объекты - true!" ); // alert сработает
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -33,11 +33,11 @@ if ( {} && [] ) {
|
|||
|
||||
```js
|
||||
//+ run
|
||||
var user = {
|
||||
firstName: 'Василий'
|
||||
var user = {
|
||||
firstName: 'Василий'
|
||||
};
|
||||
|
||||
alert(user); // [object Object]
|
||||
alert( user ); // [object Object]
|
||||
```
|
||||
|
||||
Как видно, содержимое объекта не вывелось. Это потому, что стандартным строковым представлением пользовательского объекта является строка `"[object Object]"`.
|
||||
|
@ -68,10 +68,12 @@ alert( user ); // Пользователь Василий
|
|||
```js
|
||||
//+ run
|
||||
var obj = {
|
||||
toString: function() { return 123; }
|
||||
toString: function() {
|
||||
return 123;
|
||||
}
|
||||
};
|
||||
|
||||
alert(obj); // 123
|
||||
alert( obj ); // 123
|
||||
```
|
||||
|
||||
Поэтому мы и называем его здесь *"строковое преобразование"*, а не "преобразование к строке".
|
||||
|
@ -81,9 +83,9 @@ alert(obj); // 123
|
|||
|
||||
```js
|
||||
//+ run
|
||||
alert( [1,2] ); // toString для массивов выводит список элементов "1,2"
|
||||
alert( [1, 2] ); // toString для массивов выводит список элементов "1,2"
|
||||
alert( new Date ); // toString для дат выводит дату в виде строки
|
||||
alert( function() { } ); // toString для функции выводит её код
|
||||
alert( function() {} ); // toString для функции выводит её код
|
||||
```
|
||||
|
||||
## Численное преобразование
|
||||
|
@ -134,11 +136,13 @@ alert( +new Date() ); // valueOf: кол-во миллисекунд, проше
|
|||
|
||||
```js
|
||||
//+ run
|
||||
var obj = {
|
||||
valueOf: function() { return 1; }
|
||||
var obj = {
|
||||
valueOf: function() {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
alert(obj == true); // true
|
||||
alert( obj == true ); // true
|
||||
```
|
||||
|
||||
Объект `obj` был сначала преобразован в примитив, используя численное преобразование, получилось `1 == true`.
|
||||
|
@ -149,25 +153,31 @@ alert(obj == true); // true
|
|||
|
||||
```js
|
||||
//+ run
|
||||
var obj = {
|
||||
valueOf: function() { return 1; }
|
||||
var obj = {
|
||||
valueOf: function() {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
alert(obj + "test"); // 1test
|
||||
alert( obj + "test" ); // 1test
|
||||
```
|
||||
|
||||
Или вот, для разности объектов:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var a = {
|
||||
valueOf: function() { return "1"; }
|
||||
var a = {
|
||||
valueOf: function() {
|
||||
return "1";
|
||||
}
|
||||
};
|
||||
var b = {
|
||||
valueOf: function() { return "2"; }
|
||||
var b = {
|
||||
valueOf: function() {
|
||||
return "2";
|
||||
}
|
||||
};
|
||||
|
||||
alert(a - b); // "1" - "2" = -1
|
||||
alert( a - b ); // "1" - "2" = -1
|
||||
```
|
||||
|
||||
[warn header="Исключение: `Date`"]
|
||||
|
@ -194,9 +204,9 @@ alert( +new Date ); // число миллисекунд
|
|||
|
||||
```js
|
||||
//+ run
|
||||
var value = new Boolean(false);
|
||||
if ( value ) {
|
||||
alert(true); // сработает!
|
||||
var value = new Boolean(false);
|
||||
if (value) {
|
||||
alert( true ); // сработает!
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -204,14 +214,14 @@ if ( value ) {
|
|||
|
||||
```js
|
||||
//+ run
|
||||
var value = new Boolean(false);
|
||||
var value = new Boolean(false);
|
||||
|
||||
*!*
|
||||
alert(value); // выводит false, все ок..
|
||||
alert( value ); // выводит false, все ок..
|
||||
*/!*
|
||||
|
||||
if ( value ) {
|
||||
alert(true); // ..но тогда почему выполняется alert в if ?!?
|
||||
if (value) {
|
||||
alert( true ); // ..но тогда почему выполняется alert в if ?!?
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -236,6 +246,7 @@ if ( value ) {
|
|||
|
||||
Заметим, для полноты картины, что некоторые тесты знаний в интернет предлагают вопросы типа:
|
||||
```js
|
||||
//+ no-beautify
|
||||
{}[0] // чему равно?
|
||||
{} + {} // а так?
|
||||
```
|
||||
|
@ -252,6 +263,7 @@ if ( value ) {
|
|||
|
||||
А если команду изъять, то будет пустой блок `{}`, который ничего не делает. Два примера выше как раз содержат пустой блок в начале, который ничего не делает. Иначе говоря:
|
||||
```js
|
||||
//+ no-beautify
|
||||
{}[0] // то же что и: [0]
|
||||
{} + {} // то же что и: + {}
|
||||
```
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
Например, они могут вернуть один и тот же объект `obj`, определённый снаружи:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var obj = {};
|
||||
|
||||
function A() { return obj; }
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
Возможны ли такие функции `A` и `B` в примере ниже, что соответствующие объекты `a,b` равны (см. код ниже)?
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function A() { ... }
|
||||
function B() { ... }
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
function Calculator() {
|
||||
|
||||
this.read = function() {
|
||||
this.a = +prompt('a?', 0);
|
||||
this.a = +prompt('a?', 0);
|
||||
this.b = +prompt('b?', 0);
|
||||
};
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ function Calculator() {
|
|||
op = split[1],
|
||||
b = +split[2]
|
||||
|
||||
if(!methods[op] || isNaN(a) || isNaN(b)) {
|
||||
if (!methods[op] || isNaN(a) || isNaN(b)) {
|
||||
return NaN;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ calc.addMethod("**", function(a, b) {
|
|||
});
|
||||
|
||||
var result = calc.calculate("2 ** 3");
|
||||
alert(result); // 8
|
||||
alert( result ); // 8
|
||||
```
|
||||
|
||||
<ul>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
```js
|
||||
var calc = new Calculator;
|
||||
|
||||
alert(calc.calculate("3 + 7")); // 10
|
||||
alert( calc.calculate("3 + 7") ); // 10
|
||||
```
|
||||
|
||||
</li>
|
||||
|
@ -23,12 +23,18 @@ alert(calc.calculate("3 + 7")); // 10
|
|||
|
||||
```js
|
||||
var powerCalc = new Calculator;
|
||||
powerCalc.addMethod("*", function(a, b) { return a * b; });
|
||||
powerCalc.addMethod("/", function(a, b) { return a / b; });
|
||||
powerCalc.addMethod("**", function(a, b) { return Math.pow(a, b); });
|
||||
powerCalc.addMethod("*", function(a, b) {
|
||||
return a * b;
|
||||
});
|
||||
powerCalc.addMethod("/", function(a, b) {
|
||||
return a / b;
|
||||
});
|
||||
powerCalc.addMethod("**", function(a, b) {
|
||||
return Math.pow(a, b);
|
||||
});
|
||||
|
||||
var result = powerCalc.calculate("2 ** 3");
|
||||
alert(result); // 8
|
||||
alert( result ); // 8
|
||||
```
|
||||
|
||||
</li>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
```js
|
||||
function Animal(name) {
|
||||
this.name = name;
|
||||
this.canWalk = true;
|
||||
this.canWalk = true;
|
||||
}
|
||||
|
||||
*!*
|
||||
|
@ -52,7 +52,7 @@ function Animal(name) {
|
|||
|
||||
// в this пишем свойства, методы
|
||||
this.name = name;
|
||||
this.canWalk = true;
|
||||
this.canWalk = true;
|
||||
|
||||
*!*
|
||||
// return this
|
||||
|
@ -75,7 +75,7 @@ function Animal(name) {
|
|||
Например, возврат объекта:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
function BigAnimal() {
|
||||
|
||||
this.name = "Мышь";
|
||||
|
@ -97,7 +97,7 @@ function BigAnimal() {
|
|||
return "Годзилла"; // <-- возвратим примитив
|
||||
}
|
||||
|
||||
alert( new BigAnimal().name ); // Мышь, получили this (а Годзилла пропал)
|
||||
alert( new BigAnimal().name ); // Мышь, получили this (а Годзилла пропал)
|
||||
```
|
||||
|
||||
Эта особенность работы `new` прописана в стандарте, но используется она весьма редко.
|
||||
|
@ -126,9 +126,9 @@ var animal = new BigAnimal();
|
|||
//+ run
|
||||
function User(name) {
|
||||
this.name = name;
|
||||
|
||||
|
||||
this.sayHi = function() {
|
||||
alert("Моё имя: " + this.name);
|
||||
alert( "Моё имя: " + this.name );
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -156,15 +156,15 @@ function User(firstName, lastName) {
|
|||
*!*
|
||||
// вспомогательная переменная
|
||||
var phrase = "Привет";
|
||||
|
||||
|
||||
// вспомогательная вложенная функция
|
||||
function getFullName() {
|
||||
return firstName + " " + lastName;
|
||||
}
|
||||
function getFullName() {
|
||||
return firstName + " " + lastName;
|
||||
}
|
||||
*/!*
|
||||
|
||||
|
||||
this.sayHi = function() {
|
||||
alert(phrase + ", " + getFullName()); // использование
|
||||
alert( phrase + ", " + getFullName() ); // использование
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
```js
|
||||
//+ run
|
||||
|
||||
function User(fullName) {
|
||||
this.fullName = fullName;
|
||||
|
||||
|
@ -38,12 +37,12 @@ function User(fullName) {
|
|||
var vasya = new User("Василий Попкин");
|
||||
|
||||
// чтение firstName/lastName
|
||||
alert(vasya.firstName); // Василий
|
||||
alert(vasya.lastName); // Попкин
|
||||
alert( vasya.firstName ); // Василий
|
||||
alert( vasya.lastName ); // Попкин
|
||||
|
||||
// запись в lastName
|
||||
vasya.lastName = 'Сидоров';
|
||||
|
||||
alert(vasya.fullName); // Василий Сидоров
|
||||
alert( vasya.fullName ); // Василий Сидоров
|
||||
```
|
||||
|
||||
|
|
|
@ -20,13 +20,13 @@ var vasya = new User("Василий Попкин");
|
|||
var vasya = new User("Василий Попкин");
|
||||
|
||||
// чтение firstName/lastName
|
||||
alert(vasya.firstName); // Василий
|
||||
alert(vasya.lastName); // Попкин
|
||||
alert( vasya.firstName ); // Василий
|
||||
alert( vasya.lastName ); // Попкин
|
||||
|
||||
// запись в lastName
|
||||
vasya.lastName = 'Сидоров';
|
||||
|
||||
alert(vasya.fullName); // Василий Сидоров
|
||||
alert( vasya.fullName ); // Василий Сидоров
|
||||
```
|
||||
|
||||
Важно: не рекомендуется дублировать одни и те же данные в различных свойствах. Поэтому в этой задаче `fullName` должно остаться свойством, а `firstName/lastName` -- реализованы через `get/set`.
|
|
@ -46,6 +46,7 @@ Object.defineProperty(obj, prop, descriptor)
|
|||
Два таких вызова работают одинаково:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
var user = {};
|
||||
|
||||
// 1. простое присваивание
|
||||
|
@ -69,7 +70,7 @@ var user = {};
|
|||
|
||||
Object.defineProperty(user, "name", {
|
||||
value: "Вася",
|
||||
writable: false, // запретить присвоение "user.name="
|
||||
writable: false, // запретить присвоение "user.name="
|
||||
configurable: false // запретить удаление "delete user.name"
|
||||
});
|
||||
|
||||
|
@ -90,7 +91,7 @@ user.name = "Петя";
|
|||
К сожалению, свойство `toString`, объявленное обычным способом, будет видно в цикле `for..in`, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var user = {
|
||||
name: "Вася",
|
||||
toString: function() { return this.name; }
|
||||
|
@ -106,7 +107,7 @@ for(var key in user) alert(key); // name, toString
|
|||
`Object.defineProperty` может исключить `toString` из списка итерации, поставив ему флаг `enumerable: false`. По стандарту, у встроенного `toString` этот флаг уже стоит.
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
var user = {
|
||||
name: "Вася",
|
||||
toString: function() { return this.name; }
|
||||
|
@ -169,18 +170,18 @@ Object.defineProperty(user, "fullName", {
|
|||
|
||||
*!*
|
||||
set: function(value) {
|
||||
var split = value.split(' ');
|
||||
this.firstName = split[0];
|
||||
this.surname = split[1];
|
||||
}
|
||||
var split = value.split(' ');
|
||||
this.firstName = split[0];
|
||||
this.surname = split[1];
|
||||
}
|
||||
*/!*
|
||||
});
|
||||
|
||||
*!*
|
||||
user.fullName = "Петя Иванов";
|
||||
*/!*
|
||||
alert(user.firstName); // Петя
|
||||
alert(user.surname); // Иванов
|
||||
alert( user.firstName ); // Петя
|
||||
alert( user.surname ); // Иванов
|
||||
```
|
||||
|
||||
## Указание get/set в литералах
|
||||
|
@ -213,11 +214,11 @@ var user = {
|
|||
};
|
||||
|
||||
*!*
|
||||
alert(user.fullName); // Вася Петров (из геттера)
|
||||
alert( user.fullName ); // Вася Петров (из геттера)
|
||||
|
||||
user.fullName = "Петя Иванов";
|
||||
alert(user.firstName); // Петя (поставил сеттер)
|
||||
alert(user.surname); // Иванов (поставил сеттер)
|
||||
alert( user.firstName ); // Петя (поставил сеттер)
|
||||
alert( user.surname ); // Иванов (поставил сеттер)
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -237,7 +238,7 @@ function User(name, age) {
|
|||
|
||||
var pete = new User("Петя", 25);
|
||||
|
||||
alert(pete.age); // 25
|
||||
alert( pete.age ); // 25
|
||||
```
|
||||
|
||||
С обычными свойствами в коде меньше букв, они удобны, причины использовать функции пока нет.
|
||||
|
@ -268,8 +269,8 @@ function User(name, birthday) {
|
|||
this.birthday = birthday;
|
||||
|
||||
*!*
|
||||
Object.defineProperty(this, "age", {
|
||||
get: function() {
|
||||
Object.defineProperty(this, "age", {
|
||||
get: function() {
|
||||
var todayYear = new Date().getFullYear();
|
||||
return todayYear - this.birthday.getFullYear();
|
||||
}
|
||||
|
@ -279,7 +280,7 @@ function User(name, birthday) {
|
|||
|
||||
var pete = new User("Петя", new Date(1987, 6, 1));
|
||||
|
||||
alert(pete.age); // получает возраст из даты рождения
|
||||
alert( pete.age ); // получает возраст из даты рождения
|
||||
```
|
||||
|
||||
Таким образом, `defineProperty` позволяет нам использовать обычные свойства и, при необходимости, в любой момент заменить их на функции, сохраняя полную совместимость.
|
||||
|
@ -335,7 +336,9 @@ var obj = {
|
|||
internal: 3
|
||||
};
|
||||
|
||||
Object.defineProperty(obj, "internal", {enumerable: false});
|
||||
Object.defineProperty(obj, "internal", {
|
||||
enumerable: false
|
||||
});
|
||||
|
||||
*!*
|
||||
alert( Object.keys(obj) ); // a,b
|
||||
|
@ -351,7 +354,9 @@ alert( Object.getOwnPropertyNames(obj) ); // a, internal, b
|
|||
|
||||
```js
|
||||
//+ run
|
||||
var obj = { test: 5 };
|
||||
var obj = {
|
||||
test: 5
|
||||
};
|
||||
*!*
|
||||
var descriptor = Object.getOwnPropertyDescriptor(obj, 'test');
|
||||
*/!*
|
||||
|
@ -362,7 +367,7 @@ var descriptor = Object.getOwnPropertyDescriptor(obj, 'test');
|
|||
delete descriptor.value; // ..нужно убрать value/writable
|
||||
delete descriptor.writable;
|
||||
descriptor.get = function() { // и поставить get
|
||||
alert("Preved :)");
|
||||
alert( "Preved :)" );
|
||||
};
|
||||
|
||||
*!*
|
||||
|
@ -370,7 +375,7 @@ descriptor.get = function() { // и поставить get
|
|||
*/!*
|
||||
|
||||
// если не удалить - defineProperty объединит старый дескриптор с новым
|
||||
delete obj.test;
|
||||
delete obj.test;
|
||||
|
||||
Object.defineProperty(obj, 'test', descriptor);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function Article() {
|
||||
function Article() {
|
||||
this.created = new Date;
|
||||
|
||||
*!*
|
||||
|
@ -14,7 +14,7 @@ Article.count = 0; // начальное значение
|
|||
// (нельзя оставить undefined, т.к. Article.count++ будет NaN)
|
||||
|
||||
Article.showStats = function() {
|
||||
alert('Всего: ' + this.count + ', Последняя: ' + this.last);
|
||||
alert( 'Всего: ' + this.count + ', Последняя: ' + this.last );
|
||||
};
|
||||
|
||||
new Article();
|
||||
|
|
|
@ -38,7 +38,7 @@ Article.count = 0;
|
|||
|
||||
Article.showCount = function() {
|
||||
*!*
|
||||
alert(this.count); // (1)
|
||||
alert( this.count ); // (1)
|
||||
*/!*
|
||||
}
|
||||
|
||||
|
@ -82,10 +82,10 @@ function Journal(date) {
|
|||
this.date = date;
|
||||
|
||||
this.formatDate = function(date) {
|
||||
return date.getDate() + '.' + (date.getMonth()+1) + '.' + date.getFullYear();
|
||||
return date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear();
|
||||
};
|
||||
|
||||
this.getTitle = function() {
|
||||
this.getTitle = function() {
|
||||
return "Выпуск от " + this.formatDate(this.date);
|
||||
};
|
||||
|
||||
|
@ -99,17 +99,17 @@ Journal.compare = function(journalA, journalB) {
|
|||
|
||||
// использование:
|
||||
var journals = [
|
||||
new Journal(new Date(2012,1,1)),
|
||||
new Journal(new Date(2012,0,1)),
|
||||
new Journal(new Date(2011,11,1))
|
||||
new Journal(new Date(2012, 1, 1)),
|
||||
new Journal(new Date(2012, 0, 1)),
|
||||
new Journal(new Date(2011, 11, 1))
|
||||
];
|
||||
|
||||
function findMin(journals) {
|
||||
var min = 0;
|
||||
for(var i=0; i<journals.length; i++) {
|
||||
for (var i = 0; i < journals.length; i++) {
|
||||
*!*
|
||||
// используем статический метод
|
||||
if ( Journal.compare(journals[min], journals[i]) > 0 ) min = i;
|
||||
if (Journal.compare(journals[min], journals[i]) > 0) min = i;
|
||||
*/!*
|
||||
}
|
||||
return journals[min];
|
||||
|
@ -154,7 +154,7 @@ alert( *!*Journal.formatDate(new Date)*/!* );
|
|||
```js
|
||||
//+ run
|
||||
var str = String.fromCharCode(65);
|
||||
alert(str); // 'A'
|
||||
alert( str ); // 'A'
|
||||
```
|
||||
|
||||
Но строки -- слишком простой пример, посмотрим что-нибудь посложнее.
|
||||
|
@ -165,15 +165,17 @@ alert(str); // 'A'
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function User(userData) {
|
||||
function User(userData) {
|
||||
if (userData) { // если указаны данные -- одна ветка if
|
||||
this.name = userData.name;
|
||||
this.age = userData.age;
|
||||
} else { // если не указаны -- другая
|
||||
} else { // если не указаны -- другая
|
||||
this.name = 'Аноним';
|
||||
}
|
||||
|
||||
this.sayHi = function() { alert(this.name) };
|
||||
this.sayHi = function() {
|
||||
alert(this.name)
|
||||
};
|
||||
// ...
|
||||
}
|
||||
|
||||
|
@ -182,7 +184,10 @@ function User(userData) {
|
|||
var guest = new User();
|
||||
guest.sayHi(); // Аноним
|
||||
|
||||
var knownUser = new User({name: 'Вася', age: 25});
|
||||
var knownUser = new User({
|
||||
name: 'Вася',
|
||||
age: 25
|
||||
});
|
||||
knownUser.sayHi(); // Вася
|
||||
```
|
||||
|
||||
|
@ -192,8 +197,10 @@ knownUser.sayHi(); // Вася
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function User() {
|
||||
this.sayHi = function() { alert(this.name) };
|
||||
function User() {
|
||||
this.sayHi = function() {
|
||||
alert(this.name)
|
||||
};
|
||||
}
|
||||
|
||||
User.createAnonymous = function() {
|
||||
|
@ -215,7 +222,10 @@ User.createFromData = function(userData) {
|
|||
var guest = User.createAnonymous();
|
||||
guest.sayHi(); // Аноним
|
||||
|
||||
var knownUser = User.createFromData({name: 'Вася', age: 25});
|
||||
var knownUser = User.createFromData({
|
||||
name: 'Вася',
|
||||
age: 25
|
||||
});
|
||||
knownUser.sayHi(); // Вася
|
||||
*/!*
|
||||
```
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
function sumArgs() {
|
||||
// скопируем reduce из массива
|
||||
arguments.reduce = [].reduce;
|
||||
return arguments.reduce(function(a, b) {
|
||||
return arguments.reduce(function(a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
|
||||
alert( sumArgs(4,5,6) ); // 15
|
||||
alert( sumArgs(4, 5, 6) ); // 15
|
||||
```
|
||||
|
||||
# Второй вариант
|
||||
|
@ -21,11 +21,11 @@ alert( sumArgs(4,5,6) ); // 15
|
|||
//+ run
|
||||
function sumArgs() {
|
||||
// запустим reduce из массива напрямую
|
||||
return [].reduce.call(arguments, function(a, b) {
|
||||
return a + b;
|
||||
return [].reduce.call(arguments, function(a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
|
||||
alert( sumArgs(4,5,6) ); // 15
|
||||
alert( sumArgs(4, 5, 6) ); // 15
|
||||
```
|
||||
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
```js
|
||||
//+ run
|
||||
function sum(arr) {
|
||||
return arr.reduce(function(a, b) { return a + b; });
|
||||
return arr.reduce(function(a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
|
||||
alert( sum([1,2,3]) ); // 6 (=1+2+3)
|
||||
alert( sum([1, 2, 3]) ); // 6 (=1+2+3)
|
||||
```
|
||||
|
||||
Создайте аналогичную функцию `sumArgs()`, которая будет суммировать все свои аргументы:
|
||||
|
@ -20,7 +22,7 @@ function sumArgs() {
|
|||
/* ваш код */
|
||||
}
|
||||
|
||||
alert( sumArgs(1,2,3) ); // 6, аргументы переданы через запятую, без массива
|
||||
alert( sumArgs(1, 2, 3) ); // 6, аргументы переданы через запятую, без массива
|
||||
```
|
||||
|
||||
Для решения примените метод `reduce` к `arguments`, используя `call`, `apply` или одалживание метода.
|
||||
|
|
|
@ -3,16 +3,21 @@
|
|||
```js
|
||||
//+ run
|
||||
function sum() {
|
||||
return [].reduce.call(arguments, function(a, b) { return a + b; });
|
||||
return [].reduce.call(arguments, function(a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
|
||||
function mul() {
|
||||
return [].reduce.call(arguments, function(a, b) { return a * b; });
|
||||
return [].reduce.call(arguments, function(a, b) {
|
||||
return a * b;
|
||||
});
|
||||
}
|
||||
|
||||
*!*
|
||||
function applyAll(func) {
|
||||
return func.apply(this, [].slice.call(arguments, 1) );
|
||||
}
|
||||
return func.apply(this, [].slice.call(arguments, 1));
|
||||
}
|
||||
*/!*
|
||||
|
||||
alert( applyAll(sum, 1, 2, 3) ); // 6
|
||||
|
|
|
@ -21,10 +21,15 @@ alert( applyAll(Math.min, 2, -2, 3) ); // -2
|
|||
```js
|
||||
//+ run
|
||||
function sum() { // суммирует аргументы: sum(1,2,3) = 6
|
||||
return [].reduce.call(arguments, function(a, b) { return a + b; });
|
||||
return [].reduce.call(arguments, function(a, b) {
|
||||
return a + b;
|
||||
});
|
||||
}
|
||||
|
||||
function mul() { // перемножает аргументы: mul(2,3,4) = 24
|
||||
return [].reduce.call(arguments, function(a, b) { return a * b; });
|
||||
return [].reduce.call(arguments, function(a, b) {
|
||||
return a * b;
|
||||
});
|
||||
}
|
||||
|
||||
*!*
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
Синтаксис метода `call`:
|
||||
|
||||
```js
|
||||
func.call(context, arg1, arg2,...)
|
||||
func.call(context, arg1, arg2, ...)
|
||||
```
|
||||
|
||||
При этом вызывается функция `func`, первый аргумент `call` становится её `this`, а остальные передаются "как есть".
|
||||
|
@ -21,7 +21,7 @@ func.call(context, arg1, arg2,...)
|
|||
Например, у нас есть функция `showFullName`, которая работает с `this`:
|
||||
|
||||
```js
|
||||
function showFullName() {
|
||||
function showFullName() {
|
||||
alert( this.firstName + " " + this.lastName );
|
||||
}
|
||||
```
|
||||
|
@ -32,18 +32,18 @@ function showFullName() {
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function showFullName() {
|
||||
function showFullName() {
|
||||
alert( this.firstName + " " + this.lastName );
|
||||
}
|
||||
|
||||
var user = {
|
||||
var user = {
|
||||
firstName: "Василий",
|
||||
lastName: "Петров"
|
||||
};
|
||||
|
||||
*!*
|
||||
// функция вызовется с this=user
|
||||
showFullName.call(user) // "Василий Петров"
|
||||
showFullName.call(user) // "Василий Петров"
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -51,20 +51,20 @@ showFullName.call(user) // "Василий Петров"
|
|||
|
||||
```js
|
||||
//+ run
|
||||
var user = {
|
||||
var user = {
|
||||
firstName: "Василий",
|
||||
surname: "Петров",
|
||||
patronym: "Иванович"
|
||||
};
|
||||
|
||||
function showFullName(firstPart, lastPart) {
|
||||
function showFullName(firstPart, lastPart) {
|
||||
alert( this[firstPart] + " " + this[lastPart] );
|
||||
}
|
||||
|
||||
*!*
|
||||
// f.call(контекст, аргумент1, аргумент2, ...)
|
||||
showFullName.call(user, 'firstName', 'surname') // "Василий Петров"
|
||||
showFullName.call(user, 'firstName', 'patronym') // "Василий Иванович"
|
||||
showFullName.call(user, 'firstName', 'surname') // "Василий Петров"
|
||||
showFullName.call(user, 'firstName', 'patronym') // "Василий Иванович"
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -85,9 +85,9 @@ showFullName.call(user, 'firstName', 'patronym') // "Василий Ивано
|
|||
function printArgs() {
|
||||
arguments.join = [].join; // одолжили метод (1)
|
||||
|
||||
var argStr = arguments.join(':'); // (2)
|
||||
var argStr = arguments.join(':'); // (2)
|
||||
|
||||
alert(argStr); // сработает и выведет 1:2:3
|
||||
alert( argStr ); // сработает и выведет 1:2:3
|
||||
}
|
||||
|
||||
printArgs(1, 2, 3);
|
||||
|
@ -107,12 +107,12 @@ printArgs(1, 2, 3);
|
|||
function join(separator) {
|
||||
if (!this.length) return '';
|
||||
|
||||
var str = this[0];
|
||||
var str = this[0];
|
||||
|
||||
for (var i = 1; i<this.length; i++) {
|
||||
str += separator + this[i];
|
||||
for (var i = 1; i < this.length; i++) {
|
||||
str += separator + this[i];
|
||||
}
|
||||
|
||||
|
||||
return str;
|
||||
}
|
||||
```
|
||||
|
@ -123,9 +123,9 @@ function join(separator) {
|
|||
|
||||
```js
|
||||
//+ run
|
||||
var obj = { // обычный объект с числовыми индексами и length
|
||||
0: "А",
|
||||
1: "Б",
|
||||
var obj = { // обычный объект с числовыми индексами и length
|
||||
0: "А",
|
||||
1: "Б",
|
||||
2: "В",
|
||||
length: 3
|
||||
};
|
||||
|
@ -154,10 +154,10 @@ function printArgs() {
|
|||
*!*
|
||||
// вызовем join с this=arguments,
|
||||
// этот вызов эквивалентен arguments.join(':') из примера выше
|
||||
var argStr = join.call(arguments, ':');
|
||||
var argStr = join.call(arguments, ':');
|
||||
*/!*
|
||||
|
||||
alert(argStr); // сработает и выведет 1:2:3
|
||||
alert( argStr ); // сработает и выведет 1:2:3
|
||||
}
|
||||
|
||||
printArgs(1, 2, 3);
|
||||
|
@ -195,7 +195,7 @@ printArgs('Привет', 'мой', 'мир'); // Привет, мой, мир
|
|||
**Вызов функции при помощи `func.apply` работает аналогично `func.call`, но принимает массив аргументов вместо списка.**
|
||||
|
||||
```js
|
||||
func.call(context, arg1, arg2)
|
||||
func.call(context, arg1, arg2);
|
||||
// идентичен вызову
|
||||
func.apply(context, [arg1, arg2]);
|
||||
```
|
||||
|
@ -203,7 +203,7 @@ func.apply(context, [arg1, arg2]);
|
|||
В частности, эти две строчки cработают одинаково:
|
||||
|
||||
```js
|
||||
showFullName.call(user, 'firstName', 'surname');
|
||||
showFullName.call(user, 'firstName', 'surname');
|
||||
|
||||
showFullName.apply(user, ['firstName', 'surname']);
|
||||
```
|
||||
|
@ -243,10 +243,10 @@ alert( Math.max.apply(null, arr) ); // 5
|
|||
Современный стандарт:
|
||||
```js
|
||||
//+ run
|
||||
function f() {
|
||||
function f() {
|
||||
"use strict";
|
||||
*!*
|
||||
alert(this); // null
|
||||
alert( this ); // null
|
||||
*/!*
|
||||
}
|
||||
|
||||
|
@ -257,11 +257,11 @@ f.call(null);
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function f() {
|
||||
alert(this); // window
|
||||
function f() {
|
||||
alert( this ); // window
|
||||
}
|
||||
|
||||
f.call(null);
|
||||
f.call(null);
|
||||
```
|
||||
|
||||
[/smart]
|
||||
|
@ -275,6 +275,7 @@ f.call(null);
|
|||
<dd>
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
obj.func(...) // this = obj
|
||||
obj["func"](...)
|
||||
```
|
||||
|
@ -284,7 +285,7 @@ obj["func"](...)
|
|||
<dd>
|
||||
|
||||
```js
|
||||
func(...) // this = window (ES3) /undefined (ES5)
|
||||
func(...) // this = window (ES3) /undefined (ES5)
|
||||
```
|
||||
|
||||
</dd>
|
||||
|
@ -292,7 +293,7 @@ func(...) // this = window (ES3) /undefined (ES5)
|
|||
<dd>
|
||||
|
||||
```js
|
||||
new func() // this = {} (новый объект)
|
||||
new func() // this = {} (новый объект)
|
||||
```
|
||||
|
||||
</dd>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
Если вы вдруг захотите копнуть поглубже -- аналог `bind` для IE8- и старых версий других браузеров будет выглядеть следующим образом:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function bind(func, context /*, args*/) {
|
||||
var bindArgs = [].slice.call(arguments, 2); // (1)
|
||||
function wrapper() { // (2)
|
||||
|
|
|
@ -9,7 +9,7 @@ function f() {
|
|||
var user = {
|
||||
g: f.bind("Hello")
|
||||
}
|
||||
|
||||
|
||||
user.g();
|
||||
```
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ function f() {
|
|||
var user = {
|
||||
g: f.bind("Hello")
|
||||
}
|
||||
|
||||
|
||||
user.g();
|
||||
```
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Ответ: `"Вася"`.
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
function f() {
|
||||
alert(this.name);
|
||||
}
|
||||
|
@ -19,8 +19,8 @@ f(); // Вася
|
|||
|
||||
```js
|
||||
function bind(func, context) {
|
||||
return function() {
|
||||
return func.apply(context, arguments);
|
||||
return function() {
|
||||
return func.apply(context, arguments);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
@ -28,6 +28,7 @@ function bind(func, context) {
|
|||
Код станет таким:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function f() {
|
||||
alert(this.name);
|
||||
}
|
||||
|
@ -43,8 +44,8 @@ f(); // Вася
|
|||
```js
|
||||
function bind(func, context) {
|
||||
*!*
|
||||
return function() {
|
||||
return func.apply(context, arguments);
|
||||
return function() {
|
||||
return func.apply(context, arguments);
|
||||
};
|
||||
*/!*
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
Что выведет этот код?
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function f() {
|
||||
alert(this.name);
|
||||
}
|
||||
|
|
|
@ -5,16 +5,18 @@
|
|||
В свойство функции записано значение. Изменится ли оно после применения `bind`? Обоснуйте ответ.
|
||||
|
||||
```js
|
||||
function sayHi() {
|
||||
alert(this.name);
|
||||
function sayHi() {
|
||||
alert( this.name );
|
||||
}
|
||||
sayHi.test = 5;
|
||||
alert(sayHi.test); // 5
|
||||
alert( sayHi.test ); // 5
|
||||
|
||||
*!*
|
||||
var bound = sayHi.bind({ name: "Вася" });
|
||||
var bound = sayHi.bind({
|
||||
name: "Вася"
|
||||
});
|
||||
|
||||
alert(bound.test); // что выведет? почему?
|
||||
alert( bound.test ); // что выведет? почему?
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@ var user = {
|
|||
password: '12345',
|
||||
|
||||
loginOk: function() {
|
||||
alert(this.login + ' вошёл в сайт');
|
||||
alert( this.login + ' вошёл в сайт' );
|
||||
},
|
||||
|
||||
loginFail: function() {
|
||||
alert(this.login + ': ошибка входа');
|
||||
alert( this.login + ': ошибка входа' );
|
||||
},
|
||||
|
||||
checkPassword: function() {
|
||||
|
@ -43,6 +43,7 @@ vasya.checkPassword();
|
|||
Альтернативное решение -- сделать функции-обёртки над `user.loginOk/loginFail`:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
var user = {
|
||||
...
|
||||
checkPassword: function() {
|
||||
|
@ -79,19 +80,23 @@ var user = {
|
|||
password: '12345',
|
||||
|
||||
loginOk: function() {
|
||||
alert(this.login + ' вошёл в сайт');
|
||||
alert( this.login + ' вошёл в сайт' );
|
||||
},
|
||||
|
||||
loginFail: function() {
|
||||
alert(this.login + ': ошибка входа');
|
||||
alert( this.login + ': ошибка входа' );
|
||||
},
|
||||
|
||||
checkPassword: function() {
|
||||
*!*
|
||||
var self = this;
|
||||
ask("Ваш пароль?", this.password,
|
||||
function() { self.loginOk(); },
|
||||
function() { self.loginFail(); }
|
||||
ask("Ваш пароль?", this.password,
|
||||
function() {
|
||||
self.loginOk();
|
||||
},
|
||||
function() {
|
||||
self.loginFail();
|
||||
}
|
||||
);
|
||||
*/!*
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ var user = {
|
|||
password: '12345',
|
||||
|
||||
loginOk: function() {
|
||||
alert(this.login + ' вошёл в сайт');
|
||||
alert( this.login + ' вошёл в сайт' );
|
||||
},
|
||||
|
||||
loginFail: function() {
|
||||
alert(this.login + ': ошибка входа');
|
||||
alert( this.login + ': ошибка входа' );
|
||||
},
|
||||
|
||||
checkPassword: function() {
|
||||
|
|
|
@ -17,7 +17,7 @@ var user = {
|
|||
password: '12345',
|
||||
|
||||
loginDone: function(result) {
|
||||
alert(this.login + (result ? ' вошёл в сайт' : ' ошибка входа'));
|
||||
alert( this.login + (result ? ' вошёл в сайт' : ' ошибка входа') );
|
||||
},
|
||||
|
||||
checkPassword: function() {
|
||||
|
@ -49,15 +49,19 @@ var user = {
|
|||
password: '12345',
|
||||
|
||||
loginDone: function(result) {
|
||||
alert(this.login + (result ? ' вошёл в сайт' : ' ошибка входа'));
|
||||
alert( this.login + (result ? ' вошёл в сайт' : ' ошибка входа') );
|
||||
},
|
||||
|
||||
checkPassword: function() {
|
||||
var self = this;
|
||||
*!*
|
||||
ask("Ваш пароль?", this.password,
|
||||
function() { self.loginDone(true); },
|
||||
function() { self.loginDone(false); }
|
||||
function() {
|
||||
self.loginDone(true);
|
||||
},
|
||||
function() {
|
||||
self.loginDone(false);
|
||||
}
|
||||
);
|
||||
*/!*
|
||||
}
|
||||
|
|
|
@ -30,14 +30,18 @@ var user = {
|
|||
|
||||
// метод для вызова из ask
|
||||
loginDone: function(result) {
|
||||
alert(this.login + (result ? ' вошёл в сайт' : ' ошибка входа'));
|
||||
alert( this.login + (result ? ' вошёл в сайт' : ' ошибка входа') );
|
||||
},
|
||||
|
||||
checkPassword: function() {
|
||||
*!*
|
||||
ask("Ваш пароль?", this.password,
|
||||
function() { user.loginDone(true); },
|
||||
function() { user.loginDone(false); }
|
||||
ask("Ваш пароль?", this.password,
|
||||
function() {
|
||||
user.loginDone(true);
|
||||
},
|
||||
function() {
|
||||
user.loginDone(false);
|
||||
}
|
||||
);
|
||||
*/!*
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
```js
|
||||
//+ run
|
||||
setTimeout(function() {
|
||||
alert("Привет");
|
||||
alert( "Привет" );
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
|
@ -29,13 +29,13 @@ setTimeout(function() {
|
|||
//+ run
|
||||
var user = {
|
||||
firstName: "Вася",
|
||||
sayHi: function() {
|
||||
alert(this.firstName);
|
||||
sayHi: function() {
|
||||
alert( this.firstName );
|
||||
}
|
||||
};
|
||||
|
||||
*!*
|
||||
setTimeout( user.sayHi, 1000); // undefined (не Вася!)
|
||||
setTimeout(user.sayHi, 1000); // undefined (не Вася!)
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -61,15 +61,15 @@ setTimeout(f, 1000); // контекст user потеряли
|
|||
//+ run
|
||||
var user = {
|
||||
firstName: "Вася",
|
||||
sayHi: function() {
|
||||
alert(this.firstName);
|
||||
sayHi: function() {
|
||||
alert( this.firstName );
|
||||
}
|
||||
};
|
||||
|
||||
*!*
|
||||
setTimeout(function() {
|
||||
user.sayHi(); // Вася
|
||||
}, 1000);
|
||||
user.sayHi(); // Вася
|
||||
}, 1000);
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -82,15 +82,15 @@ setTimeout(function() {
|
|||
//+ run
|
||||
var user = {
|
||||
firstName: "Вася",
|
||||
sayHi: function(who) {
|
||||
alert(this.firstName + ": Привет, " + who);
|
||||
sayHi: function(who) {
|
||||
alert( this.firstName + ": Привет, " + who );
|
||||
}
|
||||
};
|
||||
|
||||
*!*
|
||||
setTimeout(function() {
|
||||
user.sayHi("Петя"); // Вася: Привет, Петя
|
||||
}, 1000);
|
||||
user.sayHi("Петя"); // Вася: Привет, Петя
|
||||
}, 1000);
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -108,7 +108,7 @@ setTimeout(function() {
|
|||
```js
|
||||
function bind(func, context) {
|
||||
return function() { // (*)
|
||||
return func.apply(context, arguments);
|
||||
return func.apply(context, arguments);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
@ -117,10 +117,12 @@ function bind(func, context) {
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function f() { alert(this); }
|
||||
function f() {
|
||||
alert( this );
|
||||
}
|
||||
|
||||
var g = bind(f, "Context");
|
||||
g(); // Context
|
||||
g(); // Context
|
||||
```
|
||||
|
||||
То есть, `bind(f, "Context")` привязывает `"Context"` в качестве `this` для `f`.
|
||||
|
@ -132,16 +134,16 @@ g(); // Context
|
|||
Вот она отдельно:
|
||||
|
||||
```js
|
||||
function() { // (*)
|
||||
return func.apply(context, arguments);
|
||||
function() { // (*)
|
||||
return func.apply(context, arguments);
|
||||
};
|
||||
```
|
||||
|
||||
Если подставить наши конкретные аргументы, то есть `f` и `"Context"`, то получится так:
|
||||
|
||||
```js
|
||||
function() { // (*)
|
||||
return f.apply("Context", arguments);
|
||||
function() { // (*)
|
||||
return f.apply("Context", arguments);
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -153,13 +155,13 @@ function() { // (*)
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function f(a, b) {
|
||||
alert(this);
|
||||
alert(a + b);
|
||||
function f(a, b) {
|
||||
alert( this );
|
||||
alert( a + b );
|
||||
}
|
||||
|
||||
var g = bind(f, "Context");
|
||||
g(1, 2); // Context, затем 3
|
||||
g(1, 2); // Context, затем 3
|
||||
```
|
||||
|
||||
Аргументы, которые получила `g(...)`, передаются в `f` также благодаря методу `.apply`.
|
||||
|
@ -171,20 +173,20 @@ g(1, 2); // Context, затем 3
|
|||
```js
|
||||
//+ run
|
||||
function bind(func, context) {
|
||||
return function() {
|
||||
return func.apply(context, arguments);
|
||||
return function() {
|
||||
return func.apply(context, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
var user = {
|
||||
firstName: "Вася",
|
||||
sayHi: function() {
|
||||
alert(this.firstName);
|
||||
alert( this.firstName );
|
||||
}
|
||||
};
|
||||
|
||||
*!*
|
||||
setTimeout( bind(user.sayHi, user), 1000 );
|
||||
setTimeout(bind(user.sayHi, user), 1000);
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -201,7 +203,7 @@ var user = {
|
|||
*!*
|
||||
sayHi: function(who) { // здесь у sayHi есть один аргумент
|
||||
*/!*
|
||||
alert(this.firstName + ": Привет, " + who);
|
||||
alert( this.firstName + ": Привет, " + who );
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -228,9 +230,9 @@ sayHi("Маша"); // Вася: Привет, Маша
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function f(a, b) {
|
||||
alert(this);
|
||||
alert(a + b);
|
||||
function f(a, b) {
|
||||
alert( this );
|
||||
alert( a + b );
|
||||
}
|
||||
|
||||
*!*
|
||||
|
@ -238,7 +240,7 @@ function f(a, b) {
|
|||
// var g = bind(f, "Context");
|
||||
var g = f.bind("Context");
|
||||
*/!*
|
||||
g(1, 2); // Context, затем 3
|
||||
g(1, 2); // Context, затем 3
|
||||
```
|
||||
|
||||
Синтаксис встроенного `bind`:
|
||||
|
@ -264,14 +266,14 @@ var wrapper = func.bind(context[, arg1, arg2...])
|
|||
//+ run
|
||||
var user = {
|
||||
firstName: "Вася",
|
||||
sayHi: function() {
|
||||
alert(this.firstName);
|
||||
sayHi: function() {
|
||||
alert( this.firstName );
|
||||
}
|
||||
};
|
||||
|
||||
*!*
|
||||
// setTimeout( bind(user.sayHi, user), 1000 );
|
||||
setTimeout( user.sayHi.bind(user), 1000 ); // аналог через встроенный метод
|
||||
setTimeout(user.sayHi.bind(user), 1000); // аналог через встроенный метод
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -291,7 +293,7 @@ setTimeout( user.sayHi.bind(user), 1000 ); // аналог через встро
|
|||
Если у объекта много методов и мы планируем их активно передавать, то можно привязать контекст для них всех в цикле:
|
||||
|
||||
```js
|
||||
for(var prop in user) {
|
||||
for (var prop in user) {
|
||||
if (typeof user[prop] == 'function') {
|
||||
user[prop] = user[prop].bind(user);
|
||||
}
|
||||
|
@ -327,9 +329,9 @@ function mul(a, b) {
|
|||
var double = mul.bind(null, 2); // контекст фиксируем null, он не используется
|
||||
*/!*
|
||||
|
||||
alert( double(3) ); // = mul(2, 3) = 6
|
||||
alert( double(4) ); // = mul(2, 4) = 8
|
||||
alert( double(5) ); // = mul(2, 5) = 10
|
||||
alert( double(3) ); // = mul(2, 3) = 6
|
||||
alert( double(4) ); // = mul(2, 4) = 8
|
||||
alert( double(5) ); // = mul(2, 5) = 10
|
||||
```
|
||||
|
||||
При вызове `double` будет передавать свои аргументы исходной функции `mul` после тех, которые указаны в `bind`, то есть в данном случае после зафиксированного первого аргумента `2`.
|
||||
|
@ -344,9 +346,9 @@ alert( double(5) ); // = mul(2, 5) = 10
|
|||
var triple = mul.bind(null, 3); // контекст фиксируем null, он не используется
|
||||
*/!*
|
||||
|
||||
alert( triple(3) ); // = mul(3, 3) = 9
|
||||
alert( triple(4) ); // = mul(3, 4) = 12
|
||||
alert( triple(5) ); // = mul(3, 5) = 15
|
||||
alert( triple(3) ); // = mul(3, 3) = 9
|
||||
alert( triple(4) ); // = mul(3, 4) = 12
|
||||
alert( triple(5) ); // = mul(3, 5) = 15
|
||||
```
|
||||
|
||||
При помощи `bind` мы можем получить из функции её "частный вариант" как самостоятельную функцию и дальше передать в `setTimeout` или сделать с ней что-то ещё.
|
||||
|
@ -377,12 +379,12 @@ function ask(question, answer, ok, fail) {
|
|||
ask("Выпустить птичку?", "да", fly, die);
|
||||
*/!*
|
||||
|
||||
function fly() {
|
||||
alert('улетела :)');
|
||||
function fly() {
|
||||
alert( 'улетела :)' );
|
||||
}
|
||||
|
||||
function die() {
|
||||
alert('птичку жалко :(');
|
||||
function die() {
|
||||
alert( 'птичку жалко :(' );
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -400,7 +402,7 @@ setTimeout(function() {
|
|||
<li>...Либо использовать `bind`:
|
||||
|
||||
```js
|
||||
setTimeout( obj.func.bind(obj) );
|
||||
setTimeout(obj.func.bind(obj));
|
||||
```
|
||||
</li>
|
||||
<li>Вызов `bind` часто используют для привязки функции к контексту, чтобы затем присвоить её в обычную переменную и вызывать уже без явного указания объекта.</li>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function work(a) {
|
||||
function work(a) {
|
||||
/*...*/ // work - произвольная функция, один аргумент
|
||||
}
|
||||
|
||||
|
@ -10,9 +10,9 @@ function makeLogging(f, log) {
|
|||
|
||||
*!*
|
||||
function wrapper(a) {
|
||||
log.push(a);
|
||||
return f.call(this, a);
|
||||
}
|
||||
log.push(a);
|
||||
return f.call(this, a);
|
||||
}
|
||||
*/!*
|
||||
|
||||
return wrapper;
|
||||
|
@ -24,7 +24,7 @@ work = makeLogging(work, log);
|
|||
work(1); // 1
|
||||
work(5); // 5
|
||||
|
||||
for(var i=0; i<log.length; i++) {
|
||||
for (var i = 0; i < log.length; i++) {
|
||||
alert( 'Лог:' + log[i] ); // "Лог:1", затем "Лог:5"
|
||||
}
|
||||
```
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
Работать должно так:
|
||||
|
||||
```js
|
||||
function work(a) {
|
||||
function work(a) {
|
||||
/* ... */ // work - произвольная функция, один аргумент
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ work = makeLogging(work, log);
|
|||
work(1); // 1, добавлено в log
|
||||
work(5); // 5, добавлено в log
|
||||
|
||||
for(var i=0; i<log.length; i++) {
|
||||
for (var i = 0; i < log.length; i++) {
|
||||
*!*
|
||||
alert( 'Лог:' + log[i] ); // "Лог:1", затем "Лог:5"
|
||||
*/!*
|
||||
|
|
|
@ -4,17 +4,17 @@
|
|||
|
||||
```js
|
||||
//+ run
|
||||
function work(a, b) {
|
||||
alert(a + b); // work - произвольная функция
|
||||
function work(a, b) {
|
||||
alert( a + b ); // work - произвольная функция
|
||||
}
|
||||
|
||||
function makeLogging(f, log) {
|
||||
|
||||
|
||||
*!*
|
||||
function wrapper() {
|
||||
log.push([].slice.call(arguments));
|
||||
return f.apply(this, arguments);
|
||||
}
|
||||
log.push([].slice.call(arguments));
|
||||
return f.apply(this, arguments);
|
||||
}
|
||||
*/!*
|
||||
|
||||
return wrapper;
|
||||
|
@ -26,7 +26,7 @@ work = makeLogging(work, log);
|
|||
work(1, 2); // 3
|
||||
work(4, 5); // 9
|
||||
|
||||
for(var i=0; i<log.length; i++) {
|
||||
for (var i = 0; i < log.length; i++) {
|
||||
var args = log[i]; // массив из аргументов i-го вызова
|
||||
alert( 'Лог:' + args.join() ); // "Лог:1,2", "Лог:4,5"
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
Работать должно так:
|
||||
|
||||
```js
|
||||
function work(a, b) {
|
||||
alert(a + b); // work - произвольная функция
|
||||
function work(a, b) {
|
||||
alert( a + b ); // work - произвольная функция
|
||||
}
|
||||
|
||||
function makeLogging(f, log) { /* ваш код */ }
|
||||
|
@ -21,7 +21,7 @@ work = makeLogging(work, log);
|
|||
work(1, 2); // 3
|
||||
work(4, 5); // 9
|
||||
|
||||
for(var i=0; i<log.length; i++) {
|
||||
for (var i = 0; i < log.length; i++) {
|
||||
var args = log[i]; // массив из аргументов i-го вызова
|
||||
alert( 'Лог:' + args.join() ); // "Лог:1,2", "Лог:4,5"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Запоминать результаты вызова функции будем в замыкании, в объекте `cache: { ключ:значение }`.
|
||||
|
||||
```js
|
||||
//+ run
|
||||
//+ run no-beautify
|
||||
function f(x) {
|
||||
return Math.random()*x;
|
||||
}
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
Должно работать так:
|
||||
|
||||
```js
|
||||
function f(x) {
|
||||
return Math.random()*x; // random для удобства тестирования
|
||||
function f(x) {
|
||||
return Math.random() * x; // random для удобства тестирования
|
||||
}
|
||||
|
||||
function makeCaching(f) { /* ваш код */ }
|
||||
|
|
|
@ -16,8 +16,8 @@ JavaScript предоставляет удивительно гибкие воз
|
|||
|
||||
```js
|
||||
function bind(func, context) {
|
||||
return function() {
|
||||
return func.apply(context, arguments);
|
||||
return function() {
|
||||
return func.apply(context, arguments);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
@ -32,7 +32,7 @@ function bind(func, context) {
|
|||
|
||||
Использование:
|
||||
```js
|
||||
function f(x) { } // любая функция
|
||||
function f(x) {} // любая функция
|
||||
|
||||
var timers = {}; // объект для таймеров
|
||||
|
||||
|
@ -44,7 +44,7 @@ f(1);
|
|||
f(2);
|
||||
f(3); // функция работает как раньше, но время подсчитывается
|
||||
|
||||
alert(timers.myFunc); // общее время выполнения всех вызовов f
|
||||
alert( timers.myFunc ); // общее время выполнения всех вызовов f
|
||||
```
|
||||
|
||||
При помощи декоратора `timingDecorator` мы сможем взять произвольную функцию и одним движением руки прикрутить к ней измеритель времени.
|
||||
|
@ -71,7 +71,7 @@ function timingDecorator(f, timer) {
|
|||
|
||||
// функция может быть произвольной, например такой:
|
||||
function fibonacci(n) {
|
||||
return (n > 2) ? fibonacci(n-1) + fibonacci(n-2) : 1;
|
||||
return (n > 2) ? fibonacci(n - 1) + fibonacci(n - 2) : 1;
|
||||
}
|
||||
|
||||
*!*
|
||||
|
@ -86,7 +86,7 @@ alert( fibonacci(20) ); // 6765
|
|||
|
||||
*!*
|
||||
// в любой момент можно получить общее количество времени на вызовы
|
||||
alert( timers.fibo + 'мс' );
|
||||
alert( timers.fibo + 'мс' );
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
@ -105,6 +105,7 @@ var result = f.apply(this, arguments); // (*)
|
|||
Например:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function sum(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
@ -134,9 +135,9 @@ function checkNumber(value) {
|
|||
// второй аргумент checks - массив с функциями для проверки
|
||||
function typeCheck(f, checks) {
|
||||
return function() {
|
||||
for(var i=0; i<arguments.length; i++) {
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
if (!checks[i](arguments[i])) {
|
||||
alert("Некорректный тип аргумента номер " + i);
|
||||
alert( "Некорректный тип аргумента номер " + i );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +155,7 @@ sum = typeCheck(sum, [checkNumber, checkNumber]); // оба аргумента -
|
|||
*/!*
|
||||
|
||||
// пользуемся функцией как обычно
|
||||
alert( sum(1,2 ) ); // 3, все хорошо
|
||||
alert( sum(1, 2) ); // 3, все хорошо
|
||||
|
||||
*!*
|
||||
// а вот так - будет ошибка
|
||||
|
@ -180,10 +181,10 @@ sum(1, ["array", "in", "sum?!?"]); // некорректный аргумент
|
|||
```js
|
||||
function checkPermissionDecorator(f) {
|
||||
return function() {
|
||||
if ( isAdmin() ) {
|
||||
return f.apply(this, arguments);
|
||||
if (isAdmin()) {
|
||||
return f.apply(this, arguments);
|
||||
}
|
||||
alert('Недостаточно прав');
|
||||
alert( 'Недостаточно прав' );
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -191,6 +192,7 @@ function checkPermissionDecorator(f) {
|
|||
Использование декоратора:
|
||||
|
||||
```js
|
||||
//+ no-beautify
|
||||
function save() { ... }
|
||||
|
||||
save = checkPermissionDecorator(save);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue