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框架结构的理解:
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是单例模式,只能创建自己,不能创建其他
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的方法呢?
最理想的继承方式:
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,{ });