Práticas recomendadas comumente aceitas para organização de código em JavaScript [fechado]

561

Como estruturas JavaScript como o jQuery tornam os aplicativos Web do lado do cliente mais ricos e funcionais, comecei a perceber um problema ...

Como no mundo você mantém isso organizado?

  • Coloque todos os seus manipuladores em um único local e escreva funções para todos os eventos?
  • Criar função / classes para agrupar todas as suas funcionalidades?
  • Escreva como louco e só espero que funcione da melhor maneira?
  • Desistir e começar uma nova carreira?

Menciono o jQuery, mas é realmente qualquer código JavaScript em geral. Estou descobrindo que, conforme as linhas e as linhas começam a se acumular, fica mais difícil gerenciar os arquivos de script ou encontrar o que você está procurando. Possivelmente, os maiores propblems que eu encontrei são tantas maneiras de fazer a mesma coisa que é difícil saber qual é a melhor prática atualmente aceita.

Existem recomendações gerais sobre a melhor maneira de manter seus arquivos .js tão agradáveis ​​e organizados quanto o restante do seu aplicativo? Ou isso é apenas uma questão de IDE? Existe uma opção melhor lá fora?


EDITAR

Esta pergunta pretendia ser mais sobre organização de códigos e não sobre organização de arquivos. Houve alguns bons exemplos de mesclagem de arquivos ou divisão de conteúdo.

Minha pergunta é: qual é a atual maneira de prática recomendada comumente aceita para organizar seu código real? Qual é o seu caminho, ou mesmo o modo recomendado para interagir com os elementos da página e criar um código reutilizável que não entre em conflito?

Algumas pessoas listaram namespaces, o que é uma boa ideia. Quais são outras formas de lidar mais especificamente com os elementos da página e manter o código organizado e organizado?

Hugoware
fonte
alguém que realmente tomou o tempo para falar sobre a própria organização de código, e não "apenas" o instrumento que ele usa para concatenar & compressa seus arquivos JS: stackoverflow.com/questions/16736483/...
Adrien Seja

Respostas:

183

Seria muito melhor se o javascript tivesse namespaces embutidos, mas acho que organizar coisas como Dustin Diaz descreve aqui me ajuda muito.

var DED = (function() {

    var private_var;

    function private_method()
    {
        // do stuff here
    }

    return {
        method_1 : function()
            {
                // do stuff here
            },
        method_2 : function()
            {
                // do stuff here
            }
    };
})();

Coloquei "namespaces" diferentes e, às vezes, classes individuais em arquivos separados. Geralmente começo com um arquivo e, como uma classe ou espaço para nome fica grande o suficiente para justificá-lo, separo-o em seu próprio arquivo. Usar uma ferramenta para combinar todos os seus arquivos para produção também é uma excelente idéia.

urso polar
fonte
24
Costumo me referir a isso como "o caminho de Crockford". +1 de mim
Matt Briggs
4
Você pode ir um pouco mais longe. Veja este link: wait-till-i.com/2007/08/22/…
MKroehnert
4
O @MattBriggs também chamado de module patterne é baseado em IIFE pattern.
Adrien Seja
Você não precisa exportar classes de alguma forma? Como um objeto é criado de fora desse módulo? Ou deve haver um método createNewSomething()no objeto de retorno, para que a criação do objeto ocorra apenas dentro do módulo? Hum ... eu esperaria que as classes (construtores) sejam visíveis do lado de fora.
robsch
@robsch Seu exemplo não aceita nenhum parâmetro, mas a maioria aceita. Veja o meu exemplo aqui para saber como isso geralmente é feito (texto datilografado, mas 99% mesmo): repl.it/@fatso83/Module-Pattern-in-TypeScript
oligofren
88

Eu tento evitar a inclusão de qualquer javascript no HTML. Todo o código é encapsulado em classes e cada classe está em seu próprio arquivo. Para desenvolvimento, tenho tags <script> separadas para incluir cada arquivo js, ​​mas elas são mescladas em um único pacote maior para produção, a fim de reduzir a sobrecarga das solicitações HTTP.

Normalmente, terei um único arquivo js 'principal' para cada aplicativo. Portanto, se eu estivesse escrevendo um aplicativo "survey", teria um arquivo js chamado "survey.js". Isso conteria o ponto de entrada no código do jQuery. Crio referências de jQuery durante a instanciação e depois as passo para meus objetos como parâmetros. Isso significa que as classes javascript são 'puras' e não contêm nenhuma referência a IDs ou nomes de classes CSS.

// file: survey.js
$(document).ready(function() {
  var jS = $('#surveycontainer');
  var jB = $('#dimscreencontainer');
  var d = new DimScreen({container: jB});
  var s = new Survey({container: jS, DimScreen: d});
  s.show();
});

Também acho a convenção de nomenclatura importante para facilitar a leitura. Por exemplo: eu acrescento 'j' a todas as instâncias do jQuery.

No exemplo acima, há uma classe chamada DimScreen. (Suponha que isso ofereça a tela e apareça uma caixa de alerta.) Ele precisa de um elemento div que possa ser ampliado para cobrir a tela e, em seguida, adicione uma caixa de alerta, para que eu transmita um objeto jQuery. O jQuery possui um conceito de plug-in, mas parecia limitador (por exemplo, instâncias não são persistentes e não podem ser acessadas) sem nenhuma vantagem real. Portanto, a classe DimScreen seria uma classe javascript padrão que, por acaso, usa jQuery.

// file: dimscreen.js
function DimScreen(opts) { 
   this.jB = opts.container;
   // ...
}; // need the semi-colon for minimizing!


DimScreen.prototype.draw = function(msg) {
  var me = this;
  me.jB.addClass('fullscreen').append('<div>'+msg+'</div>');
  //...
};

Criei algumas aplicações bastante complexas usando essa abordagem.

Jason Moore
fonte
15
Acho que usar $como prefixo de nome de variável é uma prática mais comum, mas posso estar errado. Então, em $s = $('...')vez de jS = $('...'), apenas uma questão de preferência, eu acho. Interessante, porém, já que a notação húngara é considerada um cheiro de código. É estranho como algumas das minhas convenções / preferências de código JavaScript são diferentes das minhas convenções de codificação C # / Java.
jamiebarrow
9
@jamie Não é um cheiro de código, neste caso, é precisamente um dos poucos casos em que o húngaro é bom . Você pode querer ler isso .
Dan Abramov
3
@ DanAbramov obrigado pelo link. Eu realmente preciso ler todos os blogs de Joel, ele explica as coisas tão bem. Definitivamente merece a fama / reputação que ele tem. Vou me referir a Systems Hungariancomo um cheiro de código e Apps Hungariancomo uma prática a partir de agora :)
jamiebarrow
Eu acho que no mundo C #, também poderia ser um ótimo artigo para promover o uso de var, agora que penso nisso. A maioria dos argumentos contra o uso varé onde você não tem certeza do 'tipo' do que é retornado, mas acho que o argumento deve ser contrário, sem conhecer a 'classe' do que é retornado. Se você usa o Apps Hungarian, não deve ter essa preocupação ... interessante.
jamiebarrow
3
@ Marnen: Entendo o seu ponto, mas não é inútil como um guia para o programador. O prefixo $ me lembra o que é ao ler meu código posteriormente e, portanto, ajuda a uma compreensão mais rápida.
21713 Sean
39

Você pode dividir seus scripts em arquivos separados para desenvolvimento, criar uma versão de "release" na qual os agrupe e execute o YUI Compressor ou algo semelhante.

Greg
fonte
Às vezes, existem scripts javascript desnecessários. É um desperdício enviá-las ao cliente. Eu acho que é melhor enviar apenas o necessário. Obviamente, para um aplicativo Web que está sendo usado o dia inteiro, como um aplicativo de intranet, talvez seja melhor enviar o lote inteiro de uma só vez, no carregamento da primeira página.
DOK
2
A compilação do @DOK deve incluir excisão de itens não utilizados.
aehlke
Há também um conceito de carregamento lento para tentar reduzir as necessidades de largura de banda, onde você carrega a página inicial e executa o carregamento assíncrono dos arquivos de script necessários (conforme mencionado em outras respostas a esta pergunta). No entanto, isso pode exigir mais solicitações e, na verdade, pode ser menos utilizável. @DOK, se o JS estiver armazenado em cache, uma solicitação média poderá ser melhor do que algumas pequenas.
jamiebarrow
27

Inspirado em posts anteriores, fiz uma cópia dos diretórios Rakefile e de fornecedores distribuídos com o WysiHat (um RTE mencionado pelo changelog) e fiz algumas modificações para incluir a verificação de código com JSLint e a minificação com o YUI Compressor .

A idéia é usar Sprockets (do WysiHat) para mesclar vários JavaScripts em um arquivo, verificar a sintaxe do arquivo mesclado com JSLint e reduzi-lo com o YUI Compressor antes da distribuição.

Pré-requisitos

  • Java Runtime
  • rubi e ancinho
  • Você deve saber como colocar um JAR no Classpath

Agora faça

  1. Faça o download do Rhino e coloque o JAR ("js.jar") em seu caminho de classe
  2. Faça o download do YUI Compressor e coloque o JAR (build / yuicompressor-xyz.jar) em seu caminho de classe
  3. Faça o download do WysiHat e copie o diretório "vendor" para a raiz do seu projeto JavaScript
  4. Faça o download do JSLint for Rhino e coloque-o no diretório "vendor"

Agora crie um arquivo chamado "Rakefile" no diretório raiz do projeto JavaScript e adicione o seguinte conteúdo:

require 'rake'

ROOT            = File.expand_path(File.dirname(__FILE__))
OUTPUT_MERGED   = "final.js"
OUTPUT_MINIFIED = "final.min.js"

task :default => :check

desc "Merges the JavaScript sources."
task :merge do
  require File.join(ROOT, "vendor", "sprockets")

  environment  = Sprockets::Environment.new(".")
  preprocessor = Sprockets::Preprocessor.new(environment)

  %w(main.js).each do |filename|
    pathname = environment.find(filename)
    preprocessor.require(pathname.source_file)
  end

  output = preprocessor.output_file
  File.open(File.join(ROOT, OUTPUT_MERGED), 'w') { |f| f.write(output) }
end

desc "Check the JavaScript source with JSLint."
task :check => [:merge] do
  jslint_path = File.join(ROOT, "vendor", "jslint.js")

  sh 'java', 'org.mozilla.javascript.tools.shell.Main',
    jslint_path, OUTPUT_MERGED
end

desc "Minifies the JavaScript source."
task :minify => [:merge] do
  sh 'java', 'com.yahoo.platform.yui.compressor.Bootstrap', '-v',
    OUTPUT_MERGED, '-o', OUTPUT_MINIFIED
end

Se você fez tudo corretamente, poderá usar os seguintes comandos no console:

  • rake merge - mesclar diferentes arquivos JavaScript em um
  • rake check- para verificar a sintaxe do seu código (esta é a tarefa padrão , para que você possa simplesmente digitar rake)
  • rake minify - para preparar a versão minificada do seu código JS

Na fusão de origem

Usando o Sprockets, o pré-processador JavaScript, você pode incluir (ou require) outros arquivos JavaScript. Use a seguinte sintaxe para incluir outros scripts do arquivo inicial (chamado "main.js", mas você pode alterar isso no Rakefile):

(function() {
//= require "subdir/jsfile.js"
//= require "anotherfile.js"

    // some code that depends on included files
    // note that all included files can be in the same private scope
})();

E depois...

Dê uma olhada no Rakefile fornecido com o WysiHat para configurar os testes de unidade automatizados. Coisas legais :)

E agora a resposta

Isso não responde muito bem à pergunta original. Eu sei e sinto muito por isso, mas eu publiquei aqui porque espero que seja útil para outra pessoa organizar sua bagunça.

Minha abordagem para o problema é fazer o máximo possível de modelagem orientada a objetos e separar implementações em arquivos diferentes. Os manipuladores devem ser o mais curtos possível. O exemplo com Listsingleton também é bom.

E espaços para nome ... bem, eles podem ser imitados por uma estrutura mais profunda de objetos.

if (typeof org === 'undefined') {
    var org = {};
}

if (!org.hasOwnProperty('example')) {
    org.example = {};
}

org.example.AnotherObject = function () {
    // constructor body
};

Não sou muito fã de imitações, mas isso pode ser útil se você tiver muitos objetos que gostaria de sair do escopo global.

Damir Zekić
fonte
18

A organização do código requer a adoção de convenções e padrões de documentação:
1. Código do namespace para um arquivo físico;

Exc = {};


2. Agrupe classes nesses namespaces javascript;
3. Defina protótipos ou funções ou classes relacionadas para representar objetos do mundo real;

Exc = {};
Exc.ui = {};
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};
Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    ...
};


4. Defina convenções para melhorar o código. Por exemplo, agrupe todas as suas funções ou métodos internos em seu atributo de classe de um tipo de objeto.

Exc.ui.domTips = function (dom, tips) {
    this.dom = gift;
    this.tips = tips;
    this.internal = {
        widthEstimates: function (tips) {
            ...
        }
        formatTips: function () {
            ...
        }
    };
    ...
};


5. Crie documentação de namespaces, classes, métodos e variáveis. Onde necessário, também discuta parte do código (alguns FIs e Fors, eles geralmente implementam uma lógica importante do código).

/**
  * Namespace <i> Example </i> created to group other namespaces of the "Example".  
  */
Exc = {};
/**
  * Namespace <i> ui </i> created with the aim of grouping namespaces user interface.
  */
Exc.ui = {};

/**
  * Class <i> maskdInput </i> used to add an input HTML formatting capabilities and validation of data and information.
  * @ Param {String} mask - mask validation of input data.
  */
Exc.ui.maskedInput = function (mask) {
    this.mask = mask;
    ...
};

/**
  * Class <i> domTips </i> used to add an HTML element the ability to present tips and information about its function or rule input etc..
  * @ Param {String} id - id of the HTML element.
  * @ Param {String} tips - tips on the element that will appear when the mouse is over the element whose identifier is id <i> </i>.
  */
  Exc.ui.domTips = function (id, tips) {
    this.domID = id;
    this.tips = tips;
    ...
};


Estas são apenas algumas dicas, mas que ajudaram bastante na organização do código. Lembre-se de que você deve ter disciplina para ter sucesso!

Nery Jr
fonte
13

Seguir bons princípios e padrões de design de OO ajuda bastante a tornar seu código fácil de manter e entender. Mas uma das melhores coisas que descobri recentemente são sinais e slots, também conhecidos como publicação / assinatura. Dê uma olhada em http://markdotmeyer.blogspot.com/2008/09/jquery-publish-subscribe.html para obter uma implementação simples do jQuery.

A idéia é bem usada em outros idiomas para o desenvolvimento de GUI. Quando algo significativo acontece em algum lugar do seu código, você publica um evento sintético global no qual outros métodos em outros objetos podem se inscrever. Isso proporciona excelente separação de objetos.

Eu acho que o Dojo (e o Prototype?) Têm uma versão incorporada dessa técnica.

veja também O que são sinais e slots?

meouw
fonte
Eu fiz isso no jQuery. O JS possui um modelo de evento interno, então você realmente não precisa de muito suporte de estrutura.
Marnen Laibow-Koser 15/02
12

Consegui aplicar com êxito o Padrão do Módulo Javascript a um aplicativo Ext JS no meu trabalho anterior. Forneceu uma maneira simples de criar código bem encapsulado.

Alan
fonte
11

O Dojo teve o sistema de módulos desde o primeiro dia. Na verdade, é considerado uma pedra angular do Dojo, a cola que mantém tudo junto:

Usando os módulos, o Dojo atinge os seguintes objetivos:

  • Namespaces para código Dojo e código customizado ( dojo.declare()) - não poluem o espaço global, coexistem com outras bibliotecas e o código que não reconhece Dojo do usuário.
  • Carregando módulos de forma síncrona ou assíncrona por nome ( dojo.require()).
  • Construções personalizadas analisando dependências do módulo para criar um único arquivo ou um grupo de arquivos interdependentes (as chamadas camadas) para incluir apenas o que seu aplicativo da web precisa. As construções customizadas também podem incluir módulos Dojo e módulos fornecidos pelo cliente.
  • Acesso transparente baseado em CDN ao Dojo e código do usuário. Tanto a AOL quanto o Google carregam o Dojo dessa maneira, mas alguns clientes fazem isso também para seus aplicativos Web personalizados.
Eugene Lazutkin
fonte
9

Confira JavasciptMVC .

Você pode :

  • divida seu código em camadas de modelo, visualização e controlador.

  • compactar todo o código em um único arquivo de produção

  • código de geração automática

  • criar e executar testes de unidade

  • e muito mais...

O melhor de tudo é que ele usa o jQuery, para que você possa tirar proveito de outros plugins do jQuery.

andyuk
fonte
Sim, eu usei o jmvc e é muito bom - os documentos podem ser melhores
meouw
9

Meu chefe ainda fala dos tempos em que eles escreveram código modular (linguagem C) e reclama de quão ruim o código é hoje em dia! Dizem que os programadores podem escrever assembly em qualquer estrutura. Sempre existe uma estratégia para superar a organização do código. O problema básico é com caras que tratam o script java como um brinquedo e nunca tentam aprendê-lo.

No meu caso, escrevo arquivos js com base no tema da interface do usuário ou na tela do aplicativo, com uma init_screen () adequada. Usando a convenção de nomenclatura de identificação adequada, asseguro-me de que não haja conflitos de espaço de nome no nível do elemento raiz. No discreto window.load (), vinculo as coisas com base no ID de nível superior.

Uso estritamente os fechamentos e padrões de scripts java para ocultar todos os métodos particulares. Depois de fazer isso, nunca enfrentou um problema de propriedades / definições de função / definições de variáveis ​​conflitantes. No entanto, ao trabalhar com uma equipe, muitas vezes é difícil impor o mesmo rigor.

questzen
fonte
9

Estou surpreso que ninguém tenha mencionado estruturas MVC. Eu tenho usado o Backbone.js para modular e desacoplar meu código, e isso tem sido inestimável.

Existem muitos desses tipos de estruturas por aí, e a maioria delas também é bem pequena. Minha opinião pessoal é que, se você estiver escrevendo mais do que apenas algumas linhas de jQuery para itens chamativos da interface do usuário ou quiser um aplicativo Ajax rico, uma estrutura MVC facilitará sua vida.

Chetan
fonte
8

"Escreva como louco e só espero que funcione da melhor maneira?", Eu já vi um projeto como este que foi desenvolvido e mantido por apenas 2 desenvolvedores, um aplicativo enorme com muito código javascript. Além disso, havia atalhos diferentes para todas as funções possíveis de jquery que você pode imaginar. Sugeri que eles organizassem o código como plugins, pois esse é o equivalente jquery de classe, módulo, espaço para nome ... e todo o universo. Mas as coisas pioraram muito, agora eles começaram a escrever plugins, substituindo todas as combinações de três linhas de código usadas no projeto. Pessoalmente, acho que o jQuery é o diabo e não deve ser usado em projetos com muito javascript, porque incentiva você a ser preguiçoso e a não pensar em organizar o código de forma alguma. Prefiro ler 100 linhas de javascript do que uma linha com 40 funções jQuery encadeadas (eu ' não estou brincando). Ao contrário da crença popular, é muito fácil organizar o código javascript equivalente a namespaces e classes. É isso que YUI e Dojo fazem. Você pode rolar facilmente, se quiser. Acho a abordagem da YUI muito melhor e eficiente. Mas você geralmente precisa de um bom editor com suporte para trechos para compensar as convenções de nomenclatura YUI, se desejar escrever algo útil.

Vasil
fonte
3
Concordo com você sobre comandos encadeados muito longos, mas uma das melhores partes do jQuery é que ele mantém todo o Javascript fora do HTML. Você pode configurar manipuladores de eventos para todos os seus elementos sem "precisar" adicionar IDs ou eventos <whatever> em seus elementos. Como sempre, sobre o uso de qualquer ferramenta é ruim ...
Hugoware
Eu trabalhei em projetos enormes e bem organizados no jQuery. Não sei por que você acha que isso atrapalha a organização.
Marnen Laibow-Koser
7

Eu crio singletons para tudo o que realmente não preciso instanciar várias vezes na tela, aulas para todo o resto. E todos eles são colocados no mesmo espaço para nome no mesmo arquivo. Tudo é comentado e projetado com UML, diagramas de estado. O código javascript está livre de html, portanto, nenhum javascript embutido e eu costumo usar o jquery para minimizar problemas entre navegadores.

Nikola Stjelja
fonte
3
bons comentários são CHAVE - fico feliz que você tenha dito isso, para que eu não precisasse. Eu adicionaria convenções de nomenclatura consistentes, algum tipo de estratégia organizacional facilmente compreensível para variáveis ​​& amp; funções e, como você mencionou, uso criterioso de classes versus singletons.
Matt lohkamp
Não. Se você precisar de comentários, seu código geralmente não é legível o suficiente. Esforce-se para escrever um código que não precise de comentários.
Marnen Laibow-Koser
Além disso, se você precisar de diagramas de UML e de estado, isso provavelmente significa que sua arquitetura não está suficientemente clara a partir do código. Downvoting.
Marnen Laibow-Koser 15/02
1
@ Marnen Projetos bem escritos incluem comentários para descrever POR QUE, não necessariamente O QUE. O código já descreve o QUE, mas muitas vezes você precisa de algo para descrever o POR QUE. Voto a favor.
cifra
@Cypher Projetos bem escritos têm um código suficientemente claro para que você possa dizer o "porquê", não apenas o "o quê". Eu não confiaria em um comentário para me dizer o "porquê", porque não tenho garantia de que esteja sincronizado com o código. Deixe o código documentar-se.
Marnen Laibow-Koser
6

No meu último projeto - Viajeros.com - usei uma combinação de várias técnicas. Eu não saberia como organizar um aplicativo da Web - Viajeros é um site de rede social para viajantes com seções bem definidas, por isso é fácil separar o código para cada área.

Uso simulação de namespace e carregamento lento de módulos de acordo com a seção do site. Em cada carregamento de página, declaro um objeto "vjr" e sempre carrego um conjunto de funções comuns (vjr.base.js). Então cada página HTML decide quais módulos precisam com um simples:

vjr.Required = ["vjr.gallery", "vjr.comments", "vjr.favorites"];

O Vjr.base.js obtém cada um deles compactado com zip do servidor e os executa.

vjr.include(vjr.Required);
vjr.include = function(moduleList) {
  if (!moduleList) return false;
  for (var i = 0; i < moduleList.length; i++) {
    if (moduleList[i]) {
      $.ajax({
        type: "GET", url: vjr.module2fileName(moduleList[i]), dataType: "script"
      });
    }
  }
};

Todo "módulo" possui esta estrutura:

vjr.comments = {}

vjr.comments.submitComment = function() { // do stuff }
vjr.comments.validateComment = function() { // do stuff }

// Handlers
vjr.comments.setUpUI = function() {
    // Assign handlers to screen elements
}

vjr.comments.init = function () {
  // initialize stuff
    vjr.comments.setUpUI();
}

$(document).ready(vjr.comments.init);

Dado meu conhecimento limitado de Javascript, sei que deve haver maneiras melhores de gerenciar isso, mas até agora está funcionando muito bem para nós.

Danita
fonte
6

Organizar seu código de uma maneira NameSpace centrada no Jquery pode ter a seguinte aparência ... e também não se chocará com outras APIs Javascript, como Prototype, Ext.

<script src="jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script type="text/javascript">

var AcmeJQ = jQuery.noConflict(true);
var Acme = {fn: function(){}};

(function($){

    Acme.sayHi = function()
    {
        console.log('Hello');
    };

    Acme.sayBye = function()
    {
        console.log('Good Bye');
    };
})(AcmeJQ);

// Usage
//          Acme.sayHi();
// or
// <a href="#" onclick="Acme.sayHi();">Say Hello</a>


</script>

Espero que isto ajude.

Darryl
fonte
Isso me parece um pouco de culpa da carga. jQuery.fné um ponteiro para jQuery.prototype, porque $()na verdade retorna uma nova instância da função construtora jQuery. Adicionar um 'plugin' ao jQuery significa simplesmente estender seu protótipo. Mas o que você está fazendo não é isso, e existem maneiras mais limpas de realizar a mesma coisa.
Adam Lassek
Eu acredito que ele está simplesmente criando funções estáticas. Lembro-me de vê-lo em docs do jQuery que esta forma de declarar funções estáticas é aceitável
Alex Heyd
6

O bom princípio do OO + MVC definitivamente ajudaria bastante a gerenciar um aplicativo javascript complexo.

Basicamente, estou organizando meu aplicativo e javascript para o seguinte design familiar (que existe desde os dias de programação da minha área de trabalho até a Web 2.0)

JS OO e MVC

Descrição para os valores numéricos na imagem:

  1. Widgets representando as visualizações do meu aplicativo. Isso deve ser extensível e separado, resultando em uma boa separação que o MVC tenta obter, em vez de transformar meu widget em um código espaguete (equivalente no aplicativo da web a colocar um grande bloco de Javascript diretamente em HTML). Cada widget se comunica por meio de outras pessoas ouvindo o evento gerado por outros widgets, reduzindo assim o forte acoplamento entre widgets que pode levar a um código incontrolável (lembre-se do dia de adicionar onclick em todos os lugares apontando para funções globais na tag de script? Urgh ...)
  2. Modelos de objetos que representam os dados que eu quero preencher nos widgets e passar para o servidor. Ao encapsular os dados em seu modelo, o aplicativo se torna independente de formato de dados. Por exemplo: enquanto Naturalmente em Javascript esses modelos de objetos são principalmente serializados e desserializados para JSON, se de alguma forma o servidor estiver usando XML para comunicação, tudo o que preciso mudar é alterar a camada de serialização / desserialização e não necessariamente precisar alterar todas as classes de widgets .
  3. Classes de controladores que gerenciam a lógica comercial e a comunicação com o servidor + camada de armazenamento em cache ocasionalmente. Essa camada controla o protocolo de comunicação com o servidor e coloca os dados necessários nos modelos de objetos
  4. As classes são agrupadas ordenadamente em seus namespaces correspondentes. Tenho certeza de que todos sabemos como o namespace global pode ser desagradável em Javascript.

No passado, eu separava os arquivos em seus próprios js e usava a prática comum para criar princípios de OO em Javascript. O problema que logo descobri que existem várias maneiras de escrever JS OO e não é necessariamente que todos os membros da equipe tenham a mesma abordagem. À medida que a equipe aumentava (no meu caso, mais de 15 pessoas), isso fica complicado, pois não existe uma abordagem padrão para o Javascript orientado a objetos. Ao mesmo tempo, não quero escrever minha própria estrutura e repetir parte do trabalho que, com certeza, sou mais inteligente do que resolvi.

O jQuery é incrivelmente agradável como o Javascript Framework e eu adoro isso; no entanto, à medida que o projeto aumenta, eu claramente preciso de uma estrutura adicional para o meu aplicativo Web, especialmente para facilitar a padronização da prática de OO. Depois de várias experiências, descobri que a infraestrutura YUI3 Base e Widget ( http://yuilibrary.com/yui/docs/widget/ e http://yuilibrary.com/yui/docs/base/index.html ) fornece exatamente o que eu preciso. Poucas razões pelas quais eu as uso.

  1. Ele fornece suporte a namespace. Uma necessidade real de OO e organização organizada do seu código
  2. Suporta noção de classes e objetos
  3. Ele fornece um meio padronizado para adicionar variáveis ​​de instância à sua classe
  4. Ele suporta extensão de classe ordenadamente
  5. Fornece construtor e destruidor
  6. Ele fornece vinculação de renderização e evento
  7. Possui estrutura de widget base
  8. Agora, cada widget pode se comunicar usando o modelo padrão baseado em eventos
  9. Mais importante ainda, oferece a todos os engenheiros um padrão OO para desenvolvimento de Javascript

Ao contrário de muitos pontos de vista, não tenho necessariamente que escolher entre jQuery e YUI3. Esses dois podem coexistir pacificamente. Embora o YUI3 forneça o modelo de OO necessário para meu aplicativo da web complexo, o jQuery ainda fornece à minha equipe o JS Abstraction fácil de usar, pelo qual todos gostamos e estamos familiarizados.

Usando o YUI3, eu consegui criar o padrão MVC separando classes que estendem a Base como o Modelo, classes que estendem o Widget como uma Visualização e, claro, você tem classes Controller que estão fazendo a lógica necessária e as chamadas do lado do servidor.

O widget pode se comunicar usando o modelo baseado em eventos e ouvindo o evento e executando a tarefa necessária com base na interface predefinida. Simplificando, colocar a estrutura OO + MVC em JS é uma alegria para mim.

Apenas um aviso, não trabalho para o Yahoo! e simplesmente um arquiteto que está tentando lidar com o mesmo problema colocado pela pergunta original. Eu acho que se alguém encontrar uma estrutura OO equivalente, isso também funcionaria. Principalmente, essa pergunta se aplica a outras tecnologias também. Graças a Deus por todas as pessoas que criaram os princípios OO + MVC para tornar nossos dias de programação mais gerenciáveis.

momo
fonte
5

Eu uso o gerenciamento de pacotes ( dojo.requiree dojo.provide) e o sistema de classes do Dojo ( dojo.declareque também permite uma herança múltipla simples) para modularizar todas as minhas classes / widgets em arquivos separados. Não apenas a dose mantém seu código organizado, mas também permite que você faça o carregamento lento / just in time das classes / widgets.

Justin Johnson
fonte
3

Alguns dias atrás, os caras da 37Signals lançaram um controle RTE , com uma reviravolta. Eles criaram uma biblioteca que agrupa arquivos javascript usando uma espécie de comandos pré-processador.

Eu tenho usado desde então para separar meus arquivos JS e, no final, mesclá-los como um. Dessa forma, posso separar as preocupações e, no final, ter apenas um arquivo que passa pelo cano (compactado com gzip, nada menos).

Nos seus modelos, verifique se você está no modo de desenvolvimento, inclua os arquivos separados e, se estiver em produção, inclua o final (que você terá que "construir" sozinho).

changelog
fonte
1
getsprockets.org é a ligação direta
Matt Gardner
3

Crie classes falsas e certifique-se de que qualquer coisa que possa ser lançada em uma função separada que faça sentido seja feita. Não deixe de comentar muito, e não escrever código spagghetti, mantendo tudo em seções. Por exemplo, algum código sem sentido representando meus ideais. Obviamente, na vida real, também escrevo muitas bibliotecas que abrangem basicamente sua funcionalidade.

$(function(){
    //Preload header images
    $('a.rollover').preload();

    //Create new datagrid
    var dGrid = datagrid.init({width: 5, url: 'datalist.txt', style: 'aero'});
});

var datagrid = {
    init: function(w, url, style){
        //Rendering code goes here for style / width
        //code etc

        //Fetch data in
        $.get(url, {}, function(data){
            data = data.split('\n');
            for(var i=0; i < data.length; i++){
                //fetching data
            }
        })
    },
    refresh: function(deep){
        //more functions etc.
    }
};
Dmitri Farkov
fonte
3

Use padrões de herança para organizar grandes aplicativos jQuery.

Chetan
fonte
Estou começando a usá-lo, mesmo para coisas muito pequenas / básicas, e isso realmente ajuda a manter o código limpo e flexível. Vale a pena usar mesmo para manipulações simples de JS do lado do cliente.
Chetan 29/03
Isso eu gosto e uso em meus aplicativos.
Andreas
2

Eu acho que isso está vinculado, talvez, ao DDD (Design Orientado a Domínio). O aplicativo em que estou trabalhando, apesar de não ter uma API formal, fornece dicas por meio do código do servidor (nomes de classe / arquivo, etc.). Armado com isso, criei um objeto de nível superior como um contêiner para todo o domínio do problema; em seguida, adicionei namespaces onde necessário:

var App;
(function()
{
    App = new Domain( 'test' );

    function Domain( id )
    {
        this.id = id;
        this.echo = function echo( s )
        {
            alert( s );
        }
        return this;
    }
})();

// separate file
(function(Domain)
{
    Domain.Console = new Console();

    function Console()
    {
        this.Log = function Log( s )
        {
            console.log( s );
        }
        return this;
    }
})(App);

// implementation
App.Console.Log('foo');
ken
fonte
2

Para a organização JavaScript, use o seguinte

  1. Pasta para todo o seu javascript
  2. O javascript no nível da página obtém seu próprio arquivo com o mesmo nome da página. ProductDetail.aspx seria ProductDetail.js
  3. Dentro da pasta javascript para arquivos de biblioteca, eu tenho uma pasta lib
  4. Coloque as funções da biblioteca relacionadas em uma pasta lib que você deseja usar em todo o aplicativo.
  5. O Ajax é o único javascript que movo para fora da pasta javascript e obtém sua própria pasta. Então eu adiciono duas subpastas cliente e servidor
  6. A pasta do cliente obtém todos os arquivos .js enquanto a pasta do servidor obtém todos os arquivos do lado do servidor.
Jason muito legal Webs
fonte
Bom para organização de arquivos. Eu faço isso com código. Mas no final eu compilei meu código em uma ... digamos dll. Você também precisa disso com javascript ou solicita 15 arquivos js por página.
graffic 23/08/10
Não há nada errado em solicitar 15 arquivos JS por página. Seu navegador os armazenará em cache para solicitações subsequentes de qualquer maneira.
Marnen Laibow-Koser
@ MarnenLaibow-Koser O único problema ao solicitar 15 arquivos JS em uma página é quantas solicitações HTTP o navegador pode manipular ao mesmo tempo. Agrupá-los em um arquivo permite que o navegador solicite outros arquivos necessários ao mesmo tempo.
iwasrobbed
Isso é verdade, mas após os primeiros hits, eles estarão no cache do navegador e não exigirão conexões HTTP.
Marnen Laibow-Koser 11/11
2

Eu estou usando essa coisinha. Ele fornece a diretiva 'include' para os modelos JS e HTML. Ele elimina a bagunça completamente.

https://github.com/gaperton/include.js/

$.include({
    html: "my_template.html" // include template from file...
})
.define( function( _ ){ // define module...
    _.exports = function widget( $this, a_data, a_events ){ // exporting function...
        _.html.renderTo( $this, a_data ); // which expands template inside of $this.

        $this.find( "#ok").click( a_events.on_click ); // throw event up to the caller...
        $this.find( "#refresh").click( function(){
            widget( $this, a_data, a_events ); // ...and update ourself. Yep, in that easy way.
        });
    }
});
gaperton
fonte
2

Você pode usar o jquery mx (usado no javascriptMVC), que é um conjunto de scripts que permite usar modelos, visualizações e controladores. Eu usei em um projeto e me ajudou a criar javascript estruturado, com tamanhos mínimos de script por causa da compactação. Este é um exemplo de controlador:

$.Controller.extend('Todos',{
  ".todo mouseover" : function( el, ev ) {
   el.css("backgroundColor","red")
  },
  ".todo mouseout" : function( el, ev ) {
   el.css("backgroundColor","")
  },
  ".create click" : function() {
   this.find("ol").append("<li class='todo'>New Todo</li>"); 
  }
})

new Todos($('#todos'));

Você também pode usar apenas o lado do controlador do jquerymx se não estiver interessado na exibição e nas peças do modelo.

rolnn
fonte
1

Sua pergunta é uma que me atormentou no final do ano passado. A diferença - entregar o código a novos desenvolvedores que nunca ouviram falar de métodos públicos e privados. Eu tive que construir algo simples.

O resultado final foi uma pequena estrutura (em torno de 1 KB) que converte literais de objetos em jQuery. A sintaxe é visualmente mais fácil de digitalizar e, se o seu js crescer muito, você poderá escrever consultas reutilizáveis ​​para encontrar itens como seletores usados, arquivos carregados, funções dependentes etc.

A publicação de uma pequena estrutura aqui é impraticável, por isso escrevi uma postagem no blog com exemplos (Minha primeira. Foi uma aventura!). Você pode dar uma olhada.

Para outras pessoas aqui com alguns minutos para conferir, eu gostaria muito de receber feedback!

O FireFox é recomendado, pois suporta toSource () para o exemplo de consulta de objeto.

Felicidades!

Adão

Adam
fonte
0

Uso um script personalizado inspirado no comportamento de Ben Nolan (infelizmente não consigo mais encontrar um link atual para isso) para armazenar a maioria dos meus manipuladores de eventos. Esses manipuladores de eventos são acionados pelos elementos className ou Id, por exemplo. Exemplo:

Behaviour.register({ 
    'a.delete-post': function(element) {
        element.observe('click', function(event) { ... });
    },

    'a.anotherlink': function(element) {
        element.observe('click', function(event) { ... });
    }

});

Eu gosto de incluir a maioria das minhas bibliotecas Javascript em tempo real, exceto as que contêm comportamento global. Eu uso o auxiliar de espaço reservado headScript () do Zend Framework para isso, mas você também pode usar o javascript para carregar outros scripts dinamicamente com o Ajile, por exemplo.

Aron Rotteveel
fonte
Não é isso que você estava procurando? koders.com/javascript/…
DOK
Sim, é esse! :) Parece que o código por trás do link é bem mais recente que a versão em que fui inspirada. Obrigado pelo seu esforço!
Aron Rotteveel
0

Você não menciona qual é o seu idioma no servidor. Ou, mais pertinentemente, qual estrutura você está usando - se houver - no lado do servidor.

IME, eu organizo as coisas no lado do servidor e deixo tudo passar para a página da web. A estrutura recebe a tarefa de organizar não apenas JS que todas as páginas precisam carregar, mas também fragmentos JS que funcionam com a marcação gerada. Esses fragmentos geralmente não são emitidos mais de uma vez - e é por isso que eles são abstraídos da estrutura para que o código cuide desse problema. :-)

Para páginas finais que precisam emitir seu próprio JS, geralmente acho que há uma estrutura lógica na marcação gerada. Tais JS localizados geralmente podem ser montados no início e / ou no final dessa estrutura.

Observe que nada disso o impede de escrever JavaScript eficiente! :-)

staticsan
fonte
0

Preguiçoso Carregue o código que você precisa sob demanda. O Google faz algo assim com seu google.loader

Brig Lamoreaux
fonte