天天看点

JQ框架结构理解

1、jQuery对象的本质:

1、1 jQuery对外暴露了两个变量: $和jQuery  ,这两个变量都是指向同一个函数

1、2  举例:

1.2.1  不传参可以创建jq对象 console.log($())   console.log(jquery())  ===> jquery.fn.init 

1.2.2 传参(可以传任何参数,jq会做不同的处理,但是都会得到jq对象) 得到的也是jq对象 console.log($('body'));   ===> jquery.fn.init ==>0:body length:1

1.2.3  发现jq实例对象会以下标的形式存储数据(大部分情况下都是DOM元素),并且还有一个length属性,说明jq实例对象是一个 伪数组 ( jq实例能够像数组一样访问里面存储的数据和数据量 )

console.log($('body')[0]);   console.log($('body').length);

2、关于JQ实创建伪数组的原理:

2、1  实例化

<script>           这是工厂函数     function $(){         return new init();     }

    这是构造函数     function init(){     }              console.log($());  看上去是jq对象,但是打印出来 init__proto__: Objectconstructor: ƒ init()__proto__: Object ,说明并不是一个伪数组     console.log($().length);    undefined

</script>    

2、2 让实例化对象变成伪数组的方式

<script>           这是工厂函数     function $(){         return new init();     }

    这是构造函数     function init(){         this.length=0;    给一个length=0;给新创建的实例对象添加属性     }              console.log($());    init {length: 0}  得到的仍然是实例对象,不过这个实例对象拥有一个length属性,并且值为0,那么这个实例对象又多了一个称呼,叫伪数组对象     console.log($().length);    0

</script>    

2、3 由上面的示例理解一下什么是伪数组?     1、伪数组是一个非数组类型的对象 2、有一个length的属性,值为number类型 3、以下标的方式存储数据

2、4 关于数组push方法

function $(){         return new init();     }

    这是构造函数     function init(){          this.length=0;    此时为0 问:如果此时的值为2,那么实例化是不严谨的,需要补充上数组的值,如下:     this[0]="abc";     this[1]="cba"; 问:如果此时的值是10,20,那么如上赋值的方式太过繁琐,最简单的方法是?---apply和call

     [].push.call(this,'abc','cbs','123');  重点!!!

    }              console.log($());     init {0: "abc", 1: "cba", length: 2}     console.log($().length);   2

</script>    

3、实例成员和静态成员:

3、1 实例成员: 供实例使用的属性与方法就叫实例成员

$().css();  $().attr();  $()就是jq对象,实例对象调用的方法就一定是实例成员

3、2 静态成员: 供构造函数自己使用的属性与方法就叫静态成员

$.ajax

案例:

function person(age) {     this.age=age;  age就是实例成员 }

person.MAX_AGE=170;   静态成员

person.prototype={  原型添加方法给实例化对象用     run:function(){   实例成员         console.log('跑');  } }

3、3 实例能否使用静态成员?--- 不能

var xiaofeng = new person(16); console.log(xiaofeng.MAX_AGE); UNDEFINED

3、4 构造函数能否使用实例成员? ---- 不能

console.log(person.age);  undefined console.log(person.run());  报错 

4、抽取JQ框架结构

<script> // 1、jq的结构整体是一个自调,自调是为了防止全局变量的污染

(function (global, factory) {

//global对应的就是window //factory对应的就是第二个函数,这个函数返回一个jQuery工厂函数 //这里jq对模块化做了一些支持

factory(global);

})(typeof window !== 'undefined' ? window : this, function (window) {

//jq的主体代码都在这里

//3、这是jq对外暴露的工厂函数 ----对外暴露工厂,是为了简化用户创建对象的代码量 var jquery = function () { return new jQuery.fn.init(); };

//4、置换原型,同时给原型起了一个简称,方便用户和自己使用 给jq原型起一个简称是因为:jq实现了一个插件机制,说白了就给让用户可以自由扩展原型,简化单词的写法 jQuery.fn = jQuery.prototype = { constuctor: jQuery };

//5、定义构造函数,同时把构造函数加到了jQUery工厂函数的原型中,这是jq内部影响的构造函数 var init = jQuery.fn.init = function () { };

//6、让构造函数的原型与工厂函数的原型保持一致 置换构造函数原型为工厂函数原型,是为了让实例能够调用工厂函数原型里面的成员 init.prototype = jQuery.fn;

//2、在jq主体代码中对外暴露了两个变量,这两个变量指向同一个函数 window.jQuery = window.$ = jQuery;

return jQuery;

})

$(); $.fn(); </script>

5、jq框架结构的理解:

JQ框架结构理解

1、工厂函数有什么用?

把创建对象的过程进行封装,用户只需要调用工厂就可以得到相应的实例,这里最大的好处就是创建对象的时候省去了new关键字

2、init为什么是一个构造函数呢?

因为工厂函数new的是init,所以init是构造函数

3、为什么不能把工厂函数和构造函数融为一体,即工厂内部new自己?

new自己就是死循环

4、为什么要把init加到原型中: 猜想,对外暴露的是jQuery工厂函数,可以通过工厂创建实例,但是实例.constructor的值是工厂,为了能够通过实例得到的构造函数,所以也把构造函数加到了原型中,这样实例.init就找到了它的构造函数

5、为什么要把构造的原型置换为工厂的原型? 因为对外暴露的是工厂函数,jq在工厂的身上加了一个插件机制, 通过$.fn.extend()给工厂的原型进行扩展,但是如何让init实例能够使用工厂原型中的方法呢?解决方案就是把init的原型置换为工厂的原型

6、手写jq框架结构:

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

    3、定义工厂     var jQuery =function(){         return new jQuery.fn.init();     }          4、工厂原型置换&简称     jQuery.fn=jQuery.prototype={         constructor:jQuery         };

        5、定义构造函数         var init =jQuery.fn.init =function(){          }              6、置换狗构造原型为工厂原型         init.prototype =jQuery .fn;

        2、暴露工厂         window.jQuery=window.$=jQuery;

})(window);

7、继承结构:

注意:math是单例模式,只能创建自己,不能创建其他

JQ框架结构理解
JQ框架结构理解

8、继承类型:

方式1--默认的原型继承

function Person () {     Person.prototype.run =funtction(){};         var xiaohong= new Person(); }

方式2--置换后的原型继承

function Person () {      Person.prototype={             say:funtction(){};     }          var xiaohong= new  Person(); }

方式3--寄生式继承

var obj={val :100 }; var newObj=Object.create(obj);

方式4--混入继承

function extend (o1,o2){     for (var key in o2){         o1[key]=o2[key];     } }

var o={} var o2={aaa:111,bbb:222}; extend(o,o2)

方式5--对象冒充(构造函数借用)

function Person (name ,age ){

    this.name=mame;     this.age=age;

}

function Student (name ,age ){

    this.Person=Person;     this.Person(name ,age );     delete this.Person;

}

function Student (name ,age ,sex){

    Person.call(this,name ,age ,sex);       Person.apply(this, arguments);

}

var xiaohong =new Student('小红',16); console.log(xiaohong);

方式6--原型组合继承

function Person (name ,age ){

    this.name=mame;     this.age=age;

} Person.prototype={                say:funtction(){};      } function Student (name ,age ){

   Person.apply(this,arguments);

}

如何让student能够继承到person的方法呢?

JQ框架结构理解

最理想的继承方式:

function Person (name ,age ){

    this.name=mame;     this.age=age;

} Person.prototype={                say:funtction(){};      } function Student (name ,age ){

     Person.apply(this, arguments);

}

让学生实例,继承 Student .prototype&Person.prototype Student .prototype=Object.create(Person.prototype);

再给student扩展自己独有的方法 extend( Student .prototype,{ });