Autor | Zpráva | ||
---|---|---|---|
Suta Profil |
#1 · Zasláno: 7. 1. 2011, 16:22:40 · Upravil/a: Suta
Jelikož mě zajímá, jak funguje jQuery vevnitř, pustil jsem se do rozboru jeho zdrojového kódu. jQuery má dost komplikovaný kód, ale s trochou snahy se dá rozluštit základní schéma. Bohužel, ani po dlouhém hledání jsem nenašel vysvětlení, jak "konkrétně" jQuery funguje a jak je postaven, tak jsem se do jeho rozboru pustil sám.
Přidávám kód, který jsem z jQuery dostal a prosím zkušenější o vysvětlení částí, u kterých ještě tápu. Otázky jsou nastíněny v závěru hlavního příspěvku pod kódem. Pozn.: kód je co nejvíce zestručněn, obsahuje pouze hlavní funkční prvky bez jakýchkoliv ošetření. <script type="text/javascript"> // 1. (function() { var jQuery = (function() { // 2. var jQuery = function( selector ) { // 3. return new jQuery.fn.init( selector ); } // 4. jQuery.fn = jQuery.prototype = { init: function( selector ) { var elem = // zpracujeme selektor a vytahneme id elementu elem = document.getElementById(elem); // 5. ( tipuji že this===jQuery.fn) // 6. tady je stěžejní část; pokud this ukazuje na metodu fn() (tedy na funkci), // jakým způsobem je pak docíleno uložení elementu do indexu pole ? ( this[0]) this.length = 1; this[0] = elem; this.context = document; this.selector = "#test"; return this; } }; // 7. jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { var target = this; var options = arguments[0]; // 8. přidáme vlastní metody (rozšíříme základní objekt jQuery) for ( var name in options ) { var src = options[ name ]; target[ name ] = src; } return target; }; // 9. vytvoříme globální objekt jQuery (případně $) return (window.jQuery = window.$ = jQuery); })(); jQuery.fn.extend({ // 10. přidáme vlastní metody addClass: function( value ) { var classNames = value; var elem = this[0]; elem.className = value; return this; }, dalsiMetoda: function( xxx ) { // ... } }); })(); </script> 1. Vytvořením soukromého bloku nebudeme špinit globální kontext 2. Definujeme lokální kopii jQuery 3. jQuery object je aktuálně pouze rozšiřující init constructor 4. Proč je hlavní metoda jQuery.fn.init přiřazena také do do prototypu jQuery ? 7. Nerozumím. V kódu je celkem 10. zarážek, za jakékoliv připomínky a vysvětlení jakékoliv z nich budu moc vděčný. |
||
ah01 Profil |
#2 · Zasláno: 7. 1. 2011, 18:58:47
Upozorňuji, že abys pochopil všechny aspekty, musíš mít dobré znalosti JavaScriptu, zejména prototypové dědičnosti a věcí s tím spojených (co je to prototype objektu, co dělá new, jak funguje instanceof atd.).
1. Správně. 2. To je definice funkce jQuery. To je ta funkce, kterou voláš, když ve svém skriptu zavoláš $(...). Viz bod 9. 3. „jQuery object je aktuálně pouze rozšiřující init constructor“ To jsi trochu nepřesně přeložil komentář ze zdrojového kódu. Ono tam spíš stojí: „jQuery objekt je vlastně jen ‚vylepšený‘ konstruktor init“ Ve chvíli kdy voláš $(...), vytvoří se nová instance objektu jQuery.fn.init (bod 3). Prototype tohoto objektu je jQuery.fn (bod 7). 4. Teď nevím přesně na co se ptáš. Proč je konstruktor init v objektu jQuery.fn? Nebo proč je jQuery.fn = jQuery.prototype? První otázkou si nejsme jistý. Možná to má nějaký hlubší smysl, ale každopádně mi připadá logické, aby konstruktor byl součástí objektu. Druhá otázka má celkem jasnou odpověď – aby fungoval operátor instanceof nad jQuery objektem: jQuery("#něco") instanceof jQuery === true; 5. Tipuješ špatně. this instanceof jQuery.fn.init this instanceof jQuery 6. „pokud this ukazuje na metodu fn()“ Neukazuje, viz bod 5. „jakým způsobem je pak docíleno uložení elementu do indexu pole“ Na tom není nic zvláštního. Proč by se prvek objektu nemohl jmenovat 0, 1, 2, … To je normální chování JS. Objekt jQuery (jeho instance) se tváří jako pole, i když jím není. Následující kód bude normálně fungovat: var divs = $("div"); for(var i = 0; i < divs.length; i++) { divs[i].… } 7. viz bod 3 8. viz http://api.jquery.com/jQuery.extend/ 9. a 10. Správně. |
||
Suta Profil |
#3 · Zasláno: 8. 1. 2011, 10:54:27
ah01:
Nejprve velké díky ohledně doplnění mých nejasností, vážím si tvého času. A1. Mohl by být úplně první řádek kódu knihovny jQuery zapsán bez deklarace (v tebou uvedeném odkazovaném kódu funkce jQuery není zabalena do soukromého bloku)? Tedy místo (function() { var jQuery = (function() { // vnitřní kód jQuery }) () })() použít pouze (function() { ... })() bez přiřazení do var? Podle mě by se jednalo o totéž, protože hned po této deklarace je definována další - lokální proměnná var jQuery (ta, která hraje roli hlavního konstruktoru), která je v závěru bloku exponována do globálního oboru. A2. K mé otázce číslo 6: „jakým způsobem je pak docíleno uložení elementu do indexu pole ? ( this[0])“ Ano, máš pravdu, prvek objektu je skutečně možné pojmenovat pomocí čísla, nevěděl jsem o této možnosti u objektů. mujObjekt[0] = // funguje mujObjekt.0 = // (nula) - chyba A3. Záhadné pro mě totiž bylo explicitní nastavení vlastnosti length na hotnotu 1 [řádek 141-143 v tebou odkazovaném zdroji] : // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; Vlastnost length u objektu má hodnotu undefined (i po zápisu mujObjekt[2] = "xxx", protože se v podstatě jedná o přiřazení vlastnosti). Chápu tedy správně, že this.length = 1 na řádku 141 je vytvoření nové vlastnosti length pro objekt? (tedy odlišné vlastnosti jako je length u pole, která značí počet prvků). var xx = {}; xx[0] = "test"; xx[1] = "test"; xx[2] = "test"; xx.context = document; // xx.length === undefined; xx.length = 3; // toto chápu jako pomocnou vlastnost pro uložení počtu objektů definovaných pomocí číselného indexu A4. Toto je můj odhad, jakým způsobem pracuje jQuery a jakým je docílo řetězení dotazů pomocí tečkové notace. Prosím o opravení, pokud se pletu. var mujObjekt = { a: function() { this[0] = "a"; // mujObjekt[0] == "a"; return this; // kontext nastavíme na mujObjekt }, b: function() { this[0] = "b"; // mujObjekt[0] == "b"; return this; // kontext nastavíme na mujObjekt } } mujObjekt.a().b().a().b(); ah01: „Upozorňuji, že abys pochopil všechny aspekty, musíš mít dobré znalosti JavaScriptu, zejména prototypové dědičnosti a věcí s tím spojených (co je to prototype objektu, co dělá new, jak funguje instanceof atd.).“ Studiem objektového programování v javascriptu se bavím více než rok (jako koníček). Problémem pro mě byl nedostatek kvalitních zdrojů. Za tu dobu jsem koupil 6 knih o javascriptu, dva týdny zpátky se mi však do ruky dostala kniha "Profesionální javascript pro webové vývojáře" (stála 910,- Kč). Nic lepšího o javascriptu v ČR neexistuje. Jediná kniha, která vysvětluje, jak se mají správně definovat funkce, jak funguje prototype, constructor, uzávěry... Zodpověděla mi otázky, které jsem půl roku složitě hledal na internetu, a zodpověděla je v kompaktní, přehledné, a obsáhlé formě. Doporučuju všem, kdo to myslí s javascriptem vážně. Za jakékoliv další postřehy k výše uvedenému předem velké díky! |
||
ah01 Profil |
#4 · Zasláno: 8. 1. 2011, 13:12:18
A1.
Nemohl, přestalo by totiž fungovat jQuery.noConflict (kód), respektive noConflict by fungovalo, ale po jeho zavolání by přestalo fungovat všechno ostatní ;). Ono je tam těch lokálních proměnných jQuery víc. Musíš si všímat v jakém kontextu. (function () { // core.js var jQuery = (function () { // definice jQuery objektu var jQuery = function( selector ) { return new jQuery.fn.init( selector ); }; // původní obsah window.jQuery a window.$ // co kdyby byl na stránce jiný framework používající identifikátor „$“ var _jQuery = window.jQuery, _$ = window.$; // tady je ta vlastní funkcionalita, např.: noConflict: function (deep) { window.$ = _$; if (deep) window.jQuery = _jQuery; return jQuery; },… // umístíne jQuery do globálního kontextu (jQuery a $) a taky jej vrátíme return (window.jQuery = window.$ = jQuery); })(); // další součásti - animace, ajax,... závysející na jQuery })(); A3. Ano, přesně tak. Tváří se to jako pole, ale pole to není, takže length musíš nastavovat sám. A4. Ano, klíčové je return this;. Říká se tomu chaining (řetězení). Viz např. Maintaining Chainability na stránce věnované vývoji puginů pro jQ. Suta: Kniha JavaScript pro webové vývojáře, Programujeme profesionálně – „Doporučuju všem, kdo to myslí s javascriptem vážně.“ Nemůžu než souhlasit! Četl jsem první vydání této knihy (2005) a až s ní mě začal JavaScript opravdu bavit. U nás vyšel loni překlad druhého vydání. Internet a Google je fajn zdroj informací, ale kniha je kniha! |
||
Časová prodleva: 3 dny
|
|||
Suta Profil |
#5 · Zasláno: 11. 1. 2011, 15:06:46 · Upravil/a: Suta
Rád bych poprosil o zhodnocení způsobu vytváření elementů, který mě napadl.
Vytvářím aplikaci, která je 100% dynamická. Veškerý kód HTML je tedy vytvářen dynamicky pomocí javascriptu = každý element ve stránce je vytvořen pomocí metody document.createElement. Vytvářím-li pro elementy jazyka HTML speciální metody a vlastnosti, můžu je tradičně aplikovat několika způsoby. 1. Zavolám klasickou funkci, které zašlu element, ta s ním provede požadovanou operaci. Vyřazeno! 2. Rozšířím nativní objekt javascriptu Object. Vyřazeno! 3. Rozšířím element o danou metodu. Vyřazeno! 4. Použiji některou z javascriptových knihoven, nebo vytvořím vlastní na principu některé z rozšířených knihoven. Nevyřazeno, nicméně: Napadl mě tento přístup. Vytvářím-li všechny elementy pomocí metody document.createElement, vytvoření metod, které by mohly veškeré elementy používat bych mohl provést pomocí prototypu takto: // definice konstruktoru function MyDocumentCreateElement = function(tagName) { this.el = document.createElement(tagName); } // vytvoření metod MyDocumentCreateElement.prototype.fadeOut = function() { // pracuj s this.el } // vytvoření elementu var myDiv = MyDocumentCreateElement("div"); // zavolání metody myDiv.fadeOut(); Samozřejmě by veškeré elementy neměly přístup ke všem metodám. Vytvořil bych speciální strukturu dědičnosti, kdy by určité mnou definované speciální typy elementů dědily všechny společné metody a navíc měly přístup ke svým specifickým metodám. Tedy stejný princip, jakým datový typ v javascriptu přistupuje k metodám konstruktoru (objekt typu Array má přístup k metodám konstruktoru Array a zároveň sdílí všechny metody definované v hlavním objektu Object). Tento přístup mi přijde odlehčenější než např. způsob, jež používá jQuery (není myšleno jako kritika, jQuery a drtivá většina podobných frameworků musí pracovat s elementy, jež jsou od začátku začleněny v kódu HTML). Prosím o postřehy, pozitivní či negativní dopady k výše uvedenému. |
||
Witiko Profil |
#6 · Zasláno: 11. 1. 2011, 19:24:55 · Upravil/a: Witiko
Suta:
„1. Zavolám klasickou funkci, které zašlu element, ta s ním provede požadovanou operaci. Vyřazeno!“ Rozdíl mezi tímto a Tebou na konci nabízeným řešením je marginální. 1. způsob (ten vyřazený) // vytvoření metod var fadeOut = function(el) { // pracuj s el } // vytvoření elementu var myDiv = document.createElement("div"); // zavolání metody fadeOut(myDiv); 2. způsob // definice konstruktoru function MyDocumentCreateElement = function(tagName) { this.el = document.createElement(tagName); } // vytvoření metod MyDocumentCreateElement.prototype.fadeOut = function() { // pracuj s this.el } // vytvoření elementu var myDiv = MyDocumentCreateElement("div"); // zavolání metody myDiv.fadeOut(); Momentálně jediný rozdíl je v tom, že tvoříš dvě nové instance objektu namísto jedné. A ano, nedochází k zanesení jmenného prostoru. „Prosím o postřehy, pozitivní či negativní dopady k výše uvedenému.“ Není na tom moc ke komentování. Jde o standardně používaný postup, který je omotaný v OOP. Prototypování celému modelu v příkladu, který ukazuješ, nepřináší žádné výhody. |
||
Suta Profil |
#7 · Zasláno: 12. 1. 2011, 07:48:06
Witiko:
Ano, v této jednoduché verzi by bylo zbytečné tvořit speciální konstruktor. Nicméně u velkého projektu je objektový přístup neocenitelný, přijde mi to, jako bychom se pustili do debaty o tom, zda je objektově orientovaný přístup výhodnější než klasický přístup pomocí funkcí. Podle mě záleží na složitosti projektu. Už teď si dokážu představit desítky situací, s nimiž bych při použití klasické funkce měl problém, nebo bych musel stejný případ řešit mnohem složitěji. Chtěl jsem vědět o negativech, o nichž možná nevím. Vytvoření objektu "navíc" mi přinese více výhod. |
||
Witiko Profil |
#8 · Zasláno: 12. 1. 2011, 14:59:40
Suta:
„Už teď si dokážu představit desítky situací“ Tak je tu nastiň, pak se můžeme bavit o adekvátnosti a případných problémech daného postupu. |
||
Časová prodleva: 13 let
|
0