Usando Sass/Compass com Gemfile

Isso é util para garantir que a sua aplicação funcione sem problemas no futuro ou por exemplo se você tem projetos usando diferêntes versões do Sass ou Compass.

É necessário instalar o bundler (http://bundler.io/)

$ gem install bundler

Na raiz do projeto use o comando:

$ bundle init

Isso vai criar um arquivo Gemfile onde você pode colocar as depenências da aplicação.

Por exemplo:

source "http://rubygems.org/"
gem "compass", "0.12.1"
gem "ceaser-easing", "0.4"

Depois você tem duas opções:

Instalar as dependências no sistema.

$ bundle install

Ou espeficicar um local (melhor opção caso você queira usar versões diferentes).

$ bundle install --path .bundle

Esse segunda opção vai instalar as dependencias no diretório .bundle

Para rodar o compass que foi instalando no --path especificado use:

$ bundle exec compass -v

Modificando o contexto da palavra-chave this em JavaScript

Em JavaScript a palavra-chave this é uma referência ao objeto atual, porem seu contexto pode mudar dependendo da forma como o objeto é tratado

function fn(){
    console.log(this);
};

fn(); // this === Window
new fn(); // this === fn

Em alguns casos como no exemplo abaixo precisamos que this mantenha um determinado contexto:

var widget = {
    el: document.getElementById('wgt'),
    hide: function() {
       this.el.style.display = 'none';
    },
    init: function(){
        this.el.onclick = this.hide;
        // na função hide this passa a referenciar widget.el,
        // causando um erro pois não existe this.el neste contexto
        // precisamos que continue referenciando apenas widget
    }
}
widget.init();

Uma solução seria salvar o valor de this em uma variável, passar uma função anônima para o método onclick e executar a função hide.

var widget = {
    el: document.getElementById('wgt'),
    hide: function() {
       this.el.style.display = 'none';
    },
    init: function(){
        var self = this;
        this.el.onclick = function(){
            self.hide();
        }
    }
}
widget.init();

Não é uma solução muito elegante, e o JavaScript nos permite fazer isso de uma maneira melhor.

Implementando um método bindTo no objeto Function

Usando o método apply das funções é possivel alterar o contexto de this em funções.
Abaixo um exemplo implementando um novo método no objeto Function:

Function.prototype.bindTo = function(obj){
    var fn = this; // referencia para a função atual
    return function(){
        // obj é o objeto para o qual queremos alterar o contexto de this
        // arguments são os argumentos originais que são recebidos na função retornada
        fn.apply(obj, arguments);
    }
}

O código poderia ser modificado para:

var widget = {
    el: document.getElementById('wgt'),
    hide: function() {
       this.el.style.display = 'none';
    },
    init: function(){
        // usando bindTo agora disponível em qualquer função
        this.el.onclick = this.hide.bindTo(this);
    }
}
widget.init();

Referências

Variáveis declaradas no contexto uma função JavaScript, como acessá-las?

JavaScript é tão dinâmico que podemos criar soluções que não existem na linguagem.

Até onde sabemos não é possível acessar variáveis declaradas no contexto de uma função.

Como funciona o escopo de variável em JavaScript

Em JavaScript temos dois tipos de escopo de variável, local e global. Toda variável declarada sem a instrução var será definida no contexto do objeto global ( window nos browsers ) e também será global se for definida com a instrução var no contexto global.

Ou seja:

var a = 1;
b = 2;

function doNothing() {
    var c = 3;
    d = 4;
};

doNothing();

console.log(a); // global
console.log(b); // global
console.log(c); // local ReferenceError c is not defined
console.log(d); // global

Funções construtoras retornam objetos

Funções construtoras retornam objetos contendo as propriedades e métodos definidos:

function Car(){
    var secretKey = '#$(**dwd73451#)&@!';
    this.type = 'flex';
    this.km = 0;
}

Car.prototype.run = function(km){
    this.km+=km;
    return this.km;
}

var golf = new Car();
console.log(gol); // Car { type="flex", km=0, run=function()}

Não temos como acessar a variavel secretKey, porem se implementarmos um método dentro da função construtora Car o mesmo terá acesso a variável secretKey:

function Car(){
    var secretKey = '#$(**dwd73451#)&@!';
    this.type = 'flex';
    this.km = 0;
    this.getSecretKey = function(){
        return secretKey
    }
}
var golf = new Car();
golf.getSecretKey(); // #$(**dwd73451#)&@!

Pelo que vimos aqui os requesitos seriam:

  • A função deveria ser usada como um construtor
  • Implementar um método que retornasse as variáveis

Implementando um novo método no objeto Function

Function.prototype.expose = function( private ){
    
    // this se refere a função atual
    
    // propriedade que contera a instancia da função mofificada
    this.fn = this.fn || undefined;

    if ( this.fn ){
        // se já houver uma instancia apenas chama o método get
        return this.fn.get( private )
    };
    
    // função que sera adicionada a a função modificada para retornar as variáveis
    var get = function( v ){
        return eval( v );
    };
    
    // this.toString() retorna o código fonte da função
    var fnSource = this.toString().match( /function.+?\((.*)\).+?\{([\s\S]*)\}/ );
    
    // aqui está o segredo, criar uma nova função usando o objeto Function
    // passando a string do código fonte e adicionando o novo método get
    var F = new Function( fnSource[1],'this.get='+get+';'+fnSource[2] );
    
    // usamos F como construtor e armazenamos uma instância em this.fn para futuros acessos
    this.fn = new F;
    
    // Function.prototype.expose retorna o resultado do método get
    return this.fn.get(private);
}

Alguns testes:

var fn = function() {
    var c = 1;
    return c;
};

var fn2 = function() {
    var a = 1;
    if( a > 0 ){
        a=10;
    }
    return a;
};

var config = function() {
    var url = 'http://10.42.43.100';
    var privateKey = '#aˆ&$DU)DI)RQ#@#$%ˆFHGFOIJE%$#$#%(';
};

console.log( fn.expose('c') );
console.log( fn2.expose('a') );
console.log( config.expose('privateKey') );

Conclusões

Como vimos é possível quebrar o escopo de uma variável em JavaScript, talvez de uma maneira não muito elegante ( eval, toString ) e com algumas limitações de uso.

Sinceramente nunca precisei usar esse artificio, essa solução (baseada na referência abaixo) foi apenas para demonstrar essa curiosidade da linguagem.

Referências