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等上层需要灵活设置参数的功能做了一个统一的整理,方便了调用,节省了比特。

jQuery.access源码分析

时间: 2024-10-23 08:52:12

jQuery.access源码分析的相关文章

jQuery.attributes源码分析(attr/prop/val/class)

回顾 有了之前的几篇对于jQuery.attributes相关的研究,是时候分析jQuery.attr的源码了 Javascript中的attribute和property分析 attribute和property兼容性分析 jQuery.access源码分析 结构 jQuery.fn.extend({ attr: function (name, value) { }, removeAttr: function (name) { }, prop: function (name, value) {

jQuery选择器源码分析和easyui核心分析

写在选择器源码分析之前 这里指对1.7.2版本的源码分析,更高版本添加了更多代码. 整个jQuery的代码是写在一个(function(window, undefined){})(window);这样一个闭包里.请思考,为什么要这样做? 将其写在一个闭包函数里,并传入window直接运行的好处有三: 1,统一命名空间,防止变量的污染:  2,将window作为参数传入函数,在函数里调用window的时候,就不用再去找外层的对象,可以提高效率 : 3,undefined并不是javascript的

jQuery.queue源码分析

作者:禅楼望月(http://www.cnblogs.com/yaoyinglong ) 队列是一种特殊的线性表,它的特殊之处在于他只允许在头部进行删除,在尾部进行插入.常用来表示先进先出的操作(FIFO)--先进队列的元素先出队.搜索整个jQuery库会发现,queue在jQuery内部仅供给animate动画来使用.它提供了对外的接口,因此程序员也可以使用队列来完成一些特殊需求. queue模块对外开放的API:工具方法:queue,dequeue,_queueHooks(仅内部使用)实例方

jQuery.buildFragment源码分析以及在构造jQuery对象的作用

这个方法在jQuery源码中比较靠后的位置出现,主要用于两处.1是构造jQuery对象的时候使用 2.是为DOM操作提供底层支持,这也就是为什么先学习它的原因.之前的随笔已经分析过jQuery的构造函数了,也提到了有12个分支,其中有一个分支就是通过jQuery.buildFragment方法来处理的,什么情况呢?就是在处理复杂html标签的时候,例如$('<div>123</div>')这样的形式,在构造函数内部通过ret变量判断是不是简单标签,如果是就调用js的createEl

jQuery.extend() 源码分析

jQuery.extend() 方法 可以合并对象 深拷贝与浅拷贝 源码分析: 概述:  1. 首先定义变量 options:保存每次循环遍历的arguments[i] , name: 保存循环遍历对象的key值 src:保存目标对象target的属性 copy: 保存合并对象的属性 copyIsArray: 如果copy是数组,用copyIsArray保存 clone:如果目标对象是数组,用clone保存. target:目标对象 deep: boolean值,判断是否是深拷贝 2. 然后判断

jQuery.Deferred 源码分析

作者:禅楼望月(http://www.cnblogs.com/yaoyinglong ) 1 引子 观察者模式是我们日常开发中经常用的模式.这个模式由两个主要部分组成:发布者和观察者.通过观察者模式,实现发布者和观察者的解耦. 发布者主要负责发布内容,观察者主要负责监听发布者发布的内容,并作出相应的动作.和我们平时订阅期刊一样,cnki会维护一个订阅者列表,有期刊被发布出来时,cnki会将这些期刊推送给订阅者.从程序角度来说,订阅者就是一堆的方法,发布者的推送内容的动作就是依次调用订阅者列表中的

jquery.noConflict源码分析(2)

代码位于9159~9183 该功能是为了解决JQ与其他函数命名冲突的问题. API  jQuery.noConflict([removeAll]); 缺省情况下,运行这个函数将变量$的控制权让渡给第一个实现它的库.在运行完这个函数之后,就只能使用jQuery变量访问jQuery对象. 该函数必须在导入jQuery文件之后,并且在导入另一个导致冲突的库之前使用. var // Map over jQuery in case of overwrite _jQuery = window.jQuery,

jQuery 2.1.4版本的源码分析

jquery中获取元素的源码分析 jQuery.each({// 获取当前元素的父级元素 parent: function(elem) { var parent = elem.parentNode;//nodeType为11的节点类型是DocumentFragment return parent && parent.nodeType !== 11 ? parent : null; },//获取所有的 父节点 这涉及到 dir 方法 parents: function(elem) { ret

Jquery源码分析

1.概述 jQuery是一个非常优秀的Js库,与prototype,YUI,Mootools等众多的Js类库相比,它剑走偏锋,从web开发最实用的角度出发,抛除了一些中看但不实用的东西,为开发者提供一个短小精悍的类库.由于其个短小精悍,使用简单方便,性能相对高效.众多的开发者都选择Jquery来进行辅助的web开发. 在使用jquery时开发,我们也会时常碰到许多的问题,但是jquery的代码很晦涩,难起看懂,当开发时出现了问题,看不懂源码,不知道如何去排错. John Resig,Jquery