jquery内核学习(6)--扩展实现extend
本篇繼續豐富我的jquery框架,利用extend來擴展!
擴展的優點
不必每次增加新的方法都直接往jQuery或者jQuery.fn追加.?
jQuery.fn.extend({fun1: function() {console.log('this is an extend function');} })通過這樣的方法就能為jQuery擴展一個名叫fun1()的方法.然后能直接調用它
$('div').fun1(); //this is an extend functionextend()方法的基本思想就是把指定對象的方法都復制給jQuery或者jQuery.prototype對象!?
jQuery.extend = jQuery.fn.extend = function( obj ) {for ( var name in obj ) {this[ name ] = obj[ name ];}return this; }?知識拓展
jQuery中的extend()方法遠比上面幾行代碼復雜,強大!下面是官網提供的API.
jQuery.extend( target, [ object1 ], [ objectN ] );//example var object1 = {apple: 0,banana: {weight: 52, price: 100},cherry: 97 }; var object2 = {banana: {price: 200},durian: 100 };jQuery.extend( object1, object2 ); //result var object1 = {apple: 0,banana: {weight: 52, price: 100}, durian: 100,cherry: 97 }?
target:屬性合并后的集合.
object[1...n]:待合并的屬性,若target沒有則直接加入,否則重寫(覆蓋).
1.若有新屬性合并進來,則破壞了target原來的結構.
jQuery.extend( { }, target, [ object1 ], [ objectN ] ); //合并后的結果將輸入到{ }中.//example var defaults = { validate: false, limit: 5, name: "foo" }; var options = { validate: true, name: "bar" };var merge = jQuery.extend( { }, defaults, options );//result /* var defaults = { validate: false, limit: 5, name: "foo" }; var options = { validate: true, name: "bar" }; var merge = {"validate":true,"limit":5,"name":"bar"}; */?2. 若extend()接受的參數是唯一的.則合并到jQuery的環境中去.
jQuery.extend( target );//test jQuery.extend({test: function() {console.log( 'I'm an example' );} })jQuery.test(); //I'm an example帶選項的深度extend()方法
jQuery.extend( [ deep ], target, object1, [ objectN ] );deep(boolean): 若取值true,將會遞歸的合并(深度copy).
其它的參數含義如上.
何為深度copy?
//example var object1 = {apple: 0,banana: {weight: 52, price: 100},cherry: 97 }; var object2 = {banana: {price: 200},durian: 100 };jQuery.extend( true, object1, object2 );//result /* var object1 = {apple: 0,banana: {weight: 52, price: 200},cherry: 97,durian: 100 } */?深度copy:為每個子對象遞歸調用extend()方法!
源碼解析
jQuery.extend = jQuery.fn.extend = function() {/** options: 復制操作的對象及object[1...n]* name: object[1...n]里面的每項* src: 目標對象* copy: 復制的項目,也是遞歸copy的操作對象* copyIsArray: copy的對象是數組* clone: 需要遞歸copy的目標對象* */var options, name, src, copy, copyIsArray, clone,//復制操作的目標對象target = arguments[0] || {},i = 1,length = arguments.length,//是否進行深度copydeep = false;//若傳遞的第一個參數是boolean(false,true),則處理是否深度copyif ( typeof target === "boolean" ) {deep = target;//第二個參數變成copy的目標對象target = arguments[1] || {};//掠過boolean值i = 2;}// 若目標對象為字符串則置空對象targetif ( typeof target !== "object" && !jQuery.isFunction(target) ) {target = {};}//唯一參數的時候,目標對象是當前環境thisif ( length === i ) {target = this;--i;}//處理需要進行copy的對象for ( ; i < length; i++ ) {//只對非空對象進行處理if ( (options = arguments[ i ]) != null ) {for ( name in options ) {//相當于hash查找target中是否有name這一項,沒有則加入,有則重寫src = target[ name ];copy = options[ name ];//阻止死循環發生if ( target === copy ) {continue;}//若copy是一個對象或者是一個數組,則進行遞歸的copyif ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {if ( copyIsArray ) {copyIsArray = false;//相當于上面的target = {}; 定義進行遞歸copy的目標對象clone = src && jQuery.isArray(src) ? src : [];} else {clone = src && jQuery.isPlainObject(src) ? src : {};}//遞歸調用target[ name ] = jQuery.extend( deep, clone, copy );//其它情況則直接重寫!} else if ( copy !== undefined ) {target[ name ] = copy;}}}}//返回合并后的對象return target; };發現的問題
源碼中有一點值得注意的:
// 若目標對象為字符串則置空對象target if ( typeof target !== "object" && !jQuery.isFunction(target) ) {target = {}; }?其實不能只單純的理解為目標對象為字符串!分析源碼不難發現.這里的條件是:
target不是"object",并且target也不是"function "!怎么說呢?如下:
var object1 = {name: 'Poised-flw',age: 20 }//Number var test1 = jQuery.extend( 123, object1 ); //Object {name: "Poised-flw", age: 20} //String var test2 = jQuery.extend( 'Poised-flw', object1 ); //Object {name: "Poised-flw", age: 20} //Array var test3 = jQuery.extend( [ 1, 3, 4 ], object1 ); //Object {name: "Poised-flw", age: 20} //...more//以上的用法其實就相當于 var test = jQuery.extend( { }, object1 );話說還有個更奇妙的地方.當typeof target是"function"的時候會產生什么樣的結果?
var object1 = {name: 'Poised-flw',age: 20,test: 'haha' }var fun = function() {console.log('I'm a function'); }var result = jQuery.extend( fun, object1 );/*something interesting*/ typeof result; //"function" result(); //'I'm a function' result['name']; //"" result['age']; //20 result.test; //"haha"函數還能這么用,這玩意不多見...井底之蛙了...@^@
不過還有個問題呀...^_^
result.name; //"" 為什么不是"Poised-flw" result['name']; //"" 為什么不是"Poised-flw"以下是解釋:
function.name
name屬性返回一個function的名字,當function是一個匿名函數的時候返回一個空串(Chrome & Opera & Firefox & Safari),IE不支持此屬性(undefined)!
//example 1 function doSomething() {console.log(doSomething.name); //expcept IE: "doSomething", but for IE: undefined }//example 2 var fun = function() {console.log(fun.name); //except IE: "", and for ie: undefined }注意:name屬性是只讀屬性,并不允許修改!就像length屬性一樣.
//the name property var fun = function() {//... }//the same with length console.log(fun.name); //"" fun.name = "Poised-flw"; //"Poised-flw" console.log(fun.name); //""//the length property console.log( (function() {}).length ); //0 console.log( (function(a, b) {}).length ); //2//for firefox. function.length does not include the "rest parameter" /*About rest parameter:以...開始的參數,代表一個數組.范圍是從0到數組的長度function(a, b, ...Args) { //... } */ console.log( (function(a, ...Args) {}).length ); //1//notice! arguments.length將返回實際傳入函數的參數個數
/*
* function f( a, b, c, d ) {
* console.log( f.length );
* console.log( arguments.length );
* }
* f( 1, 2, 3 ); //4, 3
*/
到此自己的jquery框架也算具備可擴展性了!接下來就是豐富它!
轉載于:https://www.cnblogs.com/Poised-flw/archive/2013/04/24/3040630.html
總結
以上是生活随笔為你收集整理的jquery内核学习(6)--扩展实现extend的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 不坚挺的const
- 下一篇: Linq to objects示例