Posts em "javascript"

  1. Boredom

    0
    1. O que a falta de fazer não faz com as pessoas no IRC...
    2. miter: ls
    3. Sorella: .
    4. Sorella: ..
    5. Sorella: bin
    6. Sorella: lib
    7. Sorella: home
    8. vacuoustruth: rm -rf *
    9. vacuoustruth: terminal colaborativo, que idéia!
    10. Sorella: vacuoustruth: rm: permissão negada.
  2. 0

    HOLY SHIT D:

    HOLY FUCKING SHIT D:

    O que foi visto… não pode ser desvisto. comofas/

    Eu provavelmente vou martelar o teclado com minha cabeça até apagar essa informação de algum jeito. Mas eu tinha que fazer outras pessoas sofrerem com a pergunta também :D

  3. Sobrecarregando funções em JavaScript

    0

    No post anterior eu disse que era possível simular sobrecarga de funções em JavaScript sem muito trabalho, não é? Eu acabei me empolgando e resolvendo experimentar um pouco com a idéia.

    /**
     * Implementa sobrecarga de métodos com base no número de argumentos
     * de cada função.
     * Você pode passar uma ou mais funções para o construtor como
     * argumentos posicionais (exemplo: Overloaded(função 1,
     * função 2, ..., função n)), e elas serão
     * adicionadas ao objeto.
     *
     * Exemplo:
     * >>> var metodo = Overloaded(func1, func2, func3);
     *
     * Outra forma de sobrecarregar funções é instanciar o objeto e
     * chamar o método ``overload`` na instância. Como o ``overload``
     * retorna a instância do objeto de sobrecarga, você pode fazer
     * correntes de chamadas.
     *
     * Exemplo:
     * >>> var metodo = Overloaded(func1).overload(func2).overload(func3);
     */
    function Overloaded() {
        var __methods__ = [], // array de métodos sobrecarregados
            def_meth,         // método padrão
            i, len = arguments.length;
    
    
        function add(method, def)
        {
            __methods__[method.length] = method;
            if (def || !def_meth) {
                def_meth = method;
            }
            return this;
        }
    
        function call()
        {
            var meth = __methods__[arguments.length] || def_meth;
            return meth && meth.apply(this, arguments);
        }
    
        call.overload = add;
        for (i = 0; i < len; ++i) {
            typeof arguments[i] == 'function' && add(arguments[i]);
        }
    
        return call;
    }

    O código é simples e funciona da seguinte forma: Sempre que add é chamado, o método é armazenado na array de métodos de acordo com o número de argumentos que a função espera. Como exemplo, uma função de 2 argumentos seria armazenada no índice 2, uma de 7 argumentos no índice 7, e assim por diante. A função também define o método como padrão em dois casos: se o parâmetro def for verdadeiro, ou se nenhum método padrão tiver sido definido ainda.

    Depois objeto define a função call, que é responsável por chamar os métodos. A função procura primeiro um método que espere o número de argumentos passados para ela, e caso não encontre usa o método padrão. A última linha da função checa se qualquer método foi encontrado e chama esse método com os argumentos passados para a função, e por fim retorna qualquer valor que esse método retorne.

    Para que o objeto instanciado como Overload seja chamado como uma função comum, call é retornado, ao invés da instância para o objeto Overloaded. Como isso implicaria em não poder sobrecarregar outras funções, o objeto implementa a função de sobrecarga em call antes de retorná-la.

    O exemplo abaixo testa o funcionamento da sobrecarga de métodos, e você pode testá-los no console do seu navegador mesmo:

    >>> function greet(nome) { return "Olá, " + nome; }
    >>> function greet2(sobrenome, nome) {
    ...     return "Olá, " + nome + " " + sobrenome;
    ... }
    >>> var cumprimento = Overloaded(greet, greet2);
    >>> cumprimento("Undercode");
    Olá, Undercode
    >>> cumprimento("Undercode", "Blog");
    Olá, Blog Undercode

    Se quiser, você pode clonar/forkear o código fonte e alguns testes no meu Bitbucket.

  4. Simulando módulos em JavaScript

    0

    —análise sobre a organização e escalabilidade de web apps

    Uma das coisas que eu mais senti falta quando comecei a desenvolver a Lily foi um suporte nativo à módulos em javascript, já que a base do design da framework era justamente ser modular para que ela fosse bem extensível.

    Mas claro que a gamelily não é um caso isolado. A medida que o aplicativo cresce, você precisa de formas melhores para organizar seu código, tanto que isso virou discussão para as novas especificações da linguagem.

    E o que fazer quando nenhum dos navegadores oferece um bom suporte nativo à módulos? Bem, você procura soluções na interwebz, cria alguns hacks e escreve um artigo sobre eles :D

    Neste artigo eu vou falar um pouco sobre como simular módulos em JavaScript (claro), as técnicas e soluções disponíveis, e sobre os problemas que me fizeram martelar o teclado com a cabeça algumas vezes.

  5. Unix timestamp em JavaScript

    0

    Hoje no canal de ##javascript no freenode surgiu uma questão interessante: como conseguir o timestamp no formato Unix, só que para a data UTC ao invés da data local.

    Bem, JavaScript já usa um formato parecido com o do unix, só que incluindo os milisegundos também (enquanto o formato do unix só inclui até os segundos), então um getTime() é meio caminho para conseguir a data.

    O que faltava era converter a data para UTC (o horário de Greenwich), e o objeto Date tem a função getTimezoneOffset() que serve para isso mesmo. Só que ele retorna o valor em minutos!

    Então, a rotina para retornar a data no formato unix timestamp para a o horário GMT é: pegar o timestamp JavaScript e dividir por 1000 (para eliminar os milisegundos), e então diminuir pela zona de horário local. Ou na minha implementação:

    /**
     * Função: getUTCTime(data) -> Number
     * Parâmetros:
     * - {Date} data: a data para converter para timestamp unix.
     *
     * Retorna o timestamp unix para a data passada como parâmetro,
     * usando o horário GMT ao invés do horário local.
     */
    function getUTCTime(data) {
        // pega a zona horária, e como ele retorna o valor em minutos,
        // transforma esse valor para segundos.
        var timezone = data.getTimezoneOffset() * 60;
    
        // transforma a data para o formato timestamp do unix, ou seja
        // sem os milisegundos que JavaScript usa.
        var time = data.getTime() / 1000;
    
        // retorna o valor da divisão arredondado para baixo
        return Math.floor(time - timezone);
    }

    Simples não, embora ainda tenha muita coisa desnecessária no código (que eu incluí para deixá-lo um pouco mais legícel), então vamos melhorar um pouquinho a função.

    Primeiro, aquele data.getTime() não é necessário e nós podemos substituí-lo com um simples +data. Isto porque o JavaScript é bem dinâmico e converte os objetos de acordo com como você os usa. Neste caso estamos pedindo pelo valor &ldquot;positivo&rdquot; da data, precedendo a variável com um +, então getTime() é chamado automaticamente para converter a data para um número.

    Aquele Math.floor também é desnecessário. Tanto por ser lento quanto por adicionar mais uns bons bytes ao tamanho do arquivo. Ao invés disso podemos usar operadores binários.

    Como você deve saber, todos os números em JavaScript são pontos flutuantes (doubles), mas quando você executa operações binárias neles, JavaScript vai converter aquele número para inteiro, executar a operação e voltá-lo para ponto flutuante.

    Tá, e como usar isso para arredondar um número? Com o operador ~ (til é usado para negação de bits) você pode inverter os valores dos bits, isto é, todos os bits que eram 1 viram 0 e vice-versa. Embora para números você possa assumir que toda negação de bits vai retornar -(x + 1). Ou seja, ~5 retornaria -6. A parte importante aqui é essa operação ignora as casas decimais, então ~5.5 retornaria -6 também! Então a maneira mais rápida de se arredondar um número para baixo em JavaScript é inverter seus bits duas vezes, ou ~~número.

    Voltando à função:

    function getUTCTime(data) {
        return ~~((+data / 1000) - data.getTimezoneOffset() * 60);
    }

    E é isso. Você pode inclusive adicionar essa função ao protótipo da data, usando this ao invés do parãmetro passado para ela:

    function getUTCTime(data) {
        data || (data = this); // se data não estiver definido, usa this
        return ~~((+data / 1000) - data.getTimezoneOffset() * 60);
    }
    Date.prototype.getUTCTime = getUTCTime;

    Agora você pode usar a função tanto com getUTCTime(data) quanto com data.getUTCTime().