rozdział: Funkcje
==================
// Tworzymy zmienną add i zapisujemy w niej funkcję
// dodającą do siebie dwie liczby.
var add = function (a, b) {
   return a + b;
};
    
    
====================================
// Tworzymy obiekt myObject. Ma on właściwość value oraz 
// metodę increment. Metoda increment pobiera opcjonalny
// parametr. Jeśli argument nie jest liczbą, wówczas
// używana jest domyślna wartość 1.

var myObject = {
   value: 0,
   increment: function (inc) {
      this.value += typeof inc === 'number' ? inc : 1;
   }
};

myObject.increment();
document.writeln(myObject.value);  // 1

myObject.increment(2);
document.writeln(myObject.value);  // 3
    
    
====================================
var sum = add(3, 4);  // suma wynosi 7
    
    
====================================
//Rozszerzamy obiekt myObject o metodę double.

myObject.double = function () {
   var that = this;    // obejście problemu
   
   var helper = function () {
      that.value = add(that.value, that.value);
   };
   
   helper();   // wywołujemy helper jako funkcję
};

// wywołujemy double jako metodę

myObject.double();
document.writeln(myObject.value);  // 6
    
    
====================================
// Tworzymy konstruktor o nazwie Quo.
// Konstruuje on obiekt posiadający właściwość status.

var Quo = function (string) {
   this.status = string;
};

// Dodajemy wszystkim instancjom Quo metodę publiczną get_status.

Quo.prototype.get_status = function () {
   return this.status;
};

// Tworzymy instancję Quo.

var myQuo = new Quo("zdezorientowany");

document.writeln(myQuo.get_status());  // zdezorientowany
    
    
====================================
// Tworzymy tablicę dwóch liczb i dodajemy je do siebie

var array = [3, 4];
var sum = add.apply(null, array);  // suma wynosi 7

// Tworzymy obiekt posiadający właściwość status

var statusObject = {
   status: 'A-OK'
};

// statusObject nie dziedziczy z Quo.prototype, 
// ale możemy wywołać (zastosować) metodę get_status na 
// obiekcie statusObject, mimo że on sam nie ma 
// metody get_status

var status = Quo.prototype.get_status.apply(statusObject);
// status ma wartość 'A-OK'
    
    
====================================
// Tworzymy funkcję, która dodaje mnóstwo rzeczy.

// Warto zauważyć, że definicja zmiennej sum wewnątrz funkcji
// nie koliduje ze zmienną sum zdefiniowaną na zewnątrz funkcji. 
// Funkcja widzi tylko wewnętrzną zmienną.

var sum = function () {
   var i, sum = 0;
   for (i = 0; i < arguments.length; i += 1) {
      sum += arguments[i];
   }
   return sum;
};

document.writeln(sum(4, 8, 15, 16, 23, 42));  // 108
    
    
====================================
var add = function (a, b) {
   if (typeof a !== 'number' || typeof b !== 'number') {
      throw {
         name: 'TypeError',
         message: 'funkcja add wymaga przekazania liczb'
      }
   }
   return a + b;
}
    
    
====================================
// Tworzymy funkcję try_it, która wywołuje
// funkcję add nieprawidłowo

var try_it = function () {
   try {
      add("siedem");
   } catch (e) {
      document.writeln(e.name + ': ' + e.message);
   }
}

try_it();
    
    
====================================
Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};
    
    
====================================
Number.method('integer', function (  ) {
    return Math[this < 0 ? 'ceiling' : 'floor'](this);
});

document.writeln((-10 / 3).integer(  ));  // −3
    
    
====================================
String.method('trim', function (  ) {
    return this.replace(/^\s+|\s+$/g, '');
});

document.writeln('"' + "   neat   ".trim(  ) + '"');
    
    
====================================
// Dodajemy metodę warunkowo.

Function.prototype.method = function (name, func) {
    if (!this.prototype[name]) {
        this.prototype[name] = func;
    }
};
    
    
====================================
var hanoi = function (disc, src, aux, dst) {
   if (disk > 0) {
      hanoi(disc - 1, src, dst, aux);
      document.writeln('Przenoszenie dysku ' + disc + ' z ' + src + ' do ' + dst);
      hanoi(disc - 1, aux, src, dst);
   }
}

hanoi(3, 'Zrd', 'Pmc', 'Cel');
    
    
====================================
Przenoszenie dysku 1 z Zrd do Cel
Przenoszenie dysku 2 z Zrd do Pmc
Przenoszenie dysku 1 z Cel do Pmc
Przenoszenie dysku 3 z Zrd do Cel
Przenoszenie dysku 1 z Pmc do Zrd
Przenoszenie dysku 2 z Pmc do Cel
Przenoszenie dysku 1 z Zrd do Cel
    
    
====================================
// Definiujemy funkcję walk_the_DOM, która odwiedza każdy
// węzeł drzewa według kolejności podanej w źródle HTML, zaczynając
// od podanego węzła, oraz wywołuje przekazaną funkcję na każdym węźle.
// Funkcja walk_the_DOM wywołuje siebie samą w celu przetwarzania
// węzłów potomnych.

var walk_the_DOM = function walk(node, func) {
   func(node);
   node = node.firstChild;
   while (node) {
      walk(node, func);
      node = node.nextSibling;
   }
};

// Definiujemy funkcję getElementsByAttribute.
// Pobiera ona nazwę atrybutu i opcjonalną wartość wymagającą dopasowania.
// Wywołuje funkcję walk_the_DOM, przekazując jej funkcję 
// wyszukującą atrybut po nazwie w danym węźle. 
// Dopasowane atrybuty zbierane są w tablicy wyników.

var getElementsByAttribute = function (att, value) {
   var results = [];

   walk_the_DOM(document.body, function (node) {
      var actual = node.nodeType === 1 && node.getAttribute(att);
      if (typeof actual === 'string' && 
        (actual === value || typeof value !== 'string')) {
         results.push(node);
      }
   });

   return results;
};
    
    
====================================
// Tworzymy funkcję factorial (silnia)
// Funkcja ta używa rekurencji końcowej, ponieważ
// zwraca rezultat wywołania samej siebie.

// JavaScript obecnie nie optymalizuje takich wywołań.

var factorial = function factorial (i, a) {
   a = a || 1;
   if (i < 2) {
      return a;
   }
   return factorial(i - 1, a * i);
};

document.writeln(factorial(4));  // 24
    
    
====================================
var foo = function () {
   var a = 3, b = 5;

   var bar = function () {
      var b = 7, c = 11;

      // w tym punkcie a wynosi 3, b – 7, a c – 11

      a += b + c;

      // w tym punkcie a wynosi 21, b – 7, a c – 11

   };

   // w tym punkcie a wynosi 3, b – 5, a c nie jest zdefiniowane

   bar();

   // w tym punkcie a wynosi 21, a b – 5

};
    
    
====================================
var myObject = function (  ) {
    var value = 0;

    return {
        increment: function (inc) {
            value += typeof inc === 'number' ? inc : 1;
        },
        getValue: function (  ) {
            return value;
        }
    }
}(  );
    
    
====================================
// Tworzymy fukcję quo, który tworzy obiekt 
// posiadający metodę get_status oraz 
// prywatną właściwość status.

var quo = function (status) {
   return {
      get_status: function () {
         return status;
      }
   };
};

// Tworzymy instancję quo.

var myQuo = quo("zdumiony");

document.writeln(myQuo.get_status());
    
    
====================================
// Definiujemy funkcję, która ustawia kolor węzła DOM
// na żółty, a następnie rozjaśnia go do białego.

var fade = function (node) {
   var level = 1;
   var step = function () {
      var hex = level.toString(16);
      node.style.background = '#FFFF' + hex + hex;
      if (level < 15) {
         level += 1;
         setTimeout(step, 100);
      }
   };
   setTimeout(step, 100);
};

fade(document.body);
    
    
====================================
// PRZYKŁAD ZŁEGO KODU

// Tworzymy funkcję, która przypisuje funkcje obsługi zdarzenia 
// do tablicy węzłów w zły sposób.
// Po kliknięciu węzła, wyskakujące okienko powinno wyświetlić liczbę
// oznaczającą kolejność węzła w tablicy.
// W rzeczywistości wyświetlana liczba będzie zawsze równa liczbie węzłów w tablicy.

var add_the_handlers = function (nodes) {
   var i;
   for (i = 0; i < nodes.length; i += 1) {
      nodes[i].onclick = function (e) {
         alert(i);
      }
   }
};

// KONIEC PRZYKŁADU ZŁEGO KODU

    
====================================
// PRZYKŁAD LEPSZEGO KODU

// Tworzymy funkcję, która przypisuje funkcje obsługi zdarzenia 
// do tablicy węzłów w poprawny sposób.
// Po kliknięciu węzła, wyskakujące okienko wyświetli liczbę
// oznaczającą kolejność węzła w tablicy.

var add_the_handlers = function (nodes) {
   var i;
   for (i = 0; i < nodes.length; i += 1) {
      nodes[i].onclick = function (i) {
         return function (e) {
            alert(i);
         };
      }(i);
   }
};

    
====================================
request = prepare_the_request(  );
response = send_request_synchronously(request);
display(response);
    
    
====================================
request = prepare_the_request(  );
send_request_asynchronously(request, function (response) {
        display(response);
    });
    
    
====================================
String.method('deentityify', function () {

   // Tabela encji. Mapuje nazwy encji na odpowiadające im znaki.

   var entity = {
      quot: '"',
      lt: '<',
      gt: '>'
   };

   // zwraca metodę deentityify

   return function () {

      // To jest metoda deentityify. Wywołuje ona standardową metodę replace,
      // wyszukując fragmentów tekstu zaczynających się od '&' a kończących na ';'.
      // Jeśli znaki zawarte wewnątrz takiego fragmentu znajdują się w tabeli encji, 
      // cała encja jest zastępowana znakiem z tabeli. 
      // Funkcja używa wyrażeń regularnych (patrz rozdział 7).

      return  this.replace( /&([^&;]+);/g, 
         function (a, b) {
            var r = entity[b];
            return typeof r === 'string' ? r : a;
         }
      );    
   };
}());
    
    
====================================
document.writeln(
    '&lt;&quot;&gt;'.deentityify(  ));  // <">
    
    
====================================
var serial_maker = function () {

   // Tworzymy obiekt, który generuje niepowtarzające się identyfikatory.
   // Identyfikator składa się z dwóch części: prefiksu i numeru sekwencyjnego.
   // Obiekt posiada metody do ustawiania prefiksu i numeru sekwencyjnego,
   // oraz metodę gensym, która generuje identyfikatory.
   
   var prefix = '';
   var seq = 0;
   return {
      set_prefix: function (p) {
         prefix = String(p);
      },
      set_seq: function (s) {
         seq = s;
      },
      gensym: function () {
         var result = prefix + seq;
         seq += 1;
         return result;
      }
   };
};

var seqer = serial_maker();
seqer.set_prefix('Q');
seqer.set_seq(1000);
var unique = seqer.gensym();  // generuje 'Q1000'    

    
====================================
getElement('myBoxDiv').
  move(350, 150).
  width(100).
  height(100).
  color('red').
  border('10px outset').
  padding('4px').
  appendText("Proszę czekać").
  on('mousedown', function (m) {
     this.startDrag(m, this.getNinth(m));
  }).
  on('mousemove', 'drag').
  on('mouseup', 'stopDrag').
  later(2000, function () {
     this.
       color.('yellow').
       setHTML('Halo!').
       slide(400, 40, 200, 200);
  }).
  tip('To okienko można przesuwać');
    
    
====================================
var add1 = add.curry(1);
document.writeln(add1(6));    // 7
    
    
====================================
Function.method('curry', function () {
   var args = arguments, that = this;
   return function () {
      return that.apply(null, args.concat(arguments));
      };
   });  // coś tu jest nie tak...

    
====================================
Function.method('curry', function (  ) {
    var slice = Array.prototype.slice,
        args = slice.apply(arguments),
        that = this;
    return function (  ) {
        return that.apply(null, args.concat(slice.apply(arguments)));
    };
});
    
    
====================================
var fibonacci = function (n) {
    return n < 2 ? n : fibonacci(n − 1) + fibonacci(n − 2);
};

for (var i = 0; i <= 10; i += 1) {
    document.writeln('// ' + i + ': ' + fibonacci(i));
}

// 0: 0
// 1: 1
// 2: 1
// 3: 2
// 4: 3
// 5: 5
// 6: 8
// 7: 13
// 8: 21
// 9: 34
// 10: 55
    
    
====================================
var fibonacci = function (  ) {
    var memo = [0, 1];
    var fib = function (n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = fib(n − 1) + fib(n − 2);
            memo[n] = result;
        }
        return result;
    };
    return fib;
}(  );
    
    
====================================
var memoizer = function (memo, fundamental) {
    var shell = function (n) {
        var result = memo[n];
        if (typeof result !== 'number') {
            result = fundamental(shell, n);
            memo[n] = result;
        }
        return result;
    };
    return shell;
};
    
    
====================================
var fibonacci = memoizer([0, 1], function (shell, n) {
    return shell(n − 1) + shell(n − 2);
});
    
    
====================================
var factorial = memoizer([1, 1], function (shell, n) {
    return n * shell(n − 1);
});
    
    
==================