深入理解jQuery框架-框架結構


 這是本人結合資料視頻總結出來的jQuery大體框架結構,如果大家都熟悉了之后,相信你們也會寫出看似高檔的js框架;

 jquery框架的總體結構

(function(w, undefined){
    //定義一些變量和函數   
    var
    //對外提供的接口
    jQuery = function( selector, context ) {
        return new jQuery.fn.init( selector, context, rootjQuery );
    };

    //結jQuery對象添加一些方法和屬性

    //jQuery的繼承方法

    //jQuery.extend 擴展一些工具的方法(靜態方法) jQuery.trim();

    //Sizzle 復雜選擇器的實現

    //Callbacks 回調對象--函數的統一管理

    //Deferred 延遲對象,對異步的統一管理

    //support 功能檢測

    //Data 數據緩存     

    //queue 隊列管理

    //Attribute 屬性操作

    //Event 事件處理

    //DOM操作 添加刪除、包裝篩選等

    //CSS操作

    //提交的數據和ajax

    //運動/動畫 FX

    //坐標和大小

    //支持的模塊化的模式
    
    w.jQuery = w.$ = jQuery;
    
})(window);

 

 


 

jquery為什么要使用匿名函數來封裝框架

 閱讀jquery源碼,我們可以看出jquery使用的是匿名函數來封裝框架,那么為什么要使用這種方式呢,又有什么好處?

 

1.什么是匿名函數?

// 匿名函數的寫法
function(){
    console.log("test");    
}

// 將變量賦值給一個匿名函數
var test = function(){
    return 0;
}
console.log(test);    //打印的是變量test,即函數
console.log(test()); //打印0,test + ()表示調用這個方法

 

2.匿名函數自調用的方式

匿名函數有兩種調用方式,第一種是()()、第二種是 (())

// ()()調用方式
(function(){ console.log("匿名函數-自調用方法1"); })();
// (())調用方式 (
function(){ console.log("匿名函數-自調用方法2"); }());

 

3.匿名函數傳參

/*錯誤方式*/
(function(window){
    console.log(window);    //undefined    
})();

/*正確方式*/
var jQuery;
(function(win, jQuery){
    console.log(win);    //
})(window, jQuery);

 

4.使用匿名函數對外提供一個接口

(function(w) {
    var Person = function() {
        this.name = "cxb";
        this.talk = function() {
            console.log("hello, I'm " + this.name);    
        }
    }
    
    w.Person = Person;
})(window)

var p = new Person();
console.log(p.name);
p.talk();

 

 

5.使用匿名函數的好處:

防止變量方法沖突 變量與方法是獨立的,寫在匿名函數的變量或函數屬於局部的,不會受外面的干擾,也不會影響全局變量

(function(){
    var a = 10;
    
    var fun = function() {
        console.log("fun method");    
    }
})();
console.log(a);           //報錯 undefined
fun();                    //報錯 fun is not a function

 

 

 


 

 為什么可以直接使用jQuery 或 $為調用jquery方法?

 

 

 

 

對象創建的比較

 

創建對象方式一:

function Student() {
    this.name = "cxb";
    this.talk = function() {
        return "我叫" + this.name;
    }
}
var stu1 = new Student();
var stu2 = new Student();

 

創建對象方式二:

function Student() {
    this.name = "cxb";
}
Student.prototype.talk = function() {
    return "我叫" + this.name;
}
var stu1 = new Student();
var stu2 = new Student();

 

方式一與方式二產生的結構幾乎是一樣的,而本質區別就是:方式二new產生的二個實例對象共享了原型的talk方法,這樣的好處節省了內存空間,方式一則是要為每一個實例復制talk方法,每個方法屬性都占用一定的內存的空間,所以如果把所有屬性方法都聲明在構造函數中,就會無形的增大很多開銷,這些實例化的對象的屬性一模一樣,都是對this的引用來處理。除此之外方式一的所有方法都是拷貝到當前實例對象上。方式二則是要通過scope連接到原型鏈上查找,這樣就無形之中要多一層作用域鏈的查找了。

所以說在jQuery中,可以看到很多 jQuery.fn 這樣的寫法(事實上在jQuery中,使用jQuery.fn替換了jQuery.prototype)。

 

 

 

 

 

 

 

 


 

淺拷貝與深拷貝

 

1. js對象的淺拷貝

var a = [1,2,3];
var b = a;
var c = {name:"cxb", age:26};
var d = c;
console.log(a);
console.log(b);
console.log(c);
console.log(d);

[1, 2, 3]
[1, 2, 3]
Object {name: "cxb", age: 26}
Object {name: "cxb", age: 26}

 

b[2] = 5;
d.age = 20;
console.log(a);
console.log(b);
console.log(c);
console.log(d);

[1, 2, 5]
[1, 2, 5]
Object {name: "cxb", age: 20}
Object {name: "cxb", age: 20}

 

 

 

 

2.js數組的深拷貝

var arr1 = [1, 2, 3];
var arr2 = [];

function deepCopy(arr1, arr2) {
   for(var i=0; i<arr1.length; i++) {
       arr2[i] = arr1[i];
   }
}
deepCopy(arr1, arr2);
console.log(arr1);
console.log(arr2);    
arr2[2] = 5;
console.log(arr1);
console.log(arr2);

[1, 2, 3]
[1, 2, 3]
[1, 2, 3]
[1, 2, 5]

 

 

 

3.js對象的深拷貝

function Parent() {
    this.name = "李四";
    this.age = 40;
    this.talk = function() {
        console.log("hello, I'm "+ this.name);    
    }    
}

function Child() {
    this.name = "張三";
    this.age = 20;
    this.sound = function() {
        console.log("haha");    
    }        
}
Child.prototype = new Parent();
var child = new Child();
for(var key in child) {
    console.log(key);    
}

 

 

 

4.hasOwnProperty來過濾原型鏈上的屬性

for(var key in child) {
    if(child.hasOwnProperty(key))
    console.log(key);    
}

 

 

 

 

5.完整clone一個對象的方法

var child = new Child();
var childObject = {};
for(var key in child) {
    if(child.hasOwnProperty(key))
    childObject[key] = child[key];    
}
console.log(childObject.name);
console.log(childObject.age);
childObject.sound();
childObject.talk();

 

 

 

 


 

jQuery框架的實現原理

 

/******************** jQuery 框架部分 ************************/
(function(w, undefined){
//第一步:創建一個jQuery函數
var jQuery = function() {
    //第四步:
    return new jQuery.fn.init();    
}

//第三步:
jQuery.fn = jQuery.prototype;    //是覆蓋prototype

jQuery.fn = {
    //當創建了一個函數之后,js源碼會自動生成 jQuery.prototype.constructor = jQuery;
    //在jQuery中使用這個是為了防止惡意修改:如 jQuery.prototype.constructor = Array;
    constructor : jQuery,
    
    init : function() {
        return this;
    },
};
jQuery.fn.init.prototype = jQuery.fn;    //如果不使用這個,在第四步當中是無法使用new的

//第五步:使用extend將jQuery模塊化(其實原碼並不是這樣的)這里使用了拷貝,關於拷貝請看 4.js淺拷貝與深拷貝
//好處:插件擴展時直接使用此方法
jQuery.fn.extend = jQuery.extend = function( ) {                                                                                                                                                                     var target = this, source = arguments[0] || { } ;
    for(var key in source) {
        if(source.hasOwnProperty(key)) {
            jQuery.fn[key] = jQuery[key] = source[key];    
        }
    }
    return target;
}


//第六步:模塊一
jQuery.fn.extend({
    
    html : function() {},    
    
    text : function() {},
    
});

//第六步:模塊二
jQuery.extend({
    
    ajax : function() {
        //處理json格式的參數及回調函數success,error
        console.log("ajax method");    
    },    
    
    each : function() {},
});

//第二步:對外提供一個接口
w.jQuery = w.$ = jQuery;

    
})(window);

//測試1
jQuery.ajax();


//測試2:外部框架的擴展
/******************** 基於jQuery框架的ui框架部分 ************************/
(function(w, jQuery) {
    //jQuery對象的方法擴展
    jQuery.fn.extend({
        drag : function() {
            console.log("drag method");
        },
        
        dialog : function() {
            console.log("dialog method");
        },
    });
    //jQuery類的方法擴展
    jQuery.extend({
        tool : function() {
            console.log("tool method");
        },
        //....
    });
})(window, jQuery);

 

 

 

 


 示例

<html lang="zh-CN">
<head>
<script>
(function(win, undefined){ var doc = win.document; var loc = win.location; var jQuery; jQuery = function(selector, context){ return new jQuery.fn.init(selector, context); } var _jQuery = win.jQuery, _$ = win.$; jQuery.fn = jQuery.prototype; jQuery.fn = { constructor: jQuery, init : function(selector, context){ if(selector.charAt(0)=="#"){ this.context = doc.getElementById(selector.substr(1)); }else if(selector.charAt(0)=="."){ this.context = doc.getElementsByName(selector.substr(1)); }else if(selector.charAt(0)==":"){ this.context = doc.getElementsByTagName(selector.substr(1)); }else{ this.context = doc.getElementsByTagName(selector); } return this; } } jQuery.fn.init.prototype = jQuery.fn; jQuery.fn.extend = jQuery.extend = function() { var target = this; var source = agruments[0] || { }; for (var p in source) { if (source.hasOwnProperty(p)) { target[p] = source[p]; } } return target; } // 對象的方法 jQuery.fn.extend( { val : function() { if((typeof _value)=="undefined"){ return this.context.value; }else if((typeof _value)=="string"){ return this.context.value=_value; } }, html : function() {}, text : function() {}, attr : function() {}, prop : function() {}, //... }); // CSS操作 jQuery.fn.extend( { addClass : function() {}, removeClass : function() {}, css : function() {}, //... }); // 插件擴展的方法 jQuery.extend( { ajax: function() {}, each: function() {}, when: function() {}, //... });
// 對外提供的接口,即使用$ 或 jQuery win.jQuery
= win.$ = jQuery; })(window); window.onload = function(){ var value = jQuery("#test").val(); console.log("------"+value); }
</script>
</head>

<body>
<input type="text" id="test" value="123456" />
</body>
</html>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM