zoukankan      html  css  js  c++  java
  • jQuery原生框架-----------------核心框架

    // 1、自调防止全局变量污染
    (function( window ) {

    var version = '1.0.0';
    var document = window.document;

    var arr = [];
    var push = arr.push;
    var slice = arr.slice;
    var concat = arr.concat;

    var obj = {};
    var toString = obj.toString;
    var hasOwn = obj.hasOwnProperty;

    // 3、定义工厂
    var jQuery = function( selector ) {
    return new jQuery.fn.init( selector );
    }

    // 4、工厂原型置换&简称
    jQuery.fn = jQuery.prototype = {
    constructor: jQuery,

    jquery: version,

    length: 0,

    // 把参数包装成一个新的实例返回,这个新的实例记录了调用者(上一级链)
    pushStack: function( eles ) {
    var $$ = jQuery( eles );
    $$.prevObject = this;
    return $$;
    },

    // 返回上一级链,如果没有返回一个新实例
    end: function() {
    return this.prevObject || jQuery();
    },

    // 把实例转换为数组返回
    toArray: function() {
    return slice.call( this );
    },

    // 按照下标获取原生的元素,支持负数
    get: function( index ) {
    return arguments.length === 0? this.toArray():
    index >= 0? this[ index ]: this[ this.length + index ];
    },

    // 截取部分元素,返回部分元素构成的新实例
    slice: function( start, end ) {
    return this.pushStack( slice.call( this, start, end ) );
    },

    // 按照下标获取jQ包装过的元素,支持负数
    eq: function( index ) {
    return this.pushStack( this.get( index ) )
    },

    // 获取jQ包装过的第一个元素
    first: function() {
    return this.eq( 0 );
    },

    // 获取jQ包装过的最后一个元素
    last: function() {
    return this.eq( -1 );
    },

    push: push,
    sort: arr.sort,
    splice: arr.splice,

    // 传入的fn在DOM构建完毕后执行
    ready: function( fn ) {

    /*
    * 为了防止DOM已经构建完毕后,用户再调用ready方法,
    * 造成事件绑定无效,所以先判断DOM有没有构建完毕,
    * 如果完毕了,直接执行函数即可。
    * */

    /*// 如果是现代浏览器,readyState值为interactive或者complete,证明DOM构建完毕,fn直接执行
    if ( document.addEventListener &&
    ( document.readyState === 'interactive' || document.readyState === 'complete' ) ) {
    return fn();
    }
    // IE老版本浏览器,readyState值只有为complete,才能保证DOM构建完毕,fn才能执行
    else if (document.readyState === 'complete'){
    return fn();
    }*/

    /*
    * 无论是现代浏览器还是IE老版本浏览器,readyState值只要为complete,DOM就一定构建完毕了。
    * 另外对于现代浏览器,readyState值如果为interactive,那么代表DOM也构建完毕了。
    * */
    if( document.readyState === 'complete' ||
    ( document.addEventListener && document.readyState === 'interactive' ) ) {
    fn();
    }

    else {
    /*
    * 实现思路:
    * 1、判断是否支持addEventListener,支持则绑定DOMContentLoaded事件
    * 2、不支持则用attchEvent绑定onreadystatechange事件
    * */

    if( document.addEventListener ) {
    document.addEventListener( 'DOMContentLoaded', fn );
    }else {
    document.attachEvent( 'onreadystatechange', function() {
    if( document.readyState === 'complete' ) {
    fn();
    }
    } );
    }
    }

    // 链式编程
    return this;
    },

    // 遍历实例
    each: function( cbk ) {
    return jQuery.each( this, cbk );
    },

    // 遍历实例,返回映射后的新实例
    map: function( cbk ) {
    return this.pushStack( jQuery.map( this, cbk ) );
    }
    };

    // 7、是工厂自身和原型分别添加一个实现混入继承的方法
    jQuery.extend = jQuery.fn.extend = function() {

    var arg = arguments, argLen = arg.length;
    var key, i = 1;
    var target = arg[ 0 ];

    if( argLen === 1 ) {
    target = this;
    i = 0;
    }

    // 从第二个对象开始遍历
    for ( ; i < argLen; i++ ) {

    // 把遍历到的每一个对象的所有成员copy给target身上
    for ( key in arg[ i ] ) {

    if ( arg[ i ].hasOwnProperty( key ) ) {
    target[ key ] = arg[ i ][ key ];
    }
    }
    }

    return target;
    };

    // 5、定义构造函数
    var init = jQuery.fn.init = function( selector ) {

    // 非 undefined、null、NaN、0、''、false
    if ( selector ) {

    // function
    if ( jQuery.isFunction( selector ) ) {
    this.ready( selector );
    }

    // string
    else if ( jQuery.isString( selector ) ) {

    // html,创建对应的DOM元素,加到实例身上
    if ( jQuery.isHTML( selector ) ) {
    push.apply( this, jQuery.parseHTML( selector ) );
    }

    // selector,获取页面中的元素,加到实例身上
    else {
    push.apply( this, document.querySelectorAll( selector ) );
    }
    }

    // array || likeArray,把数组中所有的数据加到实例身上
    else if( jQuery.isLikeArray( selector ) ) {

    // 这个不用了,是因为IE8中slice不能操作DOM类型的伪数组
    //push.apply( this, slice.call( selector ) );

    // 这样做,又用到了apply,一下回到解放军出不来了。
    //push.apply( this, concat.apply( [], selector ) );


    // 对于IE8来说,当selector为用户自定义的伪数组时,会报错,
    // 那么在catch里面把这个伪数组转换为真数组再添加给this就可以了。
    try{
    push.apply( this, selector );
    }catch(e) {
    push.apply( this, slice.call( selector ) );
    }
    }

    // 其它,直接把数据加到实例身上
    else {
    this[ 0 ] = selector;
    this.length = 1;
    }
    }
    };

    // 6、置换构造原型为工厂原型
    init.prototype = jQuery.fn;


    // 给jQ添加一堆静态方法
    jQuery.extend({

    // 把传入的html字符串解析成对应的DOM
    parseHTML: function( html ) {
    var tempDiv = document.createElement('div');
    tempDiv.innerHTML = html;
    return tempDiv.childNodes;
    },

    // 判断数据是不是html字符串
    isHTML: function( str ) {

    // 如果传入的不是字符串,直接返回false
    if ( typeof str !== 'string' ) {
    return false;
    }

    // 如果传入的是字符串,看看这个字符串结构符不符合html字符串结构,符合返回true
    if( str[ 0 ] === '<' && str[ str.length - 1 ] === '>' && str.length >= 3 ) {
    return true;
    }

    // 不符合返回false
    return false;
    },

    _isHTML: function( htmlStr ) {
    return !!htmlStr && htmlStr[ 0 ] === '<' &&
    htmlStr[ htmlStr.length - 1 ] === '>' && htmlStr.length >= 3;
    },

    // 判断数据是不是对象类型
    isObject: function( obj ) {
    return (typeof obj === 'object' && obj !== null) || typeof obj === 'function';
    },

    // 判断数据是不是数组或伪数组
    isLikeArray: function( likeArray ) {

    // 过滤 function、window、!object
    if( jQuery.isFunction( likeArray ) || jQuery.isWindow( likeArray ) || !jQuery.isObject( likeArray ) ) {
    return false;
    }

    // 判断是不是真数组
    if( likeArray instanceof Array ) {
    return true;
    }

    // 判断是不是伪数组,要么length值为0,
    // 要么length值为number,并且还得有lenght - 1这个属性
    if( likeArray.length === 0
    || ( typeof likeArray.length === 'number' && likeArray.length > 0 && (likeArray.length - 1) in likeArray ) ) {
    return true;
    }

    return false;
    },

    // 判断是不是函数
    isWindow: function( win ) {
    return !!win && win.window === win;
    },

    // 判断是不是函数
    isFunction: function( fn ) {
    return typeof fn === 'function';
    },

    // 判断是不是字符串
    isString: function( str ) {
    return typeof str === 'string';
    },

    // 判断是不是DOM元素
    isDOM: function( dom ) {
    return !!dom && !!dom.nodeType;
    },

    // 遍历对象
    each: function( obj, cbk ) {
    /*
    * 实现思路:
    * 1、首先却分传入进来的是不是likeArray,
    * 2、如果是采用 var i = 0 的遍历方法遍历所有的值,
    * 然后把遍历到的下标和值依次传给回调使用,并且设置回调内部的this为遍历到的值
    * 3、如果不是likeArray,才有for in的遍历方法遍历所有的值,
    * 然后把遍历到的键和值依次传给回调使用,并且设置回调内部的this为遍历到的值
    * 4、如果回调的返回结果是false,那么中断遍历
    * */

    var i, len;

    // 如果是数组或者伪数组,才有vai i的方式遍历,效率比较高
    if( jQuery.isLikeArray( obj ) ) {
    for( i = 0, len = obj.length; i < len; i++ ) {

    // 把遍历到的键值传给回调使用,如果回调返回false,
    // 那么证明对方不需要再遍历其他数据了,所以break跳出循环。
    if( cbk.call( obj[ i ], i, obj[ i ] ) === false ) {
    break;
    }
    }
    }

    // 否则采用for in的遍历方式
    else {
    for( i in obj ) {

    // 把遍历到的键值传给回调使用,如果回调返回false,
    // 那么证明对方不需要再遍历其他数据了,所以break跳出循环。
    if( cbk.call( obj[ i ], i, obj[ i ] ) === false ) {
    break;
    }
    }
    }

    return obj;
    },

    map: function( obj, cbk ) {
    /*
    * 实现思路:
    * 1、先却分遍历的对象是不是likeArr
    * 2、是的话var i方式遍历,把遍历的数据传给回调,
    * 同时指定回调内部的this为遍历到的值
    * 3、不是for in方式遍历,把遍历的数据传给回调,
    * 同时指定回调内部的this为遍历到的值
    * 4、收集回调的返回结果,如果不为null或undefined,就存储起来,最终一起返回
    * */

    var i, len, temp, result = [];

    // 如果是数组或者伪数组,才有vai i的方式遍历,效率比较高
    if( jQuery.isLikeArray( obj ) ) {
    for( i = 0, len = obj.length; i < len; i++ ) {

    // 把遍历到的键值传给回调使用,
    // 同时接收回调的返回值,
    // 如果值不为null或undefined,那么存储到result数组
    temp = cbk.call( obj[ i ], i, obj[ i ] );
    if( temp != null ) {
    result.push( temp );
    }
    }
    }

    // 否则采用for in的遍历方式
    else {
    for( i in obj ) {

    // 把遍历到的键值传给回调使用,
    // 同时接收回调的返回值,
    // 如果值不为null或undefined,那么存储到result数组
    temp = cbk.call( obj[ i ], i, obj[ i ] );
    if( temp != null ) {
    result.push( temp );
    }
    }
    }

    return result;
    }
    });

    // 2、暴露工厂&提供一个工厂简称
    window.jQuery = window.$ = jQuery;

    })( window );

  • 相关阅读:
    统计插件无效问题
    Hearthbuddy跳过ConfigurationWindow窗口
    炉石兄弟更新修复记录(至2021年5月)
    HearthbuddyHelper已经开源
    2020年8月28日
    交易机制的实现
    Silverfish重构【2】-限制惩罚为某一behavior特有
    Silverfish重构【1】-发现卡牌的函数
    99-Flagstone Walk
    Behavior控场模式的解析(下)
  • 原文地址:https://www.cnblogs.com/luxiaoxiao/p/6115136.html
Copyright © 2011-2022 走看看