Pokazywanie postów oznaczonych etykietą function. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą function. Pokaż wszystkie posty

wtorek, 28 stycznia 2014

recursiveEach

recursiveEach - rekursywna iteracja po obiekcie. Funkcja do prawidłowego działania wymaga również 2 innych funkcji znajdujących się na tym blogu: getType oraz each.
Funkcję można dodatkowo rozbudować. Np. idealnie byłoby, gdyby w docelowej funkcji zamiast samej wartości klucza zwracała tablicę stringów wskazujących na ścieżkę do tego klucza w głównym obiekcie.

var recursiveEach = function recur(obj, fn, depth) {
  if (typeof depth === 'undefined')
    depth = -1;

  var res = {};

  if (getType(obj) === 'Object' && depth !== 0) {
    each(obj, function (el, key) {
      res[key] = recur(el, fn, depth - 1);
    });
    return res;
  }
  return fn(obj);
};

var getType = function (obj) {
  return ({}).toString.call(obj).slice(8, -1);
};

var each = function (obj, fn) {
  var res = {};
  for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
      res[i] = fn.call(obj, obj[i], i);
    }
  }
  return res;
};

Przy pomocy tej funkcji łatwo zaimplementować funkcję flatten. Do funkcji flatten można przekazać zarówno obiekt jak i tablicę.
var flatten = function(obj) {
  var res = [];
  recursiveEach(obj, function(val) {
    res.push(val);
  });
  return res;
};

środa, 22 stycznia 2014

asyncMap - asynchroniczne iterowanie po tablicy

Funkcja pozwalająca na iterację po tablicy w sposób asynchroniczny. Można dzięki niej w genialnie prosty sposób wykonać np. kolejkę zadań, które wymagają wykonania asynchronicznych akcji np. zapytanie do innego serwera.

var asyncMap = function(arr, fn, endFn) {
 var i = 0,
  len = arr.length,
  res = [];

 (function callee() {
  fn(arr[i], i, function(singleRes) {
   res.push(singleRes);
   if (++i < len) {
    callee();
   } else {
    endFn(res);
   }
  }, arr);
 })();
};
prosty przykład użycia: http://jsfiddle.net/gkucmierz/QzLP5/

czwartek, 12 września 2013

waitFor - zaczekaj na pojawienie się obiektu

Funkcja, która w bardzo prymitywny sposób czeka na pojawienie się oczekiwanego obiektu w bliżej nie określonym czasie. Czasami takie coś może się przydać jeśli inny skrypt tworzy obiekty i nie wiemy kiedy się pojawią.

var waitFor = function(obj, srcArr, fn, opt){
  opt = opt || {t: 50};

  (function callee(){
    var tmp = obj;
    var tid = setTimeout(callee, opt.t);
    for (var i = 0; i < srcArr.length; ++i) {
      if (typeof tmp[srcArr[i]] !== 'undefined') {
        tmp = tmp[srcArr[i]];
      } else {
        return;
      }
    }
    clearTimeout(tid);
    fn(tmp, obj);
  })();
};
Poniżej przykład użycia:
waitFor(window, 'abc.def'.split('.'), function(data, obj){
  alert('jest: ' + data);
});

setTimeout(function(){
  window.abc = {};
  
  setTimeout(function(){
    window.abc.def = 'obiekt/dane';
  }, 1e3);
}, 1e3);

sobota, 3 marca 2012

Array unique - czyli pozbywamy się duplikatów

Funkcja jako argument przyjmuje tablicę z danymi dowolnego typu. W rezultacie funkcja zwraca tablicę zawierającą tylko unikalne elementy tablicy źródłowej.
var unique = function(arr){
  return arr.filter(function(el, i){
    return arr.indexOf(el, i+1) === -1;
  });
};
Poniżej zamieszczam funkcję robiącą to samo co powyższa funkcja z drobnym wyjątkiem. Poniższa funkcja zawiera dwa dodatkowe wykonania funkcji reverse co pozwoliło na zachowanie naturalnej kolejności elementów występujących w tablicy. Pierwsze wystąpienie danego elementu pozostaje w tym samym miejscu, kolejne wystąpienia tego samego elementu są ignorowane. W poprzedniej wersji funkcji to ostatni element zostałby zachowany.
var unique = function(arr){
  return arr.reverse().filter(function(el, i){
    return arr.indexOf(el, i+1) === -1;
  }).reverse();
};

let unique = [...new Set(myArray)];

środa, 22 lutego 2012

getType - sprawdzenie typu, pewniejsze od typeof

Poniżej zamieszczam funkcję zwracającą typ danej. Funkcja w przeciwieństwie do operatora typeof znacznie skuteczniej oddaje typ przekazanej danej. Pomysł został zaczerpnięty z serwisu JavaScript Garden. Funkcja do sprawdzenia typu wykorzystuje generyczną funkcję toString podstawowego obiektu.
var getType = function(obj){
  return ({}).toString.call(obj).slice(8, -1);
};
Poniżej szybkie sprawdzenie różnic funkcji getType oraz operatora typeof. Pomaga on uświadomić sobie, z jakimi problemami mamy do czynienia, jeśli używamy operatora typeof.
[{}, [], '', 0, 1/0, false, function(){}, /./, null, undefined].map(function(obj){
  return [getType(obj), typeof obj];
});
Tak naprawdę operator typeof JavaScriptu ma tylko jedno uzasadnione zastosowanie.
typeof variable === 'undefined';

sobota, 11 lutego 2012

Array shuffle

Implementacja funkcji mieszającej elementy tablicy w języku JavaScript.
Array.prototype.shuffle = function(){
  return this.sort(function(){
    return Math.random() - 0.5;
  });
};
Przykład użycia:
[1, 2, 3].shuffle();
Poniżej inna implementacja bez użycia prototypów.
var shuffle = function(arr){
  return arr.sort(function(){
    return Math.random() - 0.5;
  });
};

niedziela, 14 sierpnia 2011

startInterval czyli natychmiastowy setInterval

var startInterval = function(fn, delay){
  var arg = [].slice.call(arguments, 2),
      that = this;  
  var newFn = function(){
    fn.apply(that, arg);
  };
  newFn();
  return setInterval(newFn, delay);
};

Powyżej zamieszczam funkcję startInterval. Działa dokładnie tak jak setInterval (z wyjątkiem możliwości przekazania pierwszego parametru jako String) z tą różnicą, że pierwsze wywołanie funkcji następuje natychmiastowo.
Funkcja jest wygodną alternatywą dla setInterval. Dzięki niej nie trzeba w kodzie tworzyć dodatkowych nazw dla funkcji, aby wywołać ją, oraz przekazać jako parametr do setInterval.

niedziela, 12 czerwca 2011

Domyślne parametry funkcji

Funkcja i domyślne jej parametry w JavaScript? JavaScript nigdy nie oferował mechanizmu nadawania domyślnych wartości niezdefiniowanym parametrom przy jej wywołaniu.

Można sobie z tą niedogodnością poradzić w całkiem prosty sposób i wiele osób tak to właśnie robi. Poniżej zamieszczam kawałek kodu.

var fn = function(a, b, c){
  a = a || 25;
  b = b || [2, 5];
  c = c || 'domyslny';
  alert(
    'liczba: ' + a + '\n' +
    'tablica: ' + b + '\n' +
    'string: ' + c
  );
};

fn(5, [1,2,3], 'test');
fn(5, [1,2,3]);
fn(5);
fn();

Działa całkiem nieźle. Co jednak jeśli wywołamy funkcję w poniższy sposób?

fn(0);

Funkcja wyświetla 25. Przecież wysłaliśmy 0 (zero). Dzieje się tak, ponieważ poniższa konstrukcja traktuje liczbę 0 jako wartość false, dlatego do zmiennej a przypisywana jest alternatywna wartość 25.

a = a || 25;

Skoro znamy już problemy wynikające z powyższych konstrukcji przejdźmy do rozwiązania problemu w inny, bardziej elegancki sposób.
Poniżej zamieszczam funkcję która pozwala ze zwykłej funkcji stworzyć funkcję przyjmującą domyślne parametry. Kod zawiera również funkcję testową oraz kilka jej wywołań.

Function.prototype.params = function(){
  var that = this,
      arg = [].splice.apply(arguments, [0, arguments.length]);
  return function(){
    return that.apply(this, [].splice.apply(arguments, [0]).concat(
        arg.slice(arguments.length)
      )
    );
  };
};

var test = function(a, b){
  alert(
    a + '\n' +
    b
  );
}.params(11, 22);

test(1, 2);
test(1);
test();

Stworzenie funkcji z domyślnymi parametrami jest teraz dziecinnie proste. Wystarczy zadeklarować dowolną funkcję a zaraz za nią wywołać naszą metodę z argumentami, które mają być domyślne.
Warto pamiętać o tym, że powyższe udogodnienie będzie spowalniać działanie skryptu. Każde wywołanie zwróconej funkcji powoduje wywołanie kilku dodatkowych instrukcji. Nadużywanie tego udogodnienia może okazać się nierozsądne, w szczególności w przypadku prostych, wielokrotnie powtarzanych funkcji.