12

Related to the answer https://stackoverflow.com/a/10619477/1076753 to cleate an element is better to use

$("<div>", {id: "foo", class: "a"});

or

$("<div />", {id: "foo", class: "a"});

They both works, but which is better or correct to use?

The official API Documentation says that to ensure cross-platform compatibility, the snippet must be well-formed. Tags that can contain other elements should be paired with a closing tag:

$( "<a href='http://jquery.com'></a>" );

while Tags that cannot contain elements may be quick-closed or not:

$( "<img>" );
$( "<input>" );

So, at the end it's wrong to use one of the first two options for a div?

Community
  • 1
  • 1
Vixed
  • 3,429
  • 5
  • 37
  • 68
  • Coding is hard enough to make it unnecessarily depend in browser recovery techniques for HTML tag soup. Just feed it with valid HTML always and save yourself future trouble. – Álvaro González Feb 15 '16 at 15:27
  • @ÁlvaroGonzález — Neither `
    ` not `
    ` is valid HTML (self-closing tag syntax is an XML feature not an HTML feature and `
    ` has a mandatory end tag).
    – Quentin Feb 15 '16 at 15:29
  • @Quentin, that's why I wrote also xhtml in the question tags. – Vixed Feb 15 '16 at 15:31
  • Sorry @charlietfl but I can't see something like this on http://api.jquery.com/jquery/ – Vixed Feb 15 '16 at 16:03
  • Understandable that all cases aren't covered in API but it is valid – charlietfl Feb 15 '16 at 16:05
  • 2
    I have read all the comments and I'm left wondering why nobody has explained that the better way is `$("
    ", {id: "foo", class: "a"});` to keep in spirit with the official API documentation.
    – Mr Lister Feb 15 '16 at 19:09
  • @MrLister your answer can be also `$("
    ")` but I need to know why and what's the difference with others method.
    – Vixed Feb 17 '16 at 18:37
  • This post may help U [Preferred way of creating element in Jquery](http://stackoverflow.com/questions/10619445/the-prefered-way-of-creating-a-new-element-with-jquery) –  Feb 18 '16 at 10:55
  • Clearly the [**documentation**](http://api.jquery.com/jquery/#entry-examples-1) uses the syntax `$('
    ')` which is probably the most jQuery'ish way of creating an element, as for what is *"better"*, whatever floats your goat, probably. It should be especially noted that `class` is a reserved keyword in javascript, and shouls ***always*** be quoted when used in jQuery, or replaced with `className`.
    – adeneo Feb 28 '16 at 22:42

4 Answers4

7

If you go solely by metrics that can be easily measured: The first is better because it is 2 bytes shorter.

Once you start accounting for readability and other less tangible considerations, it becomes largely a matter of opinion.

So, at the end it's wrong to use one of the first two options for a div?

No, that section only applies "If the HTML is more complex than a single tag without attributes"

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • Ok, but what about xHtml? – Vixed Feb 15 '16 at 16:04
  • @Vixed — It's irrelevant (for those examples, see the quote from the docs in my answer) – Quentin Feb 15 '16 at 16:07
  • @Vixed browser takes care of it when nodes are created. You are only telling jQuery what node structure/attributes/properties will be – charlietfl Feb 15 '16 at 16:08
  • I knew, but must there be a difference between **div** and **div/** – Vixed Feb 15 '16 at 16:09
  • @Vixed — Why must there be a difference? It uses [this regex](https://github.com/jquery/jquery/blob/d92310050ca7bf0b33825d64e052f9a8809c3e9e/test/data/jquery-1.9.1.js#L82), it doesn't care if there is a space or a `/` before the `>`. – Quentin Feb 15 '16 at 16:10
  • The information I give it's different, so I suppose that will be elaborate in a different way. I mean I'm not talking with a person, but with a computer. – Vixed Feb 15 '16 at 16:14
  • 2
    You're talking to a function which is designed to be called by web developers, who have a long history of having web browsers perform enormous amounts of error recovery so they don't need to learn how HTML actually works. What's more, the *information* you are giving is exactly the same, you're just using a slightly different combination of characters to give it. – Quentin Feb 15 '16 at 16:15
  • 2
    @Vixed you aren't recognizing that under the hood what you pass to `$('')` it is parsed then turned into an actual dom element which is why it doesn't need closing tags. Look at how `parseHtml()` handles a single element internally...it uses `document.createElement` ... http://james.padolsey.com/jquery/#v=1.11.2&fn=jQuery.parseHTML – charlietfl Feb 15 '16 at 16:19
  • So, @charlietfl it's just like Quentin says... question of bytes. I knew that can seems stupid, but I'll like to hear more about that, so I'll start a bounty asap. – Vixed Feb 15 '16 at 16:34
  • @Vixed — What's to know? Before compression gets involved, and if we aren't talking about the higher numbered UTF-8 characters, one character is one byte. A space is one byte. A slash is one byte. – Quentin Feb 15 '16 at 16:35
  • I would like to know which one and why, spends more time to load! I knew we are talking about two bytes like you said, but do I need it? and if not why? – Vixed Feb 15 '16 at 16:39
  • 1
    @Vixed — The one with two more characters in it needs two more bytes so will take an insignificantly longer time to load it. No you don't need those two bytes. You don't need them, because, as has been said repeatedly, they will be ignored. – Quentin Feb 15 '16 at 16:40
  • 1
    @Vixed why start a bounty when you can do this yourself in a perf test? Anyone answering the bounty will either guess (likely get a few of those) ... or provide you a perf test that you can do yourself – charlietfl Feb 15 '16 at 16:58
2

taking a look into the jQuery library, the following is the relevant section from v2.2.0 line 2827.

init = jQuery.fn.init = function(selector, context, root) {
    var match, elem;

    // HANDLE: $(""), $(null), $(undefined), $(false)
    if (!selector) {
      return this;
    }

    // Method init() accepts an alternate rootjQuery
    // so migrate can support jQuery.sub (gh-2101)
    root = root || rootjQuery;

    // Handle HTML strings
    if (typeof selector === "string") {
      if (selector[0] === "<" &&
        selector[selector.length - 1] === ">" &&
        selector.length >= 3) {

        // Assume that strings that start and end with <> are HTML and skip the regex check
        match = [null, selector, null];

      } else {
        match = rquickExpr.exec(selector);
      }

      // Match html or make sure no context is specified for #id
      if (match && (match[1] || !context)) {

        // HANDLE: $(html) -> $(array)
        if (match[1]) {
          context = context instanceof jQuery ? context[0] : context;

          // Option to run scripts is true for back-compat
          // Intentionally let the error be thrown if parseHTML is not present
          jQuery.merge(this, jQuery.parseHTML(
            match[1],
            context && context.nodeType ? context.ownerDocument || context : document,
            true
          ));

          // HANDLE: $(html, props)
          if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {
            for (match in context) {

              // Properties of context are called as methods if possible
              if (jQuery.isFunction(this[match])) {
                this[match](context[match]);

                // ...and otherwise set as attributes
              } else {
                this.attr(match, context[match]);
              }
            }
          }

          return this;

You will see that it checks if the selector is a string, and if it does then see's if it starts with < and ends with >.

if (typeof selector === "string") {
  if (selector[0] === "<" &&
    selector[selector.length - 1] === ">" &&
    selector.length >= 3) {

Then, having in mind the regex rsingleTag being:-

var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ );

Which matches both "<div>" and "<div />", returning div as group[1].

The parseHTML uses that to return a div element, in the merge:-

jQuery.parseHTML = function( data, context, keepScripts ) {

    ...

    var parsed = rsingleTag.exec( data );

    // Single tag
    if ( parsed ) {
        return [ context.createElement( parsed[ 1 ] ) ];
    }

then using the regex again, and context as your object for setting the properties:-

// HANDLE: $(html, props)
if (rsingleTag.test(match[1]) && jQuery.isPlainObject(context)) {

it for's over each property setting with this.attr(match, context[match]);

So, at the end it's wrong to use one of the first two options for a div?

As above shows, its personal preference. Both work the same.

BenG
  • 14,826
  • 5
  • 45
  • 60
  • So it's just a bytes question? – Vixed Feb 20 '16 at 16:21
  • yes. 2 extra, 1 for a space and 1 for /. Not that would make any real difference in performance. – BenG Feb 20 '16 at 16:25
  • @Vixed — As I said last week. – Quentin Feb 20 '16 at 16:43
  • @Vixed — Not really. This just shows the working of unpicking the code (which I linked to in a comment) instead of summarizing it. – Quentin Feb 20 '16 at 16:46
  • @Quentin I saw, that's why I will accept you answer, but I can't assign the bounty to you. By the way, I thought to assign the bounty to BenG but in this kind of climate, I'll let the vote decides. – Vixed Feb 20 '16 at 16:51
0

From jQuerys website:

It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler..

Notice that it doesn't mention HTML generation.

JavaScript provides the document.createElement method. jQuery utilizes this method if HTML-like string is passed as the selector.

The jQuery entry point ($(whatEverIFeelLikeDoingToday)) type checks the selector for string, node or function, then handles the request accordingly. If the argument is string, it then passes through +/- 60 lines of code (Am I HTML? Am I a selector, am I an ID, am I a class?). After the HTML-like string is identified, it is then passed to another function (additional function calls) to be generated -therefore slow (see benchmark below). In fact, it doesn't add much value to the process, aside from uniformity, just slows it down.

I've found the best practice to be: not using jQuery for rather simple tasks (i.e. node creation) -wherever practice, eliminate the obstacles in it's way.

var div = document.createElement('div');
div.setAttribute("id", "foo");
div.setAttribute("class", "a");
div = $(div);

Notice the significant performance increase in this benchmark. (Just about 4x faster in Chrome). This solution is Faster than the two described above and inherently Cross platform.

I don't think that the argument for less bytes -vs faster execution time is in the scope of this thread. However, assuming you are minifying your code, I will throw out a the practical example of looping through an array to generate html rows for a table. Bytes aren't the problem, you only needed to load the script once -execution is what bogs you down.

jtrumbull
  • 818
  • 9
  • 19
  • I've worked with some that have quite strong feelings against doing what you did here: `div = $(div)`. You're ultimately changing the type of "div" through the assignment. That said I don't really like seeing $varName either... – jKlaus Feb 24 '16 at 14:42
0

With better or correct use in your case it depends on how frequently this code will appear in your page. @Quentin is correct in that there is only a two byte difference between the first and second option. Now if the code only appears a few times in the whole page then realistically unless you are recording a large amount of traffic on your server you will not see a significant difference between the two, on the other hand if you are running a medium to high traffic site or will be having a large number of instances of this javascript appearing on your page then the best option would be to go with option one as it is two bytes smaller and over a larger page with many instances of this code you will find measurable savings in the byte size of the page.

As for well formed tags for cross platform compatibility both the first and second options will result in the exact same end result in the browser so in your use case compatibility will not be affected by either option.

Based on these points I would suggest using option one as it provides the two byte advantage over option two, that is effectively the only difference between the two options in your use case.

Chris Rutherfurd
  • 1,617
  • 1
  • 15
  • 32