jquery.js 很经典,其中有一些设计思路简直非常经典
1.安全的创建一个构造函数并进行调用;
1 <script> 2 // 这是一种安全的构造函数的创建方法,在调用构造函数G的时候,不论使用G()进行调用,还是使用new G()进行调用,返回的东西都是相同的 3 var G = function() { 4 // 先判定this 是不是G的实例,如果是,则说明this 可以调用G的属性和方法,也可是使用G.prototype 上的属性和方法 5 if (this instanceof G) { 6 return this; 7 } else { 8 // 如果不是G的实例,说明现在的this没有指向G,也就是不能调用G的原型链上的东西,那么在调用的时候,就重新实例化一个G(),这样就可以调用原型链上的东西了 9 return new G(); 10 } 11 }; 12 G.prototype = { 13 length: 123, 14 size: function() { 15 return this.length; 16 } 17 }; 18 // 因为不论使用new G() 还是G()调用构造函数,得到的结果都是一样的,所以以下结果相同; 19 // 最开始都是返回一个构造函数的实例,然后通过原型链,可以调用构造函数的原型对象G.prototype,顺着原型链,可以找到函数的size()方法; 20 console.log(new G().size()); 21 console.log(G().size()); 22 </script>
2. 另一种设计方式,调用构造函数G时,返回G上挂载的对象
1 <script> 2 // 设置一个构造函数G,当调用它时,返回挂载在它身上的fn对象 3 var G = function() { 4 return G.fn; 5 }; 6 // 把G上的fn 对象指向G的原型对象,即指向 G.prototype 7 G.fn = G.prototype = { 8 length: 12345, 9 size: function() { 10 return this.length; 11 } 12 }; 13 console.log(G().size()); //12345 14 console.log(new G().size()); //12345 15 console.log(G.prototype.size()); //12345 16 </script>
运行结果:
3. 再进一步,当调用构造函数G时,返回G上的对象fn上的函数 init(),同时把fn对象指向构造函数G的原型对象,即G.prototype
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 </head> 9 <body> 10 <script> 11 // 设置一个构造函数G,当调用它时,返回挂载在它身上的fn对象上的 init() 函数 12 var G = function(id) { 13 return G.fn.init(id); 14 }; 15 // 把G上的fn 对象指向G的原型对象,即指向 G.prototype 16 G.fn = G.prototype = { 17 length: 12345, 18 size: function() { 19 return this.length; 20 }, 21 init: function(id) { 22 return document.getElementById(id); 23 } 24 }; 25 window.onload = function() { 26 G("box").style.background = 'red'; 27 G("box").size(); 28 } 29 </script> 30 <div id="box">hello,huanyign2015,这里正在进行测试!</div> 31 </body> 32 </html>
运行结果:
4. 改变this的指向,使this指向G.prototype
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 </head> 9 <body> 10 <script> 11 // 设置一个构造函数G,当调用它时,返回挂载在它身上的fn对象上的 init() 函数 12 var G = function(id) { 13 return G.fn.init(id); 14 }; 15 // 把G上的fn 对象指向G的原型对象,即指向 G.prototype 16 G.fn = G.prototype = { 17 init: function(id) { 18 this[0] = document.getElementById(id); 19 this.length = 1; 20 return this; 21 }, 22 length: 0, 23 size: function() { 24 return this.length; 25 } 26 }; 27 window.onload = function() { 28 G("box")[0].style.background = 'red'; 29 G("box2")[0].style.background = '#ccc'; 30 console.log(G("box").size()); 31 console.log(G("box2")); 32 } 33 </script> 34 <div id="box">第一行,hello,huanyign2015,这里正在进行测试!</div> 35 <div id="box1">第二行,hello,huanyign2015,这里正在进行测试!</div> 36 <div id="box2">第三行,hello,huanyign2015,这里正在进行测试!</div> 37 </body> 38 </html>
运行结果:
5. 当构造函数返回的不是G上的fn对象上的init()函数,而是G上的fn上的init对象的实例的时候,这时就不能调用size()函数了,因为在init()实例的原型链上没有size()函数;
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 </head> 9 <body> 10 <script> 11 // 设置一个构造函数G,当调用它时,返回挂载在它身上的fn对象上的 init() 函数对象的实例 12 var G = function(id) { 13 return new G.fn.init(id); 14 }; 15 // 把G上的fn 对象指向G的原型对象,即指向 G.prototype 16 G.fn = G.prototype = { 17 init: function(id) { 18 this[0] = document.getElementById(id); 19 this.length = 1; 20 return this; 21 }, 22 length: 0, 23 size: function() { 24 return this.length; 25 } 26 }; 27 window.onload = function() { 28 console.log(G("box2")); 29 console.log(G("box").size()); 30 } 31 </script> 32 <div id="box">第一行,hello,huanyign2015,这里正在进行测试!</div> 33 <div id="box1">第二行,hello,huanyign2015,这里正在进行测试!</div> 34 <div id="box2">第三行,hello,huanyign2015,这里正在进行测试!</div> 35 </body> 36 </html>
运行结果:
6.解决能够调用size()函数的问题,需要把init的原型对象指向G.prototype 上就可以了;也就是指向G.fn
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 </head> 9 <body> 10 <script> 11 // 设置一个构造函数G,当调用它时,返回挂载在它身上的fn对象上的 init() 函数对象的实例 12 var G = function(id) { 13 return new G.fn.init(id); 14 }; 15 // 把G上的fn 对象指向G的原型对象,即指向 G.prototype 16 G.fn = G.prototype = { 17 init: function(id) { 18 this[0] = document.getElementById(id); 19 this.length = 1; 20 return this; 21 }, 22 length: 0, 23 size: function() { 24 return this.length; 25 } 26 }; 27 // 把G.fn.init对象的实例加载到G.prototype的原型链上来,这样就可以通过原型链调用size()函数了 28 G.fn.init.prototype = G.fn; 29 window.onload = function() { 30 console.log(G("box2")); 31 console.log(G("box").size()); 32 } 33 </script> 34 <div id="box">第一行,hello,huanyign2015,这里正在进行测试!</div> 35 <div id="box1">第二行,hello,huanyign2015,这里正在进行测试!</div> 36 <div id="box2">第三行,hello,huanyign2015,这里正在进行测试!</div> 37 </body> 38 </html>
运行结果:
7. 构造一个Id与元素选择器
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 7 <title>Document</title> 8 <style> 9 div, 10 p { 11 padding: 3px; 12 margin: 3px; 13 border: 1px solid green; 14 } 15 </style> 16 </head> 17 <body> 18 <script> 19 // 设置一个构造函数G,当调用它时,返回挂载在它身上的fn对象上的 init() 函数对象的实例 20 var G = function(selector, context) { 21 return new G.fn.init(selector, context); 22 }; 23 // 把G上的fn 对象指向G的原型对象,即指向 G.prototype 24 G.fn = G.prototype = { 25 constructor: G, 26 init: function(selector, context) { 27 this.length = 0; 28 context = context || document; 29 if (selector.indexOf("#") == 0) { // 说明选择器是Id 30 31 this[0] = document.getElementById(selector.substring(1)); // 构造函数上设置数字索引0属性,值为对应的选中Id元素 32 this.length = 1; // 构造函数上设置一个length属性,值为元1,因为Id只选中一个元素 33 34 } else { // 说明是元素选择器, (备注,在这里只设置支持元素选择器和id选择器) 35 var aNode = context.getElementsByTagName(selector); 36 for (var i = 0, len = aNode.length; i < len; i++) { 37 this[i] = aNode[i]; // 构造函数上设置数字索引属性,值为对应的元素 38 } 39 this.length = len; // 构造函数上设置一个length属性,值为元素的个数len 40 }; 41 this.selector = selector; // 构造函数上设置一个selector属性,值为传入的selector 42 this.context = context; // 构造函数上设置一个selector属性,值为传入的context 43 return this; 44 }, 45 length: 0, 46 size: function() { 47 return this.length; 48 } 49 }; 50 // 把G.fn.init对象的实例加载到G.prototype的原型链上来,这样就可以通过原型链调用size()函数了 51 G.fn.init.prototype = G.fn; 52 window.onload = function() { 53 console.log(G('#box1')[0]); 54 var aP = G('p'); 55 for (var i = 0, len = aP.size(); i < len; i++) { 56 aP[i].style.backgroundColor = 'blue'; 57 } 58 } 59 </script> 60 <div id="box"> 61 <p>huanying2015,思维改变世界</p> 62 <p>huanying2015,思维改变世界</p> 63 <p>huanying2015,思维改变世界</p> 64 <p>huanying2015,思维改变世界</p> 65 <p>huanying2015,思维改变世界</p> 66 <ul>huanying2015,思维改变世界,这是ul元素</ul> 67 <p>huanying2015,思维改变世界</p> 68 <p>huanying2015,思维改变世界</p> 69 <p>huanying2015,思维改变世界</p> 70 </div> 71 <div id="box1">第二行,hello,huanyign2015,这里正在进行测试!</div> 72 <div id="box2">第三行,hello,huanyign2015,这里正在进行测试!</div> 73 </body> 74 </html>
运行结果: