Heim > Web-Frontend > js-Tutorial > jQuery 2.0.3 Quellcode-Analysekern (1) Gesamtarchitektur_jquery

jQuery 2.0.3 Quellcode-Analysekern (1) Gesamtarchitektur_jquery

WBOY
Freigeben: 2016-05-16 16:46:40
Original
1075 Leute haben es durchsucht

Wenn Sie über ein Open-Source-Framework lesen, möchten Sie vor allem die Designideen und Implementierungstechniken erfahren.

Nicht viel Unsinn, die JQuery-Analyse ist seit so vielen Jahren schlecht, ich habe es vor langer Zeit gelesen,

Allerdings habe ich in den letzten Jahren an mobilen Endgeräten gearbeitet und immer zepto verwendet. Vor kurzem habe ich mir wieder etwas Zeit genommen, um jquery zu scannen

Ich werde den Quellcode nicht gemäß dem Skript übersetzen, also lesen Sie ihn bitte basierend auf Ihrer eigenen tatsächlichen Erfahrung!

Das Neueste auf Github ist jquery-master, das der AMD-Spezifikation beigetreten ist. Ich verweise auf die neueste offizielle Version 2.0.3

Gesamtstruktur

Der Kern des jQuery-Frameworks besteht darin, Elemente aus HTML-Dokumenten abzugleichen und Operationen an ihnen auszuführen,

Zum Beispiel:

Code kopieren Der Code lautet wie folgt:

$().find().css ()
$().hide().html('....').hide().

Mindestens 2 Probleme können dem obigen Text entnommen werden

1. Wie jQuery-Objekte aufgebaut sind

2. So rufen Sie die jQuery-Methode auf

Analyse 1: Die neufreie Konstruktion von jQuery

JavaScript ist eine funktionale Sprache. Klassen können das grundlegendste Konzept der objektorientierten Programmierung sein

Code kopieren Der Code lautet wie folgt:
var aQuery = function(selector, context) {
//Konstruktor
}
aQuery.prototype = {
//Prototyp
name:function(){},
age:function(){}
}
var a = new aQuery();

a.name();


Dies ist die normale Verwendung. Es ist offensichtlich, dass jQuery so nicht funktioniert

jQuery verwendet den neuen Operator nicht, um die jQuery-Anzeige zu instanziieren, oder ruft seine Funktion direkt auf

Folgen Sie der Schreibmethode von jQuery

Code kopieren Der Code lautet wie folgt:
$().ready()
$( ).noConflict()

Um dies zu erreichen, muss jQuery als Klasse betrachtet werden, dann sollte $() eine Instanz der Klasse zurückgeben

Also ändern Sie den Code:

Code kopieren Der Code lautet wie folgt:
var aQuery = function(selector, context) {
Return new aQuery();
}
aQuery.prototype = {
name:function(){},
age:function(){}
}

Durch new aQuery() können wir, obwohl eine Instanz zurückgegeben wird, immer noch ein offensichtliches Problem erkennen, eine Endlosschleife!

Wie kann man also eine korrekte Instanz zurückgeben?

Diese Instanz in Javascript bezieht sich nur auf den Prototyp

Dann können Sie die jQuery-Klasse als Factory-Methode zum Erstellen von Instanzen verwenden und diese Methode in den jQuery.prototye-Prototyp einfügen

Code kopieren Der Code lautet wie folgt:
var aQuery = function(selector, context) {
Return aQuery.prototype.init();
}
aQuery.prototype = {
init:function(){
return this;
}
name:function (){ },
age:function(){}
}

Instanz, die zurückgegeben wird, wenn aQuery() ausgeführt wird:

Offensichtlich gibt aQuery() eine Instanz der aQuery-Klasse zurück, sodass dies in init tatsächlich auf eine Instanz der aQuery-Klasse verweist

Das Problem besteht darin, dass this in init auf die aQuery-Klasse verweist. Wenn die init-Funktion auch als Konstruktor verwendet wird, wie geht man dann mit dem internen this um?

Code kopieren Der Code lautet wie folgt:
var aQuery = function(selector, context) {
Return aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
},
Name: function() {},
Alter: 20
}
aQuery().age //18


In diesem Fall geht etwas schief, da dies nur auf die aQuery-Klasse verweist, sodass Sie einen unabhängigen Bereich entwerfen müssen

Separate Bereichsverarbeitung des JQuery-Frameworks

Code kopieren Der Code lautet wie folgt:

jQuery = function( selector, context ) {
// Das jQuery-Objekt ist eigentlich nur der „erweiterte“ Init-Konstruktor
return new jQuery.fn.init( selector, context, rootjQuery );
},

Natürlich wird durch die Instanz-Init-Funktion jedes Mal ein neues Init-Instanzobjekt erstellt, um dies zu trennen und Interaktionsverwechslungen zu vermeiden

Da es sich also nicht um dasselbe Objekt handelt, muss ein neues Problem entstehen

Zum Beispiel:

Code kopieren Der Code lautet wie folgt:

var aQuery = function(selector, context) {
Return new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
this.age = 18
return this;
} ,
Name: function() {},
Alter: 20
}

//Uncaught TypeError: Object [object Object] has no method 'name'
console.log(aQuery().name())

Es wird ein Fehler ausgegeben und diese Methode kann nicht gefunden werden. Daher ist es offensichtlich, dass die Init-Initialisierung von new von dieser der JQuery-Klasse getrennt ist

Wie greife ich auf die Eigenschaften und Methoden des jQuery-Klassenprototyps zu?

Wie können wir nicht nur den Bereich isolieren, sondern auch den Bereich des jQuery-Prototypobjekts nutzen? Können wir auch auf das jQuery-Prototypobjekt in der zurückgegebenen Instanz zugreifen?

Wichtige Punkte der Umsetzung

Code kopieren Der Code lautet wie folgt:

// Geben Sie der Init-Funktion den jQuery-Prototyp für spätere Instanziierung
jQuery.fn.init.prototype = jQuery.fn;

Lösen Sie das Problem durch Prototypenübergabe und übergeben Sie den jQuery-Prototyp an jQuery.prototype.init.prototype

Mit anderen Worten: Das Prototypobjekt von jQuery überschreibt das Prototypobjekt des Init-Konstruktors

Da es als Referenz übergeben wird, besteht kein Grund zur Sorge über das Leistungsproblem dieser Zirkelreferenz

Code kopieren Der Code lautet wie folgt:

var aQuery = function(selector, context) {
Return new aQuery.prototype.init();
}
aQuery.prototype = {
init: function() {
Return this;
},
name : function( ) {
return this.age
},
age: 20
}
aQuery.prototype.init.prototype = aQuery.prototype;
console.log(aQuery ().name()) //20

Baidu hat sich zum einfachen und direkten Verständnis ein Bild von einem Internetnutzer ausgeliehen:

Erklären Sie fn. Tatsächlich hat dieser fn keine besondere Bedeutung, sondern ist nur ein Verweis auf jQuery.prototype

Analyse 2: Kettenanruf

Behandlung von DOM-Kettenaufrufen:

1. JS-Code speichern.

2. Das gleiche Objekt wird zurückgegeben, was die Effizienz des Codes verbessern kann

Erzielen Sie browserübergreifende Kettenaufrufe, indem Sie einfach die Prototyp-Methode erweitern und diese zurückgeben.

Verwenden Sie das einfache Factory-Muster unter JS, um dieselbe Instanz für alle Vorgänge am selben DOM-Objekt anzugeben.

Dieses Prinzip ist super einfach

Code kopieren Der Code lautet wie folgt:

aQuery().init().name ()
Decompose
a = aQuery();
a.init()
a.name()

Wenn man den Code aufschlüsselt, ist es offensichtlich, dass die Grundvoraussetzung für die Realisierung der Verkettung die Existenz der Instanz this ist, und das ist dasselbe

Code kopieren Der Code lautet wie folgt:

aQuery.prototype = {
init : function( ) {
return this;
},
name: function() {
return this
}
}

Wir müssen also nur in einer verketteten Methode darauf zugreifen, da diese die aktuelle Instanz zurückgibt, sodass wir auf unseren eigenen Prototyp zugreifen können

Code kopieren Der Code lautet wie folgt:

aQuery.init().name()

Vorteile: Sparen Sie die Menge an Code, verbessern Sie die Effizienz des Codes und der Code sieht eleganter aus

Das Schlimmste ist, dass alle Objektmethoden das Objekt selbst zurückgeben, was bedeutet, dass es keinen Rückgabewert gibt, der möglicherweise in keiner Umgebung geeignet ist.

Javascript ist eine nicht blockierende Sprache, also nicht blockierend, aber nicht blockierend, daher muss es ereignisgesteuert sein und einige Vorgänge, die den Prozess blockieren müssen, asynchron ausführen. Diese Verarbeitung ist nur eine synchrone Kette. und eine asynchrone Kette jquery Promise wurde seit 1.5 eingeführt, und jQuery.Deferred wird später besprochen.

Analyse 3: Plug-in-Schnittstelle

Das Hauptgerüst von jQuery sieht so aus. Wenn Sie jedoch Eigenschaftenmethoden zu jQuery oder einem jQuery-Prototyp hinzufügen und Entwicklern Methodenerweiterungen zur Verfügung stellen möchten, sollten diese gemäß den allgemeinen Gewohnheiten des Designers bereitgestellt werden Perspektive der Kapselung? Eine Schnittstelle ist die richtige, und es kann wörtlich verstanden werden, dass es sich um eine Erweiterung der Funktion handelt, anstatt den Prototyp einer benutzerfreundlichen Oberfläche direkt zu modifizieren

jQuery unterstützt seine eigenen erweiterten Eigenschaften. Dies stellt eine externe Schnittstelle, jQuery.fn.extend(), zum Hinzufügen von Methoden zu Objekten bereit

Wie Sie dem jQuery-Quellcode entnehmen können, sind jQuery.extend und jQuery.fn.extend tatsächlich unterschiedliche Referenzen, die auf dieselbe Methode verweisen

Code kopieren Der Code lautet wie folgt:
jQuery.extend = jQuery.fn.extend = Funktion( ) {
jQuery.extend erweitert die Eigenschaften und Methoden von jQuery selbst

jQuery.fn.extend erweitert die Eigenschaften und Methoden von jQuery.fn


Mit der Funktion „extend()“ können Funktionen einfach und schnell erweitert werden, ohne die Prototypenstruktur von jQuery zu zerstören

jQuery.extend = jQuery.fn.extend = function(){...}; Dies ist aufeinanderfolgend, dh zwei Punkte zeigen auf dieselbe Funktion. Wie können sie unterschiedliche Funktionen erreichen? Das ist die Kraft davon!

Für fn und jQuery handelt es sich tatsächlich um zwei verschiedene Objekte, wie zuvor beschrieben:

Wenn jQuery.extend aufgerufen wird, zeigt dies auf das jQuery-Objekt (jQuery ist eine Funktion und ein Objekt!), daher befindet sich die Erweiterung hier auf jQuery.

Wenn jQuery.fn.extend aufgerufen wird, zeigt dies auf das fn-Objekt, jQuery.fn und jQuery.prototype zeigen auf dasselbe Objekt, und durch Erweitern von fn wird das jQuery.prototype-Prototypobjekt erweitert.
Was hier hinzugefügt wird, ist die Prototypmethode, bei der es sich um die Objektmethode handelt. Daher stellt die jQuery-API die beiden oben genannten Erweiterungsfunktionen bereit.

Implementierung von Extend

Code kopieren Der Code lautet wie folgt:

jQuery.extend = jQuery.fn.extend = function() {
    var src, copyIsArray, copy, name, options, clone,
        target = arguments[0] || {},    // 常见用法 jQuery.extend( obj1, obj2 ),此时,target为arguments[0]
        i = 1,
        length = arguments.length,
        deep = false;

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {    // 如果第一个参数为true,即 jQuery.extend( true, obj1, obj2 ); 的情况
        deep = target;  // 此时target是true
        target = arguments[1] || {};    // target改为 obj1
        // skip the boolean and the target
        i = 2;
    }

    // Handle case when target is a string or something (possible in deep copy)
    if ( typeof target !== "object" && !jQuery.isFunction(target) ) {  // 处理奇怪的情况,比如 jQuery.extend( 'hello' , {nick: 'casper})~~
        target = {};
    }

    // extend jQuery itself if only one argument is passed
    if ( length === i ) {   // 处理这种情况 jQuery.extend(obj),或 jQuery.fn.extend( obj )
        target = this;  // jQuery.extend时,this指的是jQuery;jQuery.fn.extend时,this指的是jQuery.fn
        --i;
    }

    for ( ; i < length; i++ ) {
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null ) { // 比如 jQuery.extend( obj1, obj2, obj3, ojb4 ),options则为 obj2、obj3...
            // Extend the base object
            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];

                // Prevent never-ending loop
                if ( target === copy ) {    // 防止自引用,不赘述
                    continue;
                }

                // Recurse if we're merging plain objects or arrays
                // 如果是深拷贝,且被拷贝的属性值本身是个对象
                if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
                    if ( copyIsArray ) {    // 被拷贝的属性值是个数组
                        copyIsArray = false;
                        clone = src && jQuery.isArray(src) ? src : [];

                    } else {    被拷贝的属性值是个plainObject,比如{ nick: 'casper' }
                        clone = src && jQuery.isPlainObject(src) ? src : {};
                    }

// Originalobjekte NIEMALS VERSCHIEBEN, sondern klonen
Target [name] = jquery.extEnd (deep, clone, copy); // Rekursiv ~

                                                                                                                                                                           
// Das geänderte Objekt zurückgeben
return target;



Zusammenfassung:

Erstellen Sie ein neues Objekt über new jQuery.fn.init() mit der Prototyp-Prototyp-Objektmethode des Init-Konstruktors.
Durch Ändern der Ausrichtung des Prototyp-Zeigers kann dieses neue Objekt auch auf den Prototyp des Prototyps zeigen jQuery-Klassenprototyp
Das auf diese Weise konstruierte Objekt setzt also alle durch den jQuery.fn-Prototyp definierten Methoden fort

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage