Quando usar o Vanilla JavaScript vs. jQuery?

238

Eu notei enquanto monitorava / tentava responder perguntas comuns sobre jQuery, que existem certas práticas usando javascript, em vez de jQuery, que permitem escrever menos e fazer ... bem, a mesma quantidade. E também pode gerar benefícios de desempenho.

Um exemplo específico

$(this) vs this

Dentro de um evento click que faz referência ao ID dos objetos clicados

jQuery

$(this).attr("id");

Javascript

this.id;

Existem outras práticas comuns como esta? Onde certas operações Javascript poderiam ser realizadas com mais facilidade, sem incluir o jQuery na mistura. Ou este é um caso raro? (de um "atalho" do jQuery que realmente requer mais código)

Edição: Embora eu aprecie as respostas sobre jQuery vs. desempenho de javascript simples, na verdade, estou procurando respostas muito mais quantitativas. Ao usar o jQuery , instâncias em que seria realmente melhor (legibilidade / compacidade) usar javascript simples em vez de usar $(). Além do exemplo que dei na minha pergunta original.

jondavidjohn
fonte
Não sei se entendi a pergunta. Você estava procurando opiniões sobre os méritos do uso de código de biblioteca ou estava procurando técnicas adicionais compatíveis com outros navegadores não-jQuery semelhantes this.id?
usar o seguinte comando
1
pelas respostas, parece que todo mundo está tomando essa pergunta como filosófica, como eu pretendia que fosse muito quantitativa, para compilar quase uma lista de instâncias como a que eu descrevi que são práticas comuns (mal).
precisa saber é o seguinte

Respostas:

207
  • this.id (como você sabe)
  • this.value(na maioria dos tipos de entrada. apenas os problemas que conheço são o IE quando a <select>não possui valuepropriedades definidas em seus <option>elementos ou entradas de rádio no Safari.)
  • this.className para obter ou definir uma propriedade "classe" inteira
  • this.selectedIndexcontra a <select>para obter o índice selecionado
  • this.optionscontra a <select>para obter uma lista de <option>elementos
  • this.textcontra um <option>para obter o seu conteúdo de texto
  • this.rowscontra a <table>para obter uma coleção de <tr>elementos
  • this.cells contra um <tr> para obter suas células (td & th)
  • this.parentNode obter um pai direto
  • this.checkedpara obter o estado verificado de um checkbox Obrigado @ Tim Down
  • this.selectedpara obter o estado selecionado de option Obrigado @ Tim Down
  • this.disabledpara obter o estado desabilitado de um input Obrigado @ Tim Down
  • this.readOnlypara obter o estado readOnly de um input agradecimento @ Tim Down
  • this.hrefcontra um <a>elemento para obter a suahref
  • this.hostnamecontra um <a>elemento para obter o domínio de seuhref
  • this.pathnamecontra um <a>elemento para obter o caminho de suahref
  • this.searchcontra um <a>elemento para obter a string de consulta de seuhref
  • this.src contra um elemento em que é válido ter um src

... Eu acho que você entendeu.

Haverá momentos em que o desempenho é crucial. Por exemplo, se você estiver executando algo repetidamente várias vezes, convém abandonar o jQuery.

Em geral, você pode substituir:

$(el).attr('someName');

com:

Acima estava mal formulado. getAttributenão é um substituto, mas recupera o valor de um atributo enviado do servidor e seu correspondente setAttributeo definirá. Necessário em alguns casos.

As frases abaixo cobriram isso. Veja esta resposta para um melhor tratamento.

el.getAttribute('someName');

... para acessar um atributo diretamente. Observe que os atributos não são iguais às propriedades (embora eles se espelhem algumas vezes). Claro que tem setAttributetambém.

Digamos que você teve uma situação em que recebeu uma página na qual precisa desembrulhar todas as tags de um determinado tipo. É curto e fácil com o jQuery:

$('span').unwrap();  // unwrap all span elements

Mas, se houver muitos, convém fazer uma pequena API DOM nativa:

var spans = document.getElementsByTagName('span');

while( spans[0] ) {
    var parent = spans[0].parentNode;
    while( spans[0].firstChild ) {
        parent.insertBefore( spans[0].firstChild, spans[0]);
    }
    parent.removeChild( spans[0] );
}

Esse código é bem curto, tem um desempenho melhor que a versão do jQuery e pode ser facilmente transformado em uma função reutilizável na sua biblioteca pessoal.

Pode parecer que eu tenho um loop infinito com o externo whilepor causa de while(spans[0]), mas como estamos lidando com uma "lista ao vivo", ela é atualizada quando fazemos o parent.removeChild(span[0]);. Esse é um recurso bastante interessante que perdemos ao trabalhar com um Array (ou um objeto semelhante ao Array).

user113716
fonte
2
nice ... então, na maioria das vezes, gira em torno da palavra-chave this ser involuntariamente envolvida em um objeto jQuery.
precisa saber é o seguinte
1
@jondavidjohn: Bem, existem algumas correções que são boas em alguns casos, como this.valueonde existem algumas peculiaridades do navegador em certos casos. Tudo depende da sua necessidade. Existem muitas técnicas agradáveis ​​que são fáceis sem o jQuery, especialmente quando o desempenho é crucial. Vou tentar pensar em mais.
precisa saber é o seguinte
3
Eu estava prestes a escrever uma resposta, mas adicionarei sugestões para a sua. Geralmente, attr()é muito utilizado em excesso. Se você está lidando apenas com um elemento, raramente precisará attr(). Dois dos meus favoritos são a confusão em torno da checkedpropriedade de caixas de seleção (todos os tipos de fórmulas místicas ao redor que um: $(this).attr("checked", "checked"), $(this).is(":checked")etc.) e semelhante a selectedpropriedade de <option>elementos.
Tim baixo
1
Aaargh, @patrick, noooo: você recomendou getAttribute(). Você quase nunca precisa disso : está quebrado no IE, nem sempre reflete o estado atual e não é o que o jQuery faz de qualquer maneira. Basta usar propriedades. stackoverflow.com/questions/4456231/…
Tim Down
1
Eu estava usando JS por tanto tempo e não sabia sobre className, thx.
IAdapter
60

A resposta correta é que você sempre aplicará uma penalidade no desempenho ao usar o jQuery em vez do JavaScript nativo "comum". Isso porque o jQuery é uma biblioteca JavaScript. Não é uma nova versão sofisticada do JavaScript.

A razão pela qual o jQuery é poderoso é que ele torna algumas coisas excessivamente entediantes em uma situação entre navegadores (o AJAX é um dos melhores exemplos) e suaviza as inconsistências entre a miríade de navegadores disponíveis e fornece uma API consistente. Também facilita com facilidade conceitos como encadeamento, iteração implícita etc., para simplificar o trabalho em grupos de elementos juntos.

Aprender o jQuery não substitui o aprendizado de JavaScript. Você deve ter uma base firme no último, para poder apreciar completamente o fato de saber que o primeiro está facilitando para você.

- Editado para incluir comentários -

Como os comentários são rápidos em apontar (e eu concordo com 100%), as declarações acima se referem ao código de benchmarking. Uma solução JavaScript 'nativa' (supondo que esteja bem escrita) superará uma solução jQuery que realiza a mesma coisa em quase todos os casos (eu adoraria ver um exemplo em contrário). O jQuery acelera o tempo de desenvolvimento, o que é um benefício significativo que não pretendo subestimar. Ele facilita o código de fácil leitura, fácil de seguir, que é mais do que alguns desenvolvedores são capazes de criar por conta própria.

Na minha opinião, a resposta depende do que você está tentando alcançar. Se, como presumi com base em sua referência aos benefícios de desempenho, você está buscando a melhor velocidade possível para seu aplicativo, o uso do jQuery introduz uma sobrecarga toda vez que você liga $(). Se você busca legibilidade, consistência, compatibilidade entre navegadores, etc., certamente existem razões para favorecer o jQuery em vez de JavaScript 'nativo'.

gddc
fonte
8
Eu adoraria ver um exemplo de uma situação em que o jQuery pode superar uma implementação em JS puro. Não importa o que você faça, se você estiver usando jQuery (ou qualquer outra biblioteca), você terá uma sobrecarga de funções inevitável. Não há como se afastar da sobrecarga (embora menor) gerada pela chamada $(). Se você não fizer essa ligação, economiza tempo.
Gddc
16
Uma solução caseira mal escrita provavelmente seria mais lenta. A equipe do jQuery executou algum JavaScript altamente eficiente no pacote. Veja a resposta do @ Freelancer.
Stephen
3
Uma solução mal escrita sempre será uma solução mal escrita, e isso não é culpa do idioma. Isso não altera o fato de que a biblioteca incorre em sobrecarga que uma função 'nativa' poderia evitar se bem pensada.
Gddc
11
@gddc Eu acho que o melhor exemplo onde jQuery "Supera" (leia-se fora da caixa de benchmark) pura JS está em reduzir o tempo dev (que é um enorme valor sábio business-) e simplificando a experimentação
Ben
13
Tudo o que você escreveu é verdadeiro, mas você deixou o que o @Ben observa acima. O jQuery torna o desenvolvedor mais rápido e mais robusto. Veja esta implementação KillClass () que escrevi há muitos anos e que usei muito. Você sabe o que? Está quebrado para certos casos extremos. Código ruim é código ruim e código errado é código errado, mas o uso do jQuery geralmente faz com que o desenvolvedor escreva um código melhor e mais correto. Na maioria das vezes, os computadores são rápidos o suficiente; são desenvolvedores que precisam da ajuda.
Phrogz
38

Existe uma estrutura chamada ... oh adivinhem? Vanilla JS. Espero que você entenda a piada ...: D Ele sacrifica a legibilidade do código pelo desempenho ... Comparando-o jQueryabaixo, você pode ver que a recuperação de um DOMelemento IDé quase 35 vezes mais rápida. :)

Portanto, se você quer desempenho, é melhor tentar o Vanilla JS e tirar suas próprias conclusões. Talvez você não tenha o JavaScript travando a GUI do navegador / bloqueando o encadeamento da interface do usuário durante código intensivo, como dentro de um forloop.

Vanilla JS é uma estrutura rápida, leve e multiplataforma para criar aplicativos JavaScript incríveis e poderosos.

Na página inicial, há algumas comparações de desempenho:

insira a descrição da imagem aqui

Leniel Macaferi
fonte
1
@Leniel Macaferi Oh cara, eu amei essa resposta! Não percebi que o desempenho entre a baunilha e outras estruturas poderia fazer tanta diferença! Enfim Hall da fama por esta resposta !! PS: Você também criou o site?
Steve Steve
17

Já existe uma resposta aceita, mas acredito que nenhuma resposta digitada diretamente aqui pode ser abrangente em sua lista de métodos / atributos nativos de javascript que praticamente garantiram o suporte entre navegadores. Para isso, posso redirecioná-lo para o modo quirks:

http://www.quirksmode.org/compatibility.html

Talvez seja a lista mais abrangente do que funciona e do que não funciona em qual navegador em nenhum lugar. Preste atenção especial à seção DOM. É muito para ler, mas o objetivo não é ler tudo, mas usá-lo como referência.

Quando comecei a escrever seriamente aplicativos da Web, imprimi todas as tabelas do DOM e as pendurei na parede, para que eu saiba rapidamente o que é seguro de usar e o que requer hacks. Hoje em dia eu apenas procuro algo comoquirksmode parentNode compatibility quando tenho dúvidas.

Como qualquer outra coisa, o julgamento é principalmente uma questão de experiência. Eu realmente não recomendo que você leia o site inteiro e memorize todos os problemas para descobrir quando usar o jQuery e quando usar o JS simples. Apenas esteja ciente da lista. É fácil o suficiente para pesquisar. Com o tempo, você desenvolverá um instinto de quando JS simples é preferível.


PS: PPK (o autor do site) também tem um livro muito legal que eu recomendo a leitura

slebetman
fonte
14

Quando:

  1. você sabe que há suporte inflexível entre navegadores para o que está fazendo e
  2. não é significativamente mais código para digitar, e
  3. não é significativamente menos legível e
  4. você está razoavelmente confiante de que o jQuery não escolherá implementações diferentes com base no navegador para obter melhor desempenho;

use JavaScript. Caso contrário, use jQuery (se você puder).

Editar : Esta resposta se aplica tanto ao optar por usar o jQuery de maneira geral, quanto ao deixá-lo de fora, além de optar por usar o vanilla JS dentro do jQuery. Escolher entre attr('id')e .idinclinar - se a favor do JS, enquanto escolher entre removeClass('foo')versus .className = .className.replace( new Regexp("(?:^|\\s+)"+foo+"(?:\\s+|$)",'g'), '' )inclina-se a favor do jQuery.

Phrogz
fonte
3
Acho que o OP pretende usar o jQuery, mas se pergunta onde e quando usar o JavaScript nativo dentro de seus métodos do jQuery.
Stephen
.classList.remove('foo')parece funcionar bem em navegadores mais novos
Tyilo
3
@Tyilo classList.remove faz parte do HTML5 ClassList API que não está implementado no IE9 por exemplo caniuse.com/#feat=classlist
corbacho
13

As respostas de outras pessoas se concentraram na ampla questão de "jQuery vs. JS simples". A julgar pelo seu OP, acho que você estava simplesmente se perguntando quando é melhor usar o vanilla JS se você já escolheu usar o jQuery. Seu exemplo é um exemplo perfeito de quando você deve usar o vanilla JS:

$(this).attr('id');

É mais lento e (na minha opinião) menos legível do que:

this.id.

É mais lento porque você precisa girar um novo objeto JS apenas para recuperar o atributo da maneira jQuery. Agora, se você estiver usando $(this)para executar outras operações, armazene esse objeto jQuery em uma variável e opere com isso. No entanto, já deparei com muitas situações em que só preciso de um atributo do elemento (como idou src).

Existem outras práticas comuns como esta? Onde certas operações Javascript poderiam ser realizadas com mais facilidade, sem incluir o jQuery na mistura. Ou este é um caso raro? (de um "atalho" do jQuery que realmente requer mais código)

Eu acho que o caso mais comum é o que você descreve em sua postagem; pessoas envolvidas $(this)em um objeto jQuery desnecessariamente. Vejo isso com mais frequência com ide value(em vez de usar$(this).val() ).

Edit: Aqui está um artigo que explica por que usar o jQuery no diretórioattr() é mais lento. Confissão: roubou da tag wiki, mas acho que vale a pena mencionar a pergunta.

Edite novamente: Dadas as implicações de legibilidade / desempenho de apenas acessar diretamente os atributos, eu diria que uma boa regra é provavelmente tentar usar this.<attributename>quando possível. Provavelmente, existem alguns casos em que isso não funciona por causa de inconsistências no navegador, mas provavelmente é melhor tentar primeiro e recorrer ao jQuery se não funcionar.

Andrew Whitaker
fonte
hah, obrigado por ler a pergunta;) ... então essa é a exceção mais ampla?
precisa saber é o seguinte
@jondavidjohn: Honestamente, hesito em fazer essa ligação. Acho que sim, geralmente é vantajoso usar o jQuery devido a preocupações entre navegadores. Existem outros exemplos, como this.style.display = 'none'. Isso é melhor que $(this).hide()? Eu diria que o último é mais legível, mas o primeiro é provavelmente mais rápido. Não é difícil fazer algumas experiências para verificar se determinadas ações funcionarão nos navegadores sem o jQuery - normalmente é o que eu faço antes de agrupar um elemento em um objeto jQuery para executar uma operação.
Andrew Whitaker
10

Se você está mais preocupado com o desempenho, seu exemplo principal atinge a unha na cabeça. Invocar o jQuery desnecessariamente ou de forma redundante é, IMHO, a segunda principal causa de desempenho lento (sendo o primeiro o mau deslocamento do DOM).

Não é realmente um exemplo do que você está procurando, mas vejo isso com tanta frequência que é preciso mencionar: Uma das melhores maneiras de acelerar o desempenho de seus scripts jQuery é armazenar em cache objetos jQuery e / ou usar encadeamento:

// poor
$(this).animate({'opacity':'0'}, function() { $(this).remove(); });

// excellent
var element = $(this);
element.animate({'opacity':'0'}, function() { element.remove(); });

// poor
$('.something').load('url');
$('.something').show();

// excellent
var something = $('#container').children('p.something');
something.load('url').show();
Stephen
fonte
interessante ... essa separação de instanciação e ação var realmente leva a ganhos de desempenho de processamento? ou apenas permite a ação para executar por conta própria (tornando-o menos sobrecarregados eu acho ...)
jondavidjohn
1
Certamente leva a ganhos de desempenho, mas somente se você reutilizar o elemento selecionado. Portanto, no último caso var something, eu realmente não precisei armazenar em cache o objeto jQuery (desde que usei encadeamento), mas faço isso de qualquer maneira por hábito.
Stephen
2
Por outro lado, tome o mesmo exemplo. Chamar $('.something')duas vezes significa que o jQuery deve percorrer o DOM duas vezes procurando todos os elementos com esse seletor.
Stephen
2
No caso do primeiro exemplo, o armazenamento em cache $(this)reduz as chamadas para a função jQuery. Isso lhe dará o maior ganho em um cenário de loop.
Stephen
2
@ Alnitak Observe que elementé igual a $(this). Isso não contém vários elementos.
Stephen
8

Eu descobri que certamente há sobreposição entre JS e JQ. O código que você mostrou é um bom exemplo disso. Francamente, o melhor motivo para usar o JQ sobre JS é simplesmente a compatibilidade do navegador. Eu sempre me inclino para o JQ, mesmo que eu possa realizar algo em JS.

Dutchie432
fonte
8
Seria uma maravilha se não houvesse sobreposição, porque o JQuery é JavaScript.
quer
6

Essa é minha opinião pessoal, mas como o jQuery é JavaScript de qualquer maneira, acho que teoricamente ele não pode ter um desempenho melhor do que o vanilla JS.

Mas, na prática, ele pode ter um desempenho melhor que o JS escrito à mão, pois o código escrito à mão pode não ser tão eficiente quanto o jQuery.

Conclusão - para coisas menores, costumo usar baunilha JS, para projetos intensivos em JS, gosto de usar jQuery e não reinventar a roda - também é mais produtivo.

CodeVirtuoso
fonte
1
Existem muitos exemplos em que as bibliotecas superam o JS vanilla. Muitos dos métodos de protótipo internos do JS são mal escritos, ao que parece.
Estatísticas de aprendizado por exemplo
3

A lista de propriedades ao vivo da primeira resposta de this como elemento DOM está bastante completa.

Você também pode achar interessante conhecer alguns outros.

Quando este é o documento:

  • this.formspara obter um HTMLCollectiondos formulários de documentos atuais,
  • this.anchorspara obter um HTMLCollectionde toda a HTMLAnchorElementscom namesendo set,
  • this.linkspara obter um HTMLCollectionde todos os HTMLAnchorElements hrefsendo definido,
  • this.imagespara obter um HTMLCollectionde todos os HTMLImageElements
  • e o mesmo com os miniaplicativos obsoletos this.applets

Quando você trabalha document.forms, document.forms[formNameOrId]obtém o formulário chamado ou identificado.

Quando este é um formulário:

  • this[inputNameOrId] para obter o campo chamado ou identificado

Quando este é o campo do formulário:

  • this.type para obter o tipo de campo

Ao aprender os seletores de jQuery, geralmente ignoramos as propriedades dos elementos HTML já existentes, que são tão rápidos de acessar.

lib3d
fonte
As propriedades que você mencionou são definidas na especificação HTML do DOM Nível 2 e são amplamente suportadas. document.embedse document.pluginstambém são amplamente suportados (DOM 0). document.scriptstambém é uma coleção conveniente, definida na especificação HTML5 e amplamente suportada (e Firefox 9+ ).
23413 Rob Rob
@ Robw Portanto, a lista agora pode estar completa e definitivamente útil e rápida. Obrigado;)
lib3d
2

Como sempre, estou chegando atrasado a esta festa.

Não foi a funcionalidade extra que me fez decidir usar o jQuery, por mais atraente que fosse. Afinal, nada impede você de escrever suas próprias funções.

Era o fato de que havia muitos truques para aprender ao modificar o DOM para evitar vazamentos de memória (estou falando sobre você, IE). Ter um recurso central que gerenciou todos esses tipos de problemas para mim, escritos por pessoas que eram codificadores JS muito melhores do que eu jamais serei, que estavam sendo continuamente revisados, revisados ​​e testados, foi enviado por Deus.

Eu acho que esse tipo de cai sob o argumento de suporte / abstração entre navegadores.

E é claro que o jQuery não exclui o uso de JS direto quando você precisava. Eu sempre senti que os dois pareciam trabalhar perfeitamente juntos.

Obviamente, se o seu navegador não é suportado pelo jQuery ou você oferece suporte a um ambiente de baixo custo (telefone antigo?), Um arquivo .js grande pode ser um problema. Lembra quando o jQuery costumava ser pequeno?

Mas normalmente a diferença de desempenho não é uma questão de preocupação. Só precisa ser rápido o suficiente. Com o Gigahertz de ciclos de CPU desperdiçando a cada segundo, estou mais preocupado com o desempenho dos meus codificadores, os únicos recursos de desenvolvimento que não dobram de energia a cada 18 meses.

Dito isto, atualmente estou analisando problemas de acessibilidade e, aparentemente, .innerHTML é um pouco não, não com isso. É claro que o jQuery depende do .innerHTML, agora estou procurando uma estrutura que dependa dos métodos um tanto tediosos que são permitidos. E posso imaginar que essa estrutura funcione mais lentamente que o jQuery, mas, desde que funcione bem o suficiente, ficarei feliz.

Swanny
fonte
2

Aqui está uma resposta não técnica - muitos trabalhos podem não permitir determinadas bibliotecas, como o jQuery.

De fato, o Google não permite o jQuery em nenhum código (nem o React, porque é de propriedade do Facebook), que você talvez não soubesse até o entrevistador dizer "Desculpe, mas você não pode usar o jQuery, ele não está ativado a lista aprovada na XYZ Corporation ". O Vanilla JavaScript funciona absolutamente em todos os lugares, sempre, e nunca lhe dará esse problema. Se você depende de uma biblioteca, sim, obtém velocidade e facilidade, mas perde a universalidade.

Além disso, falando em entrevistas, a outra desvantagem é que, se você diz que precisa usar uma biblioteca para resolver um problema de JavaScript durante um questionário de código, parece que você realmente não entende o problema, o que parece meio ruim. Considerando que, se você resolvê-lo em JavaScript de baunilha bruto, isso demonstra que você realmente entende e pode resolver todas as partes de qualquer problema que eles apresentem à sua frente.

Jack Connor
fonte
1

$(this) é diferente de this :

Ao usar, $(this)você garante que o protótipo do jQuery esteja sendo passado para o objeto.

John Green
fonte