zoukankan      html  css  js  c++  java
  • jQuery.access源码分析

    基本理解

    jQuery.attr是jQuery.attr,jQuery.prop,jQuery.css提供底层支持,jQuery里一个比较有特色的地方就是函数的重载, 比如attr,有如下几种重载

    • $('#box').attr('title')
    • $('#box').attr('title','标题')
    • $('#box').attr({title:'标题',data-menu-toggle:'dropdown'})
    • $('#box').attr('title',function () {....})

    但是纵观jQuery.attr代码中,却没有判断value是不是存在啊之类的,ok,你猜对了,在access里实现了

    jQuery.fn.extend({
        attr: function (name, value) {
            return jQuery.access(this, jQuery.attr, name, value, arguments.length > 1);
        },
    
        removeAttr: function (name) {
            return this.each(function () {
                jQuery.removeAttr(this, name);
            });
        },
    
        prop: function (name, value) {
            return jQuery.access(this, jQuery.prop, name, value, arguments.length > 1);
        }
    });

    源码分析

    大致思路

        1.首先判断key值是不是一个object,如果是,遍历key,递归调用jQuery.access,并将是否可以链式调用的标志位设置为true
        2.判断value值是否已经定义,如果已经定义,说明是个set操作
          2.1 set操作的是可链式调用的
          2.2 如果value不是function,设置raw为true
          2.3 判断key值是否为null或者undefined,key若为空值
            2.3.1 如果value不是个函数,或者强制赋值raw为true,那么调用fn,可能是以下调用:$('#box').attr(null,{abc:'def',a:'1'})
            2.3.1 如果value是个函数,将fn包装之,改变原来fn的作用域和参数
          2.4 如果fn存在,遍历jQuery内部元素,分别执行set操作
        3.首先判断是否为set方法,如果是,返回 elems,如果不是执行get操作(如果jQuery内部length为0,返回指定的默认空值)

    源码

        // Multifunctional method to get and set values of a collection
        // The value/s can optionally be executed if it's a function
        /**
        attr: function (name, value) {
            return jQuery.access(this, jQuery.attr, name, value, arguments.length > 1);
        },
         *
         * @param elems jQuery的this
         * @param fn 函数
         * @param key 属性
         * @param value 值
         * @param chainable 是否可以链式调用,如果是get动作,为false,如果是set动作,为true
         * @param emptyGet 如果jQuery没有选中到元素的返回值
         * @param raw value是否为原始数据,如果raw是true,说明value是原始数据,如果是false,说明raw是个函数
         * @returns {*}
         */
        access: function( elems, fn, key, value, chainable, emptyGet, raw ) {
            var i = 0,
                length = elems.length,
                bulk = key == null; // bulk 体积,容量;大多数,大部分;大块
    
            // Sets many values
            /**
             * 如果参数key是对象,表示要设置多个属性,则遍历参数key,遍历调用access方法
             *
             * $('#box').attr({data:1,def:'addd'});
             */
            if ( jQuery.type( key ) === "object" ) {
                chainable = true; //表示可以链式调用
                for ( i in key ) {
                    jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
                }
    
            // Sets one value
    
                /**
                 * $('#box').attr('customvalue','abc')
                 * $('#box').attr('customvalue',function (value) {});
                 */
    
            } else if ( value !== undefined ) {
                chainable = true;
    
                if ( !jQuery.isFunction( value ) ) {
                    raw = true;
                }
    
                if ( bulk ) { // if (key == null && value !== undefined)
                    // Bulk operations run against the entire set
                    /**
                     * $('#box').attr(undefined,'abc')
                     *
                     * jQuery.attr.call(elems,value); 调用完毕之后,将fn设置为空
                     */
                    if ( raw ) {
                        fn.call( elems, value );
                        fn = null;
    
                    // ...except when executing function values
                        /**
                         * $('#box').attr(undefined,function () {})
                         *
                         * fn = bulk = jQuery.attr;
                         *
                         * fn = function (elem, key, value) {
                         *  return jQuery.attr.call(jQuery(elem),value);
                         * }
                         *
                         */
                    } else { //如果key有值的话,好办,这里的bulk是为了节省一个变量,将fn用bulk存起来,然后封装fn的调用
                        bulk = fn;
                        fn = function( elem, key, value ) {
                            return bulk.call( jQuery( elem ), value );
                        };
                    }
                }
    
                //jQuery.access(elems,jQuery.attr,)
    
    
                //如果fn存在,掉调用每一个元素,无论key是否有值,都会走到这个判断,执行set动作
                if ( fn ) { // 递归调用之
                    for ( ; i < length; i++ ) {
                        fn( elems[i], key,
                            raw ? value :
                            /**
                             * 如果value是原始数据,就取value,如果是个函数,就调用这个函数取值
                             * $('#box').attr('abc',function (index,value) { index指向当前元素的索引,value指向oldValue
                             *
                             *  先调用jQuery.attr(elements[i],key) 取到当前的值,然后调用传入的fn值
                             * });
                             */
    
    
                                value.call( elems[i], i, fn( elems[i], key ) )
                        );
                    }
                }
            }
    
            /**
             * 如果chainable为true,说明是个set方法,就返回elems
             * 否则说明是get方法
             * 1.如果bulk是个true,说明没有key值,调用fn,将elems传进去
             * 2.如果bulk为false,说明key有值哦,然后判断元素的长度是否大于0
             *    2.1 如果大于0,调用fn,传入elems[0]和key,完成get
             *    2.2 如果为0,说明传参有问题,返回指定的空值emptyGet
             */
            return chainable ?
                elems :
    
                // Gets
                bulk ?
                    fn.call( elems ) :
                    length ? fn( elems[0], key ) : emptyGet;
        },

    ExtJS 中的flexSetter方法

    这让我猛然想起了Ext的flexSetter方法,该方法在Ext.Function.flexSetter 详细API请看这里

    用法:

        var ele = document.getElementById('box');
    
        function setAttribute(name, value) {
            ele.setAttribute(name, value);
        }
    
        var flexSetAttribute = Ext.Function.flexSetter(setAttribute);
    
        flexSetAttribute('title', '标题');
        flexSetAttribute({
            'abc': 'otherattribu',
            'other': 1
        });

    源码

        /**
         * 1.关于Ext.enumerables的实现
         *
         * 这里为了兼容某些浏览器的toString,valueOf等内置方法不能被遍历出来的bug
         * var o = {toString:111,valueOf:222};
         *
         * for (var oo in o)
         * {
               alert(oo);
           }
         *
         */
        var enumerables = [//'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
                    'valueOf', 'toLocaleString', 'toString', 'constructor'];
    
        for (i in { toString: 1 }) {
            enumerables = null;
        }
    
        Ext.Function = {
            flexSetter: function(setter) {
                return function(name, value) { // 返回一个闭包
                    var k, i;
    
                    if (name !== null) {
                        if (typeof name !== 'string') { //如果name不是字符串,这里就认为是对象,进行for in
                            for (k in name) {
                                if (name.hasOwnProperty(k)) {
                                    setter.call(this, k, name[k]); //逐个调用setter
                                }
                            }
    
                            if (Ext.enumerables) {
                                for (i = Ext.enumerables.length; i--;) {
                                    k = Ext.enumerables[i];
                                    if (name.hasOwnProperty(k)) {
                                        setter.call(this, k, name[k]);
                                    }
                                }
                            }
                        } else {
                            setter.call(this, name, value); // 如果是个字符串,直接调用了
                        }
                    }
    
                    return this;
                };
            }
        };

    总结:很显然,Ext的flexSetter没有jQuery的强大,但是足够严谨,jQuery.access为prop、attr等上层需要灵活设置参数的功能做了一个统一的整理,方便了调用,节省了比特。

  • 相关阅读:
    MFC 的资源文件 就是那个后缀名是 .rc的那个
    servlet 上下文
    servlet 会话技术
    页面分层
    分页技术 -servlet
    关于servlet连接数据库会出现空指针异常情况
    servlet 1
    (转)用户级和内核级线程
    (转)数据库分片Shard操作
    (转)系统设计题要考虑的方面
  • 原文地址:https://www.cnblogs.com/hhstuhacker/p/jquery-access-source-advance.html
Copyright © 2011-2022 走看看