壹、大家从3个粗略的构造函数+原型程序开始,结营造立好了之后

壹、大家从一个不难易行的构造函数+原型程序起始

每三个框架都有3个骨干,全体的布局都是依照那当中央之上,结营造立好了随后,剩下的便是意义的堆砌。

1 var G = function(){};
2         G.prototype = {
3             length : 5,
4             size : function(){
5                 return this.length;
6             }
7         }

jQuery的主导正是从HTML文书档案中相配成分并对其操作。

上例是个万分简单的程序,假诺需求调用,大家能够用new的不二等秘书诀

就跟一座楼房一样,让大家一步一步驾驭那座高楼的木本和组织。

var oG = new G();

1.构造函数

console.log( oG.size() ); //5

2.链式语法

1、常见的一无所长调用格局一

3.选择器

console.log( G.size() ); //报错

4.扩展性

G.size那种调用,是把size当做静态方法调用,假使需求健康的调用,
应该把size方法加在函数自己,如:

G.size = function(){

壹、构造函数

return 10;

  大家知晓类是面向对象编制程序的2个第三概念,它是对事物的万丈抽象,它是一个模子。通超过实际例化3个类,大家得以成立一个实例。

}

javascript自身未有类的定义,只有原型prototype,prototype是怎么样啊?它是为构造函数设置的6脾气质,这几个特性蕴含二个对象(简称prototype对象)。这几个指标中带有了实例对象共享的习性(properties)和方法(methods)。有了那般一脾质量,我们就足以让具备的实例共享有些事物,来促成面向对象中类的概念。

二、常见的不当调用格局2

上边用一个例子来解释一下,链接————–

G().size() //报错

就此jQuery利用原型继承来促成类的

G()重临的是undefined, undefined.size() 肯定是报错,
size是函数G原型对象上的秘籍,假如要有限支撑这种方法调用正常,那么大家就要让G()
重临一个G函数的实例

 1 var jQuery = function(){}
 2 
 3 jQuery.prototype = {
 4     //扩展的原型对象
 5 }
 6 //由于prototype名称太长,我们可以另起一名fn
 7 jQuery.fn = jQuery.prototype = {
 8     //扩展的原型对象
 9 }
10 /********************我是分割线************************/
11 //同理jQuery也可以用别名$来代替,因此代码可以写成
12 var $ = jQuery = function(){};
13 jQuery.fn = jQuery.prototype = {
14     //扩展的原型对象
15     jquery : "1.7.2",
16     size : function(){
17         return this.length;
18     }
19 }

就此,大家得以如此做:

这大家怎么调用它吧?

1         var G = function () {
2             if( this instanceof G ) {
3                 return this;
4             }else {
5                 return new G();
6             }
7         };
1 var my$ = new $();//实例化
2 console.log(my$.jquery);//1.7.2
3 console.log(my$.size());//undefined

把G的构造函数改造一下,判断this是或不是是当前G函数的实例,即使是,直接重回,假设不是,再次来到new
G()  那样依据原型对象的探寻条件,就能担保调用到size方法

不过jQuery并不是这么调用的,它就像是$().jquery 那种样式。

一体化的代码:

也等于说jQuery没用new实例化,而是向来调用jQuery()函数,然后前面跟jQuery的原型方法。怎么落实吗?

 1         var G = function () {
 2             if( this instanceof G ) {
 3                 return this;
 4             }else {
 5                 return new G();
 6             }
 7         };
 8         G.prototype = {
 9             length: 5,
10             size: function () {
11                 return this.length;
12             }
13         }
14         console.log( G().size() );
 1 var $ = jQuery = function(){
 2     return  new jQuery();
 3 };    
 4 jQuery.fn = jQuery.prototype = {
 5     
 6     jquery : "1.7.2",
 7     size : function(){
 8         return this.length;
 9     }
10 }
11 
12 console.log($().jquery);
13 console.log($().size());

在jquery框架中,他是怎么做的?

若是依据上边的做法会出错,内部存款和储蓄器溢出,因为创制实例的时候循环引用导致出错。

 1         var G = function () {
 2             return G.fn;
 3         };
 4         G.fn = G.prototype = {
 5             length: 5,
 6             size: function () {
 7                 return this.length;
 8             }
 9         }
10         console.log( G.prototype.size() ); //5
11         console.log( G().size() ); //5

小编们需求回到贰个实例,大家驾驭在new3个对象的时候,this指向new的实例,实例获取了prototype的习性方法。

在jquery中, 为函数G扩大2个属性fn(
记住:在js中等高校函授数是指标,那其实便是给目标扩展了1个属性
),然后在G函数中回到 G.fn 正是便是回来G.prototype

就此大家得以用工厂方法成立贰个实例,把这几个情势放在jQuery.prototype
的原型对象在那之中,然后在jQuery函数中回到这一个原型方法的调用。

那正是说用G().size 其实就是1对壹于调用 G.prototype.size()

 1 var $ = jQuery = function(){
 2     return  jQuery.fn.init();
 3 };    
 4 jQuery.fn = jQuery.prototype = {
 5     init: function(){
 6         console.log(this);
 7         return this;//返回实例的引用
 8     },
 9     jquery : "1.7.2",
10     size : function(){
11         return this.length;
12     }
13 }
14 console.log($().jquery);
15 console.log($().size());

二、在jquery中,那个构造函数1般是用来摘取元素的。

console中会看到this对象是 jQuery的2个实例。

G再次来到的是G的原型对象,大家要加进采纳成分的成效,听之任之,就是往原型对象上添加:

init()方法再次来到的是this关键字,该重大字引用的是jQuery的实例,借使在init()中再而三利用this关键字,也正是将init函数视为三个构造器,this又是什么处理呢?

 1         var G = function ( id ) {
 2             return G.fn.init( id );
 3         };
 4         G.fn = G.prototype = {
 5             init : function( id ){
 6                 return document.getElementById( id );
 7             },
 8             length: 5,
 9             size: function () {
10                 return this.length;
11             }
12         }
var $ = jQuery = function(){
    return  jQuery.fn.init();
};    
jQuery.fn = jQuery.prototype = {
    init: function(){
        this.length = 2;
        this.test = function(){
            return this.length;
        }
        return this;
    },
    jquery : "1.7.2",
    length:0,
    size : function(){
        return this.length;
    }
}

console.log($().jquery);
console.log($().test()); //2 ? 0 ?
console.log($().size()); //2 ? 0 ?

向G的原型对象上添加贰个init方法, 然后在构造函数中调用

  再次回到的都以2,能够见见,this关键字引用了init函数功用域所在的目的,此时它访问length属性时,重回的为贰。this关键字也能访问上级对象jQuery.fn对象的成效域,所以回来1.七.二,而调用size方法时,重返的是二而不是0。

1         window.onload = function(){
2             console.log( G( 'box' ) );
3             G('box').style.backgroundColor = 'red';
4             // G('box').size(); //报错,无法链式调用
5         }
6 
7     <div id="box">ghost wu tell you how to learn design pattern</div>

这种设计思路很不难破坏功用域的独立性,对jQuery框架大概产生消沉影响,由此jQuery通超过实际例化init早先化类型来划分作用域的

就算如此经过init方法,能够挑选到dom成分,可是不能够实现链式调用,
因为G(‘box’)重返的是2个dom对象,
而在dom对象上是不曾size那些点子的,因为size是G.prototype上的

1 var $ = jQuery = function(){
2     return new jQuery.fn.init();
3 };    

由此要兑现链式调用,就要保障init方法重回的是G的实例或然G.prototype,
 这一年,this就足以派上用场了

  那样就能够把init()构造函器中的this和jQuery.fn对象中的this关键字隔开分离开来。防止混淆。可是那种方法带来的另一个难题是不能访问jQuery.fn
的对象的习性和措施。

 1 <script>
 2         var G = function (id) {
 3             return G.fn.init(id);
 4         };
 5         G.fn = G.prototype = {
 6             init: function (id) {
 7                 this[0] = document.getElementById(id);
 8                 this.length = 1;
 9                 return this;
10             },
11             length: 0,
12             size: function () {
13                 return this.length;
14             }
15         }
16         window.onload = function () {
17             console.log(G('box'));
18             console.log( G('box2').size() );
19         }
20     </script>

1     <div id="box">ghost wu tell you how to learn design pattern</div>
2     <div id="box2">id为box2的第二个div</div>

Object [object Object] has no method ‘size’.

把选用到的要素放在this中, 这一年的this指向的是G.fn,G.prototype?

怎么着成功既能分割起头化构造函数与jQuery原型对象的作用域,又能够在回去实例中访问jQuery原型对象呢?

因为在构造函数中,是这么调用的: G.fn.init( id ), 笔者把G.fn标成青白,
也等于1对一于G.fn是四个对象,没有错他实在就是二个目的G.prototype,所以在init中的this指向的就是

jQuery框架巧妙地通过原型传递消除了那个标题

init方法后边的对象( G.fn, G.prototype ).

1 jQuery.fn.init.prototype = jQuery.fn;//使用jQuery原型对象覆盖init原型对象

三、this覆盖

  那样 new jQuery.fn.init()
创造的新目的具备init构造器的prototype原型对象的艺术,通过改动prototype指针的指向,使其针对性jQuery类的prototype,那样成立出来的目的就此起彼伏了jQuery.fn原型对象定义的方法。

接下去,就会发生3个题材, this共用之后,成分选拔就会发出覆盖

二、扩展性

 1 <script>
 2         var G = function (id) {
 3             return G.fn.init(id);
 4         };
 5         G.fn = G.prototype = {
 6             init: function (id) {
 7                 this[0] = document.getElementById(id);
 8                 this.length = 1;
 9                 console.log( this === G.fn, this === G.prototype, this );
10                 return this;
11             },
12             length: 0,
13             size: function () {
14                 return this.length;
15             }
16         }
17 
18         window.onload = function(){
19             console.log( G( 'box' ) );
20             console.log( G( 'box2' ) );
21         }
22     </script>
23 
24     <div id="box">ghost wu tell you how to learn design pattern</div>
25     <div id="box2">id为box2的第二个div</div>

  jQuery 自定义扩充方法用的extend () 函数

调用一遍组织函数G 去获取成分的时候, this[0] 以后都指向了
id为box2的要素,
把第一次G(‘box’)选取到的id为box的成分覆盖了,发生覆盖的缘由是this共用,那么大家

1 jQuery.extend = jQuery.fn.extend = function() {
2     //code    
3 }

能够经过什么办法把this分开呢?差异的this指向不一样的实例? 用什么?
恩,对了, 用new,每一次new多少个构造函数就会转移新的实例

在讲源码在此之前,先说一下什么样是拷贝,浅拷贝,深拷贝。

4、化解this覆盖与链式调用

大家知道js 种分化的数据类型

 1     <script>
 2         var G = function (id) {
 3             return new G.fn.init(id);
 4         };
 5         G.fn = G.prototype = {
 6             init: function (id) {
 7                 this[0] = document.getElementById(id);
 8                 this.length = 1;
 9                 return this;
10             },
11             length: 0,
12             size: function () {
13                 return this.length;
14             }
15         }
16         window.onload = function(){
17             console.log( G( 'box' ) );
18             console.log( G( 'box2' ) );
19         }
20     </script>
21     <div id="box">ghost wu tell you how to learn design pattern</div>
22     <div id="box2">id为box2的第二个div</div>

* 着力类型:按值传递  (undefined,NULL,boolean,String,Number)
* 引用类型:传递内存地址 Object

因此构造函数中new G.fn.init( id )
的情势,每趟生成多少个新的实例,可是爆发了一个新的题目,不能链式调用,
因为init中的this爆发了变动,不再指向( G.fn, G.prototype ).

/*
深度拷贝,全体的成分和总体性完全clone,并与原引用对象完全部独用立,克隆后的指标与原对象再也从不别的关联,也便是当您拷贝达成后,原对象值有其余改变,都不会影响到大家克隆后尤其指标的值*/

G(‘box2’).size();//报错,

从而大家在展开深拷贝(clone)的时候,注意将复制对象中的每三个值,而不是援引,换句话说,正是使用递归的措施浅拷贝对象。

为了能够调用到size(),
所以在实践完构造函数之后,大家要保管this指向G的实例,也许G的原型对象,

1.浅拷贝

只须要把init函数的原型对象指向G.fn就能够了

 1 var clone = _.clone = function(obj){
 2     //不是对象直接放回返回值
 3     if (typeof obj != 'object') return obj;
 4     var result;
 5     //数组用slice方法 不改变原数组
 6     if(Object.prototype.toString.call(obj)==="[Object Array]"){
 7         result =  obj.slice();
 8     }else{
 9         //对象 for遍历
10         result = {};
11         for(var name in obj){
12             result[name] = object[name];
13         }
14     }
15     return result;
16 }
 1         var G = function (id) {
 2             return new G.fn.init(id);
 3         };
 4         G.fn = G.prototype = {
 5             init: function (id) {
 6                 this[0] = document.getElementById(id);
 7                 this.length = 1;
 8                 return this;
 9             },
10             length: 0,
11             size: function () {
12                 return this.length;
13             }
14         }
15         G.fn.init.prototype = G.fn;

2.深拷贝

丰盛G.fn.init.prototype = G.fn;我们就修正了this的掩盖与链式调用难点

 1 var _deepClone = function(source){
 2     if(source===null) return null;
 3     var result;
 4     if(source instanceof Array){
 5         result = [];
 6         //如果是数组,递归调用
 7         for(var i = 0;i

 5、扩张选取器

3.jQuery 的实现

地点帮忙id选拔器,我们只需求在init函数加上其余类型的扩大就足以了,比如,小编那边扩展了一个标签选用器

 1 jQuery.extend = jQuery.fn.extend = function() {
 2     //所有使用的的变量最好最好在函数定义的最前就写下来,原因与ECMA有关 详解
 3 
 4     var options, name, src, copy, copyIsArray, clone,
 5         target = arguments[0] || {},
 6         i = 1,
 7         length = arguments.length,
 8         deep = false;
 9 
10     // 判断是否为深拷贝|浅拷贝
11     if ( typeof target === "boolean" ) {
12         deep = target;
13         target = arguments[1] || {};    //返回的目标对象
14         // 遍历的时候跳过 deep | target 参数
15         i = 2;
16     }
17 
18     // 如果初始值不为对象 且不是一个函数则置空,比如一个string ""置为{};
19     if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
20         target = {};
21     }
22 
23     // 如果只有自己一个参数,而没有被克隆继承的参数,则返回自己本身
24     if ( length === i ) {
25         target = this;
26         --i;
27     }
28 
29     for ( ; i < length; i++ ) {
30         // 处理值为null undefined情况
31         if ( (options = arguments[ i ]) != null ) {
32             // 继承对象options
33 
34             for ( name in options ) {
35                 src = target[ name ];       //原对象中对应的值
36                 copy = options[ name ];     //需要拷贝的对象中对应的值
37 
38                 // 防止陷入死循环,如果原对象本身就等于需要拷贝的对象中的那值(o),
            //在对o遍历的时候就把自己重新遍历赋值了一遍
39                 if ( target === copy ) {
40                     continue;
41                 }
42 
43                 //在 Array和Object的情况,且deep为true和传进对象有值(true)的情况下,递归调用本身方法进行深拷贝
44                 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
45                     if ( copyIsArray ) {//如果需要拷贝的对象为数组
46                         copyIsArray = false;
47                         clone = src && jQuery.isArray(src) ? src : [];
48 
49                     } else {
50                         clone = src && jQuery.isPlainObject(src) ? src : {};
51                     }
52 
53                     target[ name ] = jQuery.extend( deep, clone, copy );
54                     // 如果不是上述情况,则进行浅拷贝,我们在执行jQuery.extend({})或jQuery.fn.extend({})的时候都是执行的这个方法,但却搞不明白为什么一个是对JQuery类的自定义扩展,一个是JQuery对象的自定义扩展,那么这里的target究竟代表什么呢,我们看下面的例子
55                 } else if ( copy !== undefined ) {
56                     target[ name ] = copy;
57                 }
58             }
59         }
60     }
61 
62     // 返回修改过后的target
63     return target;
64 };
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 
 4 <head>
 5     <meta charset="UTF-8">
 6     <meta name="viewport" content="width=device-width, initial-scale=1.0">
 7     <meta http-equiv="X-UA-Compatible" content="ie=edge">
 8     <title>Document</title>
 9     <style>
10         div,p {
11             border:1px solid red;
12             margin: 10px;
13             padding: 10px;
14         }
15     </style>
16     <script>
17         var G = function ( selector, context ) {
18             return new G.fn.init( selector, context );
19         };
20         G.fn = G.prototype = {
21             constructor : G,
22             init: function ( selector, context ) {
23                 this.length = 0;
24                 context = context || document;
25                 if ( selector.indexOf( '#' ) == 0 ) {
26                     this[0] = document.getElementById( selector.substring( 1 ) );
27                     this.length = 1;
28                 }else {
29                     var aNode = context.getElementsByTagName( selector );
30                     for( var i = 0, len = aNode.length; i < len; i++ ){
31                         this[i] = aNode[i];
32                     }
33                     this.length = len;
34                 }
35                 this.selector = selector;
36                 this.context = context;
37                 return this;
38             },
39             length: 0,
40             size: function () {
41                 return this.length;
42             }
43         }
44         G.fn.init.prototype = G.fn;
45 
46         window.onload = function(){
47             console.log( G('#box')[0] );
48             var aP = G('p', G('#box')[0]);
49             // var aP = G('p');
50             // var aP = G('#p1');
51             for( var i = 0, len = aP.size(); i < len; i++ ){
52                 aP[i].style.backgroundColor = 'blue';
53             }
54         }
55     </script>
56 </head>
57 
58 <body>
59     <div id="box">
60         <p>跟着ghostwu学习设计模式</p>
61         <p>跟着ghostwu学习设计模式</p>
62         <p>跟着ghostwu学习设计模式</p>
63         <p>跟着ghostwu学习设计模式</p>
64     </div>
65     <p id="p1">跟着ghostwu学习设计模式</p>
66     <p>跟着ghostwu学习设计模式</p>
67 </body>
68 
69 </html>

注意:虽然jQuery.extend = jQuery.fn.extend
它们是3个方法,可是它们的求实职能是不平等的,因为this的指向分裂。

 function jQuery() {}
 //使用字面量的方式创建原型对象,这里{}就是对象,是Object,new Object就相当于{}
 jQuery.fn = jQuery.prototype = {
  constructor : jQuery,   //强制指向jQuery
  name : 'Lee', 
  age : 100,
  run : function () {
   return this.name + this.age + '运行中...';
  }
 };
 jQuery.extend = jQuery.fn.extend = function(){
  var option = arguments[0] ;
  for(var v in option){
   this[v] = option[v];
  }
  return this;
 };
 var jquery = new jQuery(); 
 document.write(""+jQuery.extend({
   add:function(){
    alert("aaaa");
   }
  })+""); 
 document.write(""+jQuery.fn.extend({
   minu:function(){
    alert("bbbb");
   }
  })+""); 

 jQuery.add();
 jquery.minu();

this打字与印刷结果

function jQuery() {}

[object Object]

在构造函数那些模块大家看看

jQuery .extend 的this 是jQuery类本人,在jQuery类上助长(对象,方法)

jQuery.fn.extend
的this是jQuery的原型,在jQuery原型上助长(对象,方法),那么JQuery对象自笔者也会具有哪些措施

jQuery.fn = jQuery.prototype

4、来1个简化版的

 1 var _deepClone = function(source){
 2     if(source===null) return null;
 3     var result;
 4     if(source instanceof Array){
 5         result = [];
 6         //如果是数组,递归调用
 7         for(var i = 0;i

图片 1

http://www.bkjia.com/Javascript/767644.htmlwww.bkjia.comtruehttp://www.bkjia.com/Javascript/767644.htmlTechArticle每一个框架都有一个核心,所有的结构都是基于这个核心之上,结构建立好了之后,剩下的就是功能的堆砌。
jQuery的主导正是从HTML文档中…

相关文章

网站地图xml地图