🍃このブログは移転しました。
3秒後、自動的に移動します・・・。

jQueryでadd/removeClassする前にhasClassすべきか

ちょうど気になってたので調べてみました。

結論からいうと、しなくて良いみたい。

気になるポイント

  • チェックしなくても、addClass/removeClassしてくれるっぽいしいらないのでは
  • でもclassNameに値入れるってことは、再レンダリングされちゃうのでは
  • 値入れるのはコスト高なイメージあるので、できれば避けるべきでは

ってとこかな?

肝心のソース

/**
 * Source code from v2.1.1
 *
 */

addClass: function( value ) {
    var classes, elem, cur, clazz, j, finalValue,
        proceed = typeof value === "string" && value,
        i = 0,
        len = this.length;

    if ( jQuery.isFunction( value ) ) {
        return this.each(function( j ) {
            jQuery( this ).addClass( value.call( this, j, this.className ) );
        });
    }

    if ( proceed ) {
        // The disjunction here is for better compressibility (see removeClass)
        classes = ( value || "" ).match( rnotwhite ) || [];

        for ( ; i < len; i++ ) {
            elem = this[ i ];
            cur = elem.nodeType === 1 && ( elem.className ?
                ( " " + elem.className + " " ).replace( rclass, " " ) :
                " "
            );

            if ( cur ) {
                j = 0;
                while ( (clazz = classes[j++]) ) {
                    if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
                        cur += clazz + " ";
                    }
                }

                // only assign if different to avoid unneeded rendering.
                finalValue = jQuery.trim( cur );
                if ( elem.className !== finalValue ) {
                    elem.className = finalValue;
                }
            }
        }
    }

    return this;
},

removeClass: function( value ) {
    var classes, elem, cur, clazz, j, finalValue,
        proceed = arguments.length === 0 || typeof value === "string" && value,
        i = 0,
        len = this.length;

    if ( jQuery.isFunction( value ) ) {
        return this.each(function( j ) {
            jQuery( this ).removeClass( value.call( this, j, this.className ) );
        });
    }
    if ( proceed ) {
        classes = ( value || "" ).match( rnotwhite ) || [];

        for ( ; i < len; i++ ) {
            elem = this[ i ];
            // This expression is here for better compressibility (see addClass)
            cur = elem.nodeType === 1 && ( elem.className ?
                ( " " + elem.className + " " ).replace( rclass, " " ) :
                ""
            );

            if ( cur ) {
                j = 0;
                while ( (clazz = classes[j++]) ) {
                    // Remove *all* instances
                    while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
                        cur = cur.replace( " " + clazz + " ", " " );
                    }
                }

                // only assign if different to avoid unneeded rendering.
                finalValue = value ? jQuery.trim( cur ) : "";
                if ( elem.className !== finalValue ) {
                    elem.className = finalValue;
                }
            }
        }
    }

    return this;
},

というわけで

  • チェックしなくても、addClass/removeClassしてくれるっぽいしいらないのでは

-> その通りでした。

  • でもclassNameに値入れるってことは、再レンダリングされちゃうのでは

-> これもその通りで、ただ値のチェックをしてくれてるのでそれは起こらない模様。

  • 値入れるのはコスト高なイメージあるので、できれば避けるべきでは

-> 上述の通り、それは同じクラス名である限り起こらないので気にしなくて良い。


なのでhasClassは、本当に値の有無が知りたい時しか使わなくてOK!