JavaScript для продвинутых методическое пособие Минск 2016


Задача: Функция должна принимать два значения. Первый - число, второе – функция, циклично вызывающаяся с параметрами от 0 до числа первого параметра функции



страница4/5
Дата09.11.2016
Размер4.67 Mb.
Просмотров1240
Скачиваний0
1   2   3   4   5

Задача: Функция должна принимать два значения. Первый - число, второе – функция, циклично вызывающаяся с параметрами от 0 до числа первого параметра функции

Решим эту задачу используя функции высшего порядка.


Реализация функции высшего порядка. Листинг 2.15

function buildString(n, callback){

var result = ‘’;

for(var i=0; i
result += callback(i);

}

return result;



}

var digits = buildString(10, function(i){

return i;

});


Такой подход называют абстракцией высшего порядка.

2.6 Косвенный вызов, методы call() и apply()

Методы call() и apply() позволяют выполнить косвенный вызов функции, как если бы она была методом другого объекта. Первым параметром ободим методам передается объект, относительно которого вызывается функция, этот аргумент определяет ключевое слово this в теле функции.

Чтобы вызвать функцию без аргументов, ка метод объекта o, можно использовать любой из методов: call() или apply().


Косвенный вызов функций через методы call() и apply(). Листинг 2.16

f.call(o);

f.apply(o);



call()

Метод call может применяться для вызова функции в контексте нужного объекта:



Вызов sayName в контексте разных объектов. Листинг 2.17

var Animal1 = {name: 'Cat'}

var Animal2 = {name: 'Dog'}


function sayName() {

// this — ссылка на объект, в контексте которого вызвана функция

alert(this.name);

}
sayName.call(Animal1) // выдаст сообщение "Cat"

sayName.call(Animal2) // выдаст сообщение "Dog"


При этом совершенно не важно, какому объекту принадлежит функция. В качестве текущего(this) объекта будет взят первый аргумент.

Вызов sayName, как метода объекта в контексте разных объектов. Листинг 2.18

var Animal1 = {

name: 'Cat',



sayName: function() {

alert(this.name);



}

};
var Animal2 = {name: 'Dog'};


Animal1.sayName() // выдаст сообщение "Cat"

Animal1.sayName.call(Animal2) // выдаст сообщение "Dog"



Помимо смены контекста вызова, метод call может передавать в функцию аргументы:

Вызов функции с аргументами. Листинг 2.19

var obj = {attr: 10};
function sum(a, b) {

alert(this.attr + a + b);

}
sum.call(obj, 5, 2) // выдаст сообщение с результатом "17"


Если контекст вызова не указан, то функция будет выполнятся в контексте заданного объекта:

Выполнение функции в контексте заданного объекта. Листинг 2.20

window.a = 5

function sayThis() {

alert(this.a);

}
sayThis.call() // выдаст 5


window.a = 5

function sayThis(b) {

alert(this.a + b);

}
sayThis.call(null, 3) // выдаст 8



apply()

Метод apply() действует точно также, как метод call(), за исключением того, что apply() аргументы для функции передает ввиде элементов массива:



Передача аргументов функции методом apply(). Листинг 2.21

f.apply(o,1,2);

Метод apply() получает массив аргументов и вызывает функцию, как будто каждый элемент массива является отдельным аргурментом вызова функции. Поэтому он полезен для вызова вариативных (с неизвестным количеством аргументов) функций с вычисляемым массивом аргументов.

Кроме массива аргументов, метод apply получает первый аргрумент, указывающий на вариант связывания this для вызываемой функции. Если функция не ссылается на this, ей можно передать null.



Вызов функции не ссылающейся на this. Листинг 2.22

var score = [0,1,2]

average.apply(null, score);

// это будет равносильно вызову average(score[0], score[1], score[2])


Если функция ссылается на this, то необходимо вместо null указать объект, в котором находятся ссылки this.

Вызов функции ссылающейся на this. Листинг 2.23

var obj = {}

var scor = [0,1,2]

average.apply(obj, score);

// это будет равносильно вызову: {obj.average(scor[0],scor[1],scor[2])



Т.е. функция average превратилась в метод объекта obj.

Еще один пример использования apply():



Суммирование элементов массива. Листинг 2.24

var test = [1,7,2,20];

alert(sum.apply(null, test)); //выведет 30



2.7 Аргументы функций

Список аргументов можно получить с помощью свойства arguments.



Arguments как массив. Листинг 2.25

function f(x) {

print(x); // Выводит начальное значение аргумента

arguments[0] = null; // Изменяя элементы массива, мы изменяем x

print(x); // Теперь выводит "null"

}


Если число аргументов в функции превышает число имен параметров при вызове, функция не может напрямую обращаться к неименованным значениям. Однако, ко всем параметрам функции мы можем обращаться через свойство arguments. Благодаря этому свойству имеется возможность создавать функции с переменным числом аргументов.

Вариативная функция. Листинг 2.26

function average(){

for(var i=0, sum=0, n=arguments.length; i

sum += arguments[i];

}

return sum/n;



}

Эта функция проходит циклический перебор каждого элемента объекта arguments и возвращает их среднеарифметическое значение.

2.8 Замыкания

В javaScript используются лексические области видимости. Это означает, что при выполнении функций действуют области видимости переменных, которые имелись на момент их определения, а не на момент вызова.



Реализация замыканий. Листинг 2.27

var scope = “global”;

function check(){

var scope = “local”;

function f(){return scope}

return f;

}

check()(); // вернет “local”



Рассмотрим следующий пример преобразования замыканий.

Счетчик. Листинг 2.28

function counter(){

var n = 0;

return {

count: function(){return n++;}

reset: function(){n=0;}

};

}



var c = counter(), d = counter; // создать два счетчика

c.count(); // вернет 0

d.cound(); // вернет 0

c.reset(); // обнуление, вернет 0


c.count(); // вернет 0

d.count(); // вернет 1



Чтобы понять суть замыканий, требуется знать три основных факта:

1. JavaScript позволяет ссылаться на переменные, определенные за пределами текущей функции:



- ссылка на переменные определенные за пределами текущей функции.

2. Функции могут ссылаться на переменные, определенные во внешних функциях. Функции, отслеживающие переменные, в содержащих эти переменные областях видимости, и называются замыканиями.



- можно возвращать внутреннюю функцию для его последующего вызова. Функция make() является замыканием, код которого ссылается на две внешние переменные: magic и filling. Функция может ссылаться на люые переменные в своей области видимости.

Этим можно воспользоваться для создания более универсальной функции main()



Универсальная функция main() использующая механизм замыканий. Листинг 2.29

function main(magic){

function make(filling){

return magic + " и " + filling;

}

return make;



}

var f = main("овощи");

f("фрукты"); //овощи и фрукты

f("огород"); //овощи и огород

var f = main("кофе");

f("чай"); //кофе и чай

f("молоко"); //кофе и молоко


3. Замыкания хранят внутри себя ссылки на внешние переменные, они способны как читать, так и обновлять эти свои переменные.

Функция box(), значения которого могут быть считаны и обновлены. Листинг 2.30

function box(){

var val = undefined;

return {

set: function(newVal){val = newVal;},

get: function(){return val;},

type: function(){return typeof val;}

};

}

var b = box();



b.type(); //undefined

b.set(98.6)

b.get(); // 98.6

b.type(); // "number"



В этом примере создается объект, в котором содержится три замыкания – это его свойства: set (определение или переопределение переменной), get (вернуть переменную), type (определить тип переменной)

2.9 Подъем переменной

Объявленные переменные внутри блока неявно поднимаются на вершину той функции, в которую они заключены.



Визуальное представление подъема переменной. Листинг 2.31

function f(){

//…


//…

{

var x = /* … */



}

}

// JavaScript неявно поднимает объявление переменных на вершину охватывающей функции. Т.е. JavaScript “видит” следующую функцию:



function f(){

var x;

//…


//…

{

var x = /* … */



}

}





Вывод: Во избежание путаницы, необходимо объявлять переменные, даже если их значение еще не извесно, в начале функции. Причем, при определении таких переменных, заранее указываем тип ожидаемой переменной:

Переменная x является элементом массива. Листинг 2.32

function f(){



var x = [];

//…


//…

{

var x = /* … */



}

}





2.10 Немедленно вызываемые функции-выражения

Замыкания хранят свои внешние переменные ввиде ссылок, а не в виде значений.



Задача: Передать в функцию массив. Функция должна вернуть значение того элемента, индекс которого получила вместе с массивом.

Для решения этой задачи воспользуемся приемом, известным как немедленный вызов функции выражения:



Создание вложенной функции с ее немедленным вызовом. Листинг 2.33

function wrap(a){

var result = [];

for (var i=0, n=a.length; i
(function(){

var j = i;

result[i] = function(){ return a[j];};

}

)();

}

return result;



}

var wrapped = wrap([10,20,30]);

var f = wrapped[1];

f(); // 20



2.11 Метод bind()

Объекты функций могут поставляться вместе с методом bind(), который принимает объект получатель и создает функцию оболочку, вызывающую исходную функцию в качестве метода получателя.

Представим себе объект строкового буфера, хронящий строки в массиве.


Использование bind() с объектом. Листинг 2.34

var buffer = {

entries: [],

add: function(s){

this.entries.push(s);

}

}



var source = ["375", "-", "123456"];

source.forEach(buffer.add.bind(buffer));

console.log(buffer.entries);


Причем, buffer.add.bind(buffer) не преобразовывает функцию buffer.add, а создает новую. Парметр buffer является объектом-получателем с сылкой на this.

Лаконичный пример использования bind:



Лаконичный пример использования bind(). Листинг 2.35

function f() {

alert(this.name);

}

var user = { name: "Вася" };



var f2 = f.bind(user);

f2(); // выполнит f с this.name = “Вася”




Задача. Имеется функция, ссылающаяся на this, и производит с ссылкой на this простые арифметические действия. И объект с числом (числами). Необходимо вызвать функцию методом данного объекта.

Преобразование функции в метод с помощью bind(). Листинг 2.36

function x(y) {

return this.x + y

}

var o = {x:1};



var g = x.bind(o);

g(2);


Как видно из листинга, метод bind() полезен для связывания методов с получателями.

Однако существует еще один не менее полезный трюк использования bind().



Использование метода bind() для каррирования функций. Методика связывания функций с подмножеством ее аргументов известна как каррирование. Если часть атрибутов функции постоянные для каждой итерации, то это верная причина использования каррирования.

Каррирование функции. Листинг 2.37

function simpleURL(protocol, domain, path){

return protocol + "://" + domain + "/" + path;

}

var paths = ["about", "12"];



var url = paths.map(simpleURL.bind(null, "http", "obmenka.by"));

console.log(url)



Первый метода bind() предоставляет значение получателя. Поскольку в simpleURL нет ссылки на this, используем null.

Каталог: media
media -> Литература Ссылка для цитирования
media -> Буланов С. В. Кудрявцева Е. Л. Развитие креативности билингвов: путь от интеркультурности к формированию «человека мира»
media -> Условия и процесс формирования международной конкурентоспособности национальной экономики
media -> Имени М. В. Ломоносова Биологический факультет
media -> Интернет! Актуальность
media -> Образовательная программа «Гражданское население в противодействии распространению идеологии терроризма»
media -> Планета «периодика» Мурзилка
media -> Система рейтинга сайтов


Поделитесь с Вашими друзьями:
1   2   3   4   5


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал