Web

JS中JQ框架的分析

2019-09-18  本文已影响0人  追逐_chase
web.jpeg

1. 首先我们在看jQ代码的时候 发现整体是一个 闭包函数

// JQ的整体是一个自调用函数/闭包
(function(window,undefined){

})(window)

作用:
1.防止全局变量污染(只提送2个变量 $ 和 jQuery)
2.保护内部的代码不会被覆盖
其中 里面的2个参数 windowundefined值默认不能被修改,但是在IE9-是可以被修改的

  • window不用多解释,全局的对对象

2.JQ使用的事工厂函数


//自调用函数
(function(window,undefiend){
    
    //1.创建工厂函数
    var jQuery = function(select){
        //返回一个 构造函数
        return  new jQuery.fn.init(select);
    }

    

    //2. 设置元素对象和原型对象
    jQuery.fn = jQuery.prototype = {
        constructor:jQuery,
        //初始化方法 匿名的构造函数
        init:function(select){
        
        }
    }

    //3.更改init构造函数的原型对象 指向 jQuery.prototype
    jQuery.fn.init.prototype = jQuery.prototype;


    //4.给外界提供一个变量
    window.jQuery = window.$ = jQuery;


})(window);

3.jQ的参数分析

1.如果条件判断为假 0 false null undefined NaN ... 返回空的jQ实例对象

  jQuery.fn = jQuery.prototype = {
        constructor:jQuery,
        init:function (selector) {
            //条件判断为假 返回空的jQ对象
            if(!selector)
            {
               return this;
            }
        }
    }
  1. 字符串(标签) 返回所有标签保存到jQ实例对象 比如$("<span>我是spanA</span><span>我是spanB</span>")
 jQuery.fn = jQuery.prototype = {
        constructor:jQuery,
        init:function (selector) {
            //[1] 条件判断为假 返回空的jQ对象
            if(!selector)
            {
               return this;
            }

            //[2] 参数是字符串
            else if(Tool.isString(selector))
            {
                //参数是标签
                //<div></div>
                //总结判断的条件:必须以<开头 && 必须以>结尾 && 长度>=3
                //charAt(index) 获取字符串中指定的字符  "zhangsan"
                //容错性处理:包容用户
                selector = Tool.trim(selector);
                if(Tool.isHTML(selector))
                {
                    //console.log("参数是标签");
                    //console.log(typeof selector);
                    //把参数中所有的一级标签都保存到jQ实例对象中返回
                    //分析: 创建一个临时的div 存储标签字符串
                    //     把所有获取的标签都存到当前jQ实例对象中(this)
                    //     更新length的值
                    var tempEle = document.createElement("div");
                    tempEle.innerHTML = selector;
                    var nodes = tempEle.children;
                    //console.log(tempEle);
                    //console.log(nodes);
                    for(var i = 0;i<nodes.length;i++)
                    {
                        this[i] = nodes[i];
                    }
                    //console.log("this",this);
                    this.length = nodes.length;
                    return this;
                }
                //参数是选择器
                else
                {
                    console.log("其他情况");
                }
            }

            // 数组
        }
    }

//工具方法
 var Tool = {
        isString:function (str) {
        return typeof str === "string"
    },
        isHTML:function (html) {
        return html.charAt(0) === "<" && html.charAt(html.length -1) ===">" && html.length >=3
    },
        trim:function (text) {
        //检测当前环境是否支持trim方法,如果支持那么就直接使用
        if(text.trim)
        {
            return text.trim();
        }else
        {
       
            return text.replace(/^\s+|\s+$/g,"")
        }
    }
    }
  1. 字符串(选择器)把参数中所有的一级标签都保存到jQ实例对象中返回
    比如:
//获取参数
 var nodes = document.querySelectorAll(selector);
//遍历 查看是否有自标签
      for(var i = 0;i<nodes.length;i++){
                        this[i] = nodes[i];
             }
      this.length = nodes.length;

//获取使用  call / apply借调函数

 [].push.apply(this,document.querySelectorAll(selector));

4.数组 |伪数组(本质是对象) 返回jQ实例对象

   [].push.apply(this,selector);
    return this;  //返回jQ对象

5.如果参数是函数,那么会监听DOM的加载,等DOM加载完执行回调函数中的代码


//闭包函数
(function(window,undefined){
    //1.创建工厂函数
    var jQuery = function(select){
        
        return  new jQuery.fn.init(select);
    };

    //2.设置原型对象
    jQuery.fn = jQuery.prototype = {
        constructor:jQuery,
        init:function(select){
            //1.判断条件是否为假
            if(!select){

                return this;
            } else if(tool.isFunction(select)){
                this.ready(selector);
            }
             //2.判断字符串
              //console.log(typeof selector);
                    //把参数中所有的一级标签都保存到jQ实例对象中返回
                    //分析:(001)需要根据字符串获取一级标签
                    //     (002)把所有获取的标签都存到当前jQ实例对象中(this)
                    //     (003)更新length的值
            else if(tool.isString(select)){
                //取出空格
                select = tool.trim(select);
                //匹配标签字符串
                if(tool.isHTML(select)){
                    //创建一个临时div 包裹
                    var tempElement = document.createElement("div");
                    //把标签字符串设置 div的内容 获取div的 子元素
                    tempElement.innerHTML = select;

                    var nodes = tempElement.children;

                    for(var i =0 ; i < nodes.length; i ++){
                        //包装成 JQ对象  this就是创建JQ的对象
                        this[i] = nodes[i];
                    }

                    this.length = nodes.length;

                    return this;

                }
                //字符串是选择器
                else{

                     //(001) 根据参数获取所有指定的标签
                    //(002) 把所有获取的标签存储到jQ实例对象中返回
                    //(003) 更新length的值,返回jQ实例对象
                    //"div"
                    //#demoID
                    //.box

                    // var nodes = document.querySelectorAll(select);
                    // for(var i = 0; i < nodes.length; i ++){
                    //     this[i] = nodes[i];
                    // }
                    // this.length = nodes.length;

                    // apply借调函数的使用
                    // this借调数组[] push的方法
                    // push是  Array.prototype.push 的原型方法
                    //这个方法 等价于 上面的for 遍历
                    [].push.apply(this,document.querySelectorAll(select));

                    return this;

                }

            }
            //3.判断是否为 数组/为数组
            else if(tool.isArray(select) || tool.isLikeArray(select)){

               //IE8之前调用下面的方法会报错
               //select是伪数组的时候
               //处理,把为数组转化为数组
               var arrt = [].slice.call(select);
                [].push.apply(this,arrt);

                return this;
            }
            //其他参数
            else{
                this[0] = select;
                this.length = 1;
            }
            
        },
        ready:function(fn){
            //判断是不是已经加载完成了,如果是 直接调用
            if(document.readyState == "complete") {
                fn();
                return;
            }
            //不是
            //监听DOM 加载完成 
            if(document.addEventListener){
                document.addEventListener("DOMContentLoaded",fn);
            } else{
                //兼容IE的方法
                document.attachEvent("onreadystatechange",function(){
                    if(document.readyState == "complete") {
                        fn();
                      
                    }
                });

            }
        }
    }

   //抽出的工具方法
   var tool = {
       isObject:function(obj){
        return typeof obj == "object" && obj != null;
       },
       isWindow(obj){
        return obj === window.window;
       },
       isString:function(str){
            return (typeof str === "string");
       },
       isHTML:function(html){
           //判断是字符串是否是标签 <h1>zheshi</h1>
        return  html.chatAt(0) === "<" && html.chatAt(html.lenth -1) === ">"&&html.length >= 3;
       },
       trim:function(text){
           //判断是否支持这个方法
           if(text.trim){

            return text.trim();

           } else{
            //处理字符串中的空格
            // 把空格替换掉
            return text.replace(/^\s+|\s+$/g,"");
           }
       },
       isArray:function(arr){
           //处理是不是数组
           if(Array.isArray){
               //ES5
               return Array.isArray(arr);
           } else{
                //ES5之前的
            return Object.prototype.toString.call(arr) === "[object Array]";
           }
       },
       /**
        * (1) 是对象
        * (2) 拥有length属性
        * (3) 拥有length-1属性
        * (4) 不是window
        */
       isLikeArray:function(likeArray){
        return this.isObject && length in likeArray && likeArray.length - 1 in likeArray && !tool.isWindow(likeArray);
       },
       isFunction:function(fn){
            return typeof fn == "function";
       }
   };

    //3.更改init的构造函数的原型对象的指向
    jQuery.fn.init.prototype = jQuery.prototype;

     jQuery.tool = tool;

    //4.提供全局变量给外部
    window.jQuery = window.$ = jQuery;
    


})(window);

4.工具优化---插件机制

我们知道jQ提供的2个参数分别是$jQuery,那么如何暴露给外面一些工具方法,或者是对象方法呢?

答案是:原型对象

  //优化工具方法
    jQuery.fn.extend = jQuery.extend = function(obj){
        for(var i in obj){
            this[i] = obj[i];
        }
}

jQuery.fn.extend 其实就是 jQuery.prototype..extend 给原型对象扩展方法

jQuery.extend 扩展其实就是 jQuery = function(){}函数,扩展静态的属性或者方法

比如:

 // 工厂函数 添加属性或者方法
    jQuery.extend({
        isObject:function(obj){

            return typeof obj == "object" && obj != null;
        },
        isWindow:function(obj){
            
            return obj === window.window;
        },
        isString:function(str){

            return (typeof str == "string");
        },
        isHtml:function(html){
            return html.charAt(0) === "<" && html.charAt(html.length -1) === ">" && html.length >= 3;
        },
        trim:function(text){
            if(text.trim){
               return text.trim(); 
            }else {
                //排除空格
                return text.replace(/^\s+|^s+$/g,"");
            }
        },
        isArray:function(tempArr){
            if(Array.isArray){
                return Array.isArray(tempArr);
            }else{
                //es5之前 调用object的原型对象tostring 处理
                return Object.prototype.toString.call(tempArr) == "[object Array]";
            }
        },
        isLikeArray:function(tempArr){
            return this.isObject && length in tempArr && tempArr.length - 1 in tempArr && !this.isWindow(tempArr);
        },
        isFunction:function(fn){

            return  typeof fn == "function";
        }

    });
    
 
jQ的所谓插件机制就是这样给或者实例对象来扩充自己的方法
上一篇下一篇

猜你喜欢

热点阅读