1. Apa itu panggilan berantai
Ini mudah difahami, contohnya:
$(this).setStyle('color', 'red').show();
Perbezaan antara panggilan fungsi umum dan panggilan berantai: selepas memanggil kaedah, kembalikan ini mengembalikan objek kaedah panggilan semasa.
function Dog(){ this.run= function(){ alert("The dog is running...."); return this;//返回当前对象 Dog }; this.eat= function(){ alert("After running the dog is eatting...."); return this;//返回当前对象 Dog }; this.sleep= function(){ alert("After eatting the dog is running...."); return this;//返回当前对象 Dog }; } //一般的调用方式; /* var dog1 =new Dog(); dog1.run(); dog1.eat(); dog1.sleep();*/ var dog2 = new Dog(); dog2.run().eat().sleep();
2. Menguraikan panggilan berantai
Panggilan berantai sebenarnya adalah dua bahagian:
1). Objek Operasi (iaitu, elemen DOM sedang dimanipulasi, seperti $(this) dalam contoh di atas)
2). Kaedah operasi (khususnya perkara yang perlu dilakukan, seperti setStyle dan tunjukkan dalam contoh di atas)
Cara melaksanakan objek operasi dan kaedah operasi
Buat fungsi $generik:
function $(){ var elements = []; for(var i= 0,len=arguments.length; i<len; i++){ var element = arguments[i]; if(typeof element==='string'){ element = document.getElementById(element); } if(arguments.length==1){ return element; } elements.push(element); } return elements; }
Walau bagaimanapun, jika anda mengubah fungsi ini menjadi pembina, simpan elemen tersebut sebagai tatasusunan dalam atribut contoh, dan biarkan semua kaedah yang ditakrifkan dalam objek yang ditunjukkan oleh atribut prototaip fungsi pembina kembali untuk memanggil kaedah rujukan A untuk contoh itu, maka ia mempunyai keupayaan untuk membuat panggilan berantai. (Setelah berkata begitu banyak, kembalikan ini; pada akhir setiap kaedah),
Saya perlu menukar fungsi $ini terlebih dahulu kepada kaedah kilang, yang bertanggungjawab untuk mencipta objek yang menyokong panggilan berantai. Fungsi ini sepatutnya boleh menerima hujah dalam bentuk tatasusunan elemen supaya kita boleh menggunakan antara muka awam yang sama seperti sebelumnya. Dengan cara ini, ia mempunyai keupayaan untuk membuat panggilan berantai.
Transformasi adalah seperti berikut:
(function(){ function _$(els){ this.elements = [];//把那些元素作为数组保存在一个实例属性中, for(var i= 0, len=els.length; i<len; i++){ var element = els[i]; if(typeof element==='string'){ element = document.getElementById(element); } this.elements.push(element); } } _$.prototype = { each: function(fn){ for(var i= 0,len=this.elements.length; i<len; i++){ fn.call(this, this.elements[i]); } return this; //在每个方法的最后return this; }, setStyle: function(prop, val){ this.each(function(el){ el.style[prop] = val; }); return this; //在每个方法的最后return this; }, show: function(){ var that = this; this.each(function(el){ that.setStyle('display', 'block'); }); return this; //在每个方法的最后return this; }, addEvent: function(type, fn){ var add = function(el){ if(window.addEventListener){ el.addEventListener(type, fn, false); }else if(window.attachEvent){ el.addEvent('on'+type, fn); } }; this.each(function(el){ add(el); }); return this; //在每个方法的最后return this; } } window.$ = function(){ return new _$(arguments); } })();
Kembalikan ini pada penghujung, yang menghantar objek kaedah panggilan ke kaedah seterusnya dalam rantai panggilan.
3. Simulasikan pengaturcaraan rantaian asas jquery
// 块级作用域 //特点1 程序启动的时候 里面的代码直接执行了 //特点2 内部的成员变量 外部无法去访问 (除了不加var修饰的变量) (function(window , undefined){ // $ 最常用的对象 返回给外界 大型程序开发 一般使用'_'作为私用的对象(规范) function _$(arguments){ //实现代码...这里仅实现ID选择器 // 正则表达式匹配id选择器 var idselector = /#\w+/ ; this.dom ; // 此属性 接受所得到的元素 // 如果匹配成功 则接受dom元素 arguments[0] = '#inp' if(idselector.test(arguments[0])){ this.dom = document.getElementById(arguments[0].substring(1)); } else { throw new Error(' arguments is error !'); } }; // 在Function类上扩展一个可以实现链式编程的方法 Function.prototype.method = function(methodName , fn){ this.prototype[methodName] = fn ; return this ; //链式编程的关键 } // 在_$的原型对象上 加一些公共的方法 _$.prototype = { constructor : _$ , addEvent:function(type,fn){ // 给你的得到的元素 注册事件 if(window.addEventListener){// FF this.dom.addEventListener(type , fn); } else if (window.attachEvent){// IE this.dom.attachEvent('on'+type , fn); } return this ; }, setStyle:function(prop , val){ this.dom.style[prop] = val ; return this ; } }; // window 上先注册一个全局变量 与外界产生关系 window.$ = _$ ; // 写一个准备的方法 _$.onReady = function(fn){ // 1 实例化出来_$对象 真正的注册到window上 window.$ = function(){ return new _$(arguments); }; // 2 执行传入进来的代码 fn(); // 3 实现链式编程 _$.method('addEvent',function(){ // nothing to do }).method('setStyle',function(){ // nothing to do }); }; })(window); // 程序的入口 window传入作用域中 $.onReady(function(){ var inp = $('#inp'); //alert(inp.dom.nodeName); //alert($('#inp')); inp.addEvent('click',function(){ alert('我被点击了!'); }).setStyle('backgroundColor' , 'red'); });
4 Gunakan fungsi panggil balik untuk mendapatkan data daripada kaedah yang menyokong panggilan berantai
Panggilan berangkai sangat sesuai untuk kaedah pengagih, tetapi untuk kaedah peroleh nilai, ia menyusahkan kerana setiap kaedah mengembalikan ini.
Walau bagaimanapun, masih terdapat penyelesaian, dan itu ialah fungsi panggil balik.
Apabila fungsi panggil balik tidak digunakan
//without callback window.API = window.API || function(){ var name = 'JChen'; this.setName = function(newName){ name = newName; return this; }; this.getName = function(){ return name; }; }; var o = new API(); console.log(o.getName()); console.log(o.setName('Haha').getName());
Apabila menggunakan fungsi panggil balik
//with callback window.API2 = window.API2 || function(){ var name = 'JChen'; this.setName = function(newName){ name = newName; return this; }; this.getName = function(callback){ callback.call(this, name); return this; }; }; var o2 = new API2(); o2.getName(console.log).setName('Hehe').getName(console.log);
Apabila menggunakan fungsi panggil balik, callback.call(ini, nama) biasanya baik. Walau bagaimanapun, dalam contoh ini, console.log digunakan, jadi terdapat masalah. Sebabnya ialah konsol ini menunjuk kepada konsol dan bukannya winodw.
Masalah ini juga mudah untuk diselesaikan. Seperti berikut:
//with callback window.API2 = window.API2 || function(){ var name = 'JChen'; this.setName = function(newName){ name = newName; return this; }; this.getName = function(callback){ callback.call(this, name); return this; }; }; var o2 = new API2(); var log = function(para){ console.log(para); }; o2.getName(log).setName('Hehe').getName(log);
Gaya panggilan berantai ini membantu memudahkan penulisan kod, menjadikan kod lebih ringkas dan lebih mudah dibaca, dan juga mengelak daripada menggunakan semula pembolehubah objek beberapa kali.