0

I stumbled upon this piece of code of a friend and from my knowledge and testing of JS, especially jQuery, this caching is not necessary:

   jQuery('.loggedin.bookmark, .loggedin.bookmarked').on('click', function(e) {
        e.preventDefault();
        var $this = jQuery(this),
            id = $this.data('id');
        if($this.hasClass('bookmarked') ) {
            //remove bookmark
            jQuery.post(MyAjax.ajaxurl, {
                action : 'bookmark-remove',
                post_id : id
            },
            function() {
                //we sent the data, now we update the button bg color and tooltip
                $this.tooltip("destroy");
                $this.data('title', 'BOOKMARK');
                $this.removeClass('bookmarked');
                $this.addClass('bookmark');
            });
        }
        else {
            //add bookmark
            jQuery.post(MyAjax.ajaxurl, {
                action : 'bookmark-submit',
                post_id : id
            },
            function() {
                //we sent the data, now we update the button bg color and tooltip
                $this.tooltip("destroy");
                $this.data('title', 'BOOKMARKED');
                $this.removeClass('bookmark');
                $this.addClass('bookmarked');
            });
        }
    });

When you do jQuery('.selector-here).on('click', function(e) {, the this context is the element itself. As such, my opinion from running tests before is that there's no need to cache it with var $this = jQuery(this); since it's already cached by the function's "parameters".

My tests also show no increase in performance and a lean towards the non-$this method working faster, clearly, this is just for one line of code:

<html>
<head>
</head>
<body>

<div id="basic-thing">
    <p class="click-me"> Hey there!</p>
</div>

<script
src="https://code.jquery.com/jquery-3.2.1.min.js"
integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
crossorigin="anonymous"></script>
<script type="text/javascript" src="scripts.js"></script>
</body>
</html>

First test:

$(document).ready(function(){
    $('.click-me').on("click", function( e ) {
        e.preventDefault();
        console.log(performance.now());
        var context = $(this);
        console.log(context);
        console.log(performance.now());
        console.log("---------------");
    });
});

Results:

scripts.js:4 3268.7400000000002
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 3272.0600000000004
scripts.js:8 ---------------
scripts.js:4 3604.9350000000004
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 3605.7050000000004
scripts.js:8 ---------------
scripts.js:4 3772.32
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 3772.905
scripts.js:8 ---------------
scripts.js:4 3929.1400000000003
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 3929.715
scripts.js:8 ---------------
scripts.js:4 4089.645
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 4090.3450000000003
scripts.js:8 ---------------
scripts.js:4 4248.81
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 4249.450000000001
scripts.js:8 ---------------
scripts.js:4 4437.070000000001
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 4437.635
scripts.js:8 ---------------
scripts.js:4 4557.56
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 4558.215
scripts.js:8 ---------------
scripts.js:4 4730.045
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 4730.795
scripts.js:8 ---------------
scripts.js:4 4879.95
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 4880.530000000001
scripts.js:8 ---------------
scripts.js:4 5021.1
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 5023.305
scripts.js:8 ---------------
scripts.js:4 5175.945000000001
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 5176.505000000001
scripts.js:8 ---------------
scripts.js:4 5329.89
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 5330.455000000001
scripts.js:8 ---------------
scripts.js:4 5492.42
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 5492.9400000000005
scripts.js:8 ---------------
scripts.js:4 5638.72
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 5639.375
scripts.js:8 ---------------
scripts.js:4 5783.885
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 5784.525000000001
scripts.js:8 ---------------
scripts.js:4 5943.805
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 5944.455000000001
scripts.js:8 ---------------
scripts.js:4 6086.06
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 6086.665000000001
scripts.js:8 ---------------
scripts.js:4 6241.115000000001
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 6241.64
scripts.js:8 ---------------
scripts.js:4 6378.925
scripts.js:6 r.fn.init [p.click-me]
scripts.js:7 6379.5650000000005
scripts.js:8 ---------------

Second test:

$(document).ready(function(){
    $('.click-me').on("click", function( e ) {
        e.preventDefault();
        console.log(performance.now());
        var context = (this);
        console.log(context);
        console.log(performance.now());
        console.log("---------------");
    });
});

Results:

1814.5900000000001
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 1816.8200000000002
scripts.js:8 ---------------
scripts.js:4 1969.2
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 1969.5600000000002
scripts.js:8 ---------------
scripts.js:4 2271.8550000000005
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 2272.1050000000005
scripts.js:8 ---------------
scripts.js:4 2655.715
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 2655.9700000000003
scripts.js:8 ---------------
scripts.js:4 2826.9100000000003
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 2827.2350000000006
scripts.js:8 ---------------
scripts.js:4 3018.3250000000003
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 3018.5850000000005
scripts.js:8 ---------------
scripts.js:4 3496.3650000000002
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 3496.6250000000005
scripts.js:8 ---------------
scripts.js:4 3689.8100000000004
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 3690.09
scripts.js:8 ---------------
scripts.js:4 3853.8250000000007
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 3854.1300000000006
scripts.js:8 ---------------
scripts.js:4 4011.66
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 4011.9550000000004
scripts.js:8 ---------------
scripts.js:4 4175.7300000000005
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 4176.01
scripts.js:8 ---------------
scripts.js:4 4373.255
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 4373.52
scripts.js:8 ---------------
scripts.js:4 4546.89
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 4547.165000000001
scripts.js:8 ---------------
scripts.js:4 4711.555
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 4711.83
scripts.js:8 ---------------
scripts.js:4 4898.745000000001
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 4899.01
scripts.js:8 ---------------
scripts.js:4 5165.515
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 5165.81
scripts.js:8 ---------------
scripts.js:4 5523.6900000000005
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 5523.985000000001
scripts.js:8 ---------------
scripts.js:4 5895.43
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 5895.705000000001
scripts.js:8 ---------------
scripts.js:4 6094.78
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 6095.040000000001
scripts.js:8 ---------------
scripts.js:4 6502.720000000001
scripts.js:6 <p class=​"click-me">​ Hey there!​</p>​
scripts.js:7 6502.975
scripts.js:8 ---------------

I tested the most popular jQuery methods on the selector and they all work.

He's a much more experienced developer than me and he says he did it to optimize. What am I missing?

  • [CodeReview](https://codereview.stackexchange.com/) ? – Kos Jan 20 '18 at 15:13
  • 2
    *"...the `this` context is the selector itself"* It's the element, not the "selector". A selector is the string you use to select the element(s). –  Jan 20 '18 at 15:14
  • @Kos CodeReview seems a better fit, yes! Should I remove the question and re-post there? Or do you think SO's community can benefit? – Jonathan Guerin Jan 20 '18 at 15:14
  • @rockstar Please suggest an edit, you're right! Also, does this change the dynamics of the script? – Jonathan Guerin Jan 20 '18 at 15:15
  • 1
    Every mention of `$(this)` is a function call. For most code, stashing the value of `$(this)` makes little actual performance difference, but it's a common coding pattern with jQuery. – Pointy Jan 20 '18 at 15:15
  • 3
    Another consideration is that inside the callbacks `this` will be something different. Read [How to access the correct `this` inside a callback](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – charlietfl Jan 20 '18 at 15:16
  • 1
    @Pointy Exactly my thoughts. The difference is so minuscule it seems not to matter that much! Any chance you could put a detailed answer up if you think it's worth? – Jonathan Guerin Jan 20 '18 at 15:16
  • Performance testing is tricky. Your tests, for example, are also testing the performance of a call to `console.log()`, which will obscure the difference between creating a jQuery object or not. Also, keep in mind that for every object allocation, the garbage collector needs to trace and eventually free the memory. However, doing this here and there won't make a noticeable difference. If you were actually selecting from the DOM and doing so over and over rapidly, that would be a different story. –  Jan 20 '18 at 15:23
  • ...perhaps most importantly is to remember that jQuery is always going to be slower than using the native API directly. Worrying about small performance optimizations here and there doesn't make sense because the biggest performance drain comes from using jQuery in the first place. –  Jan 20 '18 at 15:28

1 Answers1

0

Saving a few function calls in an event handler in almost all cases is not going to make any noticeable difference in page performance in modern (2018) JavaScript environments (even phones). That said, stashing $(this) in a variable is a time-honored jQuery tradition.

Personally if I were to do that, I'd use a more meaningful variable name:

$("div.content-box").each(function() {
  var contentBox = this, $contentBox = $(contentBox);
  // ...
});

Now the variable name means something, which in jQuery code that does a lot of "climbing around" in the DOM (via .parent(), .closest(), or .find()) can help avoid confusion.

Pointy
  • 405,095
  • 59
  • 585
  • 614