<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ferrante.pl - simplicity of web programming &#187; Vademecum</title>
	<atom:link href="http://ferrante.pl/category/tech/vademecum/feed/" rel="self" type="application/rss+xml" />
	<link>http://ferrante.pl</link>
	<description>Technologie internetowe, PHP5, Python, Javascript. Publicystyka i kursy w najlepszym wydaniu.</description>
	<lastBuildDate>Tue, 01 May 2012 18:21:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Architektura aplikacji JavaScript: Wstęp</title>
		<link>http://ferrante.pl/frontend/javascript/architektura-aplikacji-javascript-wstep/</link>
		<comments>http://ferrante.pl/frontend/javascript/architektura-aplikacji-javascript-wstep/#comments</comments>
		<pubDate>Tue, 12 Apr 2011 12:50:48 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=1248</guid>
		<description><![CDATA[Architektura aplikacji JavaScript to jeden z najczęściej przejawiających się tematów w dyskusjach na temat tego języka. Jest to chyba też jedno z najmniej opisywanych zagadnień w ogóle, zupełnie nieproporcjonalnie do ilości zadawanych pytań. Te formułujemy najczęściej, kiedy musimy napisać dużą aplikację. Równie regularnie głos na temat architektury podnoszą programiści, którzy zaczęli pisać w JS po [...]]]></description>
			<content:encoded><![CDATA[<p>Architektura aplikacji JavaScript to jeden z najczęściej przejawiających się tematów w dyskusjach na temat tego języka. Jest to chyba też jedno z najmniej opisywanych zagadnień w ogóle, zupełnie nieproporcjonalnie do ilości zadawanych pytań. Te formułujemy najczęściej, kiedy musimy napisać dużą aplikację. Równie regularnie głos na temat architektury podnoszą programiści, którzy zaczęli pisać w JS po odejściu od Javy, Pythona czy innych obiektowych języków. Pojawia się rozczarowanie połączone z zaskoczeniem. Jak zatem powinno się pisać w JavaScript?<span id="more-1248"></span></p>
<p>Żeby mówić o architekturze w JS, należy zrozumieć specyfikę tego języka. Nie mamy tutaj klas, dziedziczenie można uzyskać na kilka sposobów, jednocześnie możemy spokojnie pisać, korzystając z paradygmatów programowania funkcyjnego, nie tracąc na efektywności naszych programów. Niestety, bez zrozumienia istoty closures, <span class="f">prototype</span>, kontekstu uruchomienia funkcji nie możemy skutecznie przejść do zagadnienia architektury.</p>
<p>Jeśli nie znasz tych pojęć, pozwól, że krótko je przypomnę. Pamiętaj jednak, że JavaScript jest na tyle specyficznym językiem, że ich zrozumienie może zająć więcej czasu niż przeczytanie tego artykułu. Praktyka czyni mistrza!</p>
<p>Przede wszystkim <s>przeglądarki</s> normalne przeglądarki nie wymyślają JavaScriptu po swojemu. Jest to język oparty na <a href="http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf">specyfikacji o nazwie ECMAScript</a>. Również ActionScript (tak, to, co będzie niedługo wyparte z webu przez HTML5) opiera się na ECMA. Jeśli coś wywoła w Tobie sążniste <em>ale o co tu chodzi, majster?!</em>, to na pewno w powyższym dokumencie znajdziesz odpowiedź na swój programistyczno-egzystencjalny ból.</p>
<p>Podstawą JS są funkcje, zresztą jak w każdym języku. Możemy je zdefiniować tak:</p>
<pre><code>var suma = function(a, b) {
	return a + b;
};</code></pre>
<p>Taki kod, a konkretnie funkcja o nazwie <span class="f">suma</span> pozwoli nam zwrócić wynik dodawania dwóch liczb, które podamy do funkcji:</p>
<pre><code>suma(5, 10); // zwróci 15</code></pre>
<p>To podstawy. By mówić o dobrej architekturze, musimy ją oprzeć na jak najbardziej skalowalnych i tzw. &#8222;reużywalnych&#8221; komponentach. Zapewne więc chciałbyś wiedzieć, jak wykorzystać funkcje do tworzenia obiektów, skoro w JavaScript nie ma klas ani niczego takiego. Jest kilka sposobów, jeden lepszy, drugi gorszy. Pierwszy z nich:</p>
<pre><code>var DataManager = function() {
	this.add = function() {};
	this.get = function() {};
};</code></pre>
<p>Prosta funkcja <span class="f">DataManager</span>, która powinna pomóc tworzyć obiekty do zarządzania danymi. Jak rzeczywiście stworzyć z tego obiekt?</p>
<pre><code>var manager = new DataManager();</code></pre>
<p>Nic prostszego! Zapewne widzisz tutaj analogię do innych języków, gdzie <span class="f">new</span> również pomaga tworzyć nowe obiekty. W ten oto też sposób, <em>DataManager</em> możemy nazwać konstruktorem obiektu (w przyszłości zapewne będę używał tej nazwy na przemian ze słowem &#8222;<em>funkcja</em>&#8222;).</p>
<p>A jakby to wyglądało w JAVA?</p>
<pre><code>public class DataManager {
	public void add() {}
	public void get() {}
}
// [...]
DataManager manager = new DataManager();</code></pre>
<p>W PHP?</p>
<pre><code>class DataManager {
	public function add() {}
	public function get() {}
}
$manager = new DataManager();</code></pre>
<p>Wracając do JS… Dzięki temu, że stworzyliśmy dwie metody: <span class="f">add</span> oraz <span class="f">get</span>, nasz obiekt <span class="f">manager</span> będzie mógł ich użyć:</p>
<pre><code>manager.add("blog", "ferrante.pl");
manager.get("blog");</code></pre>
<p>Ten kod oczywiście nic nie robi, bo funkcje (vel <em>metody</em>) <span class="f">add</span> oraz <span class="f">get</span> zdeklarowaliśmy jako puste:</p>
<pre><code>this.add = function() {};
this.get = function() {};</code></pre>
<p>Dodajmy do nich coś, nie ma znaczenia co, na razie niech to będą komunikaty dla użytkownika (oczywiście w realnym świecie jest to mało prawdopodobne):</p>
<pre><code>var DataManager = function() {
	this.add = function() {
		alert("dodaję!");
	};
	this.get = function() {
		alert("zwracam!");
	};
};</code></pre>
<p>Jak widzisz, <span class="f">this</span> pomógł nam zrobić niesamowity trick (szacuneczek!), by te dwie metody były dostępne dla każdego nowo utworzonego obiektu (u nas <span class="f">manager</span>).</p>
<p><span class="f">this</span> to jednak zguba w JS. Pomińmy <span class="f">new</span> przy tworzeniu nowego obiektu:</p>
<pre><code>var manager = DataManager();</code></pre>
<p>A teraz spróbujmy wywołać nasze metody. </p>
<pre><code>var manager = DataManager();
manager.add("blog", "jsnews.pl");</code></pre>
<p>Ups? Dostajemy błąd, a przyczyna leży w tym, że do <span class="f">manager</span> tym razem nic się nie przypisało, więc bez sensu byłoby wywoływać jakiekolwiek metody na nim. Dlaczego? Otóż bez <span class="f">new</span> wywołujemy tylko funkcję (bez zamiaru tworzenia obiektów). Jeśli ona nic nie zwraca, to też to &#8222;nic&#8221; jest przypisywane do <span class="f">manager</span>. To &#8222;nic&#8221; w JS nazywa się <span class="f">undefined</span> &#8211; oznacza, że OK, przypisaliśmy coś, lecz ta wartość nie została zdefiniowana. Każda funkcja zwraca <em>undefined</em>, jeśli nie zdefiniujemy <span class="f">return</span> na jej końcu. </p>
<pre><code>var suma = function() {};
suma(a, b); // undefined</code></pre>
<pre><code>var suma = function(a, b) {
	return a + b;
};
suma(10, 20); // 30</code></pre>
<p>Jak sprawdzić, czy coś rzeczywiście jest niezdefiniowane? Pomaga nam w tym konstrukcja <span class="f">typeof</span>:</p>
<pre><code>var suma = function() {};
var wynik = suma();

if (typeof wynik === "undefined") {
	alert("funkcja nic nie zwróciła!");
}</code></pre>
<p>Jak widzisz, <em>typeof</em> zwraca stringa, więc jego wynik porównaliśmy do <span class="f">&#8222;undefined&#8221;</span>. <em>Typeof</em> to jeden sposobów na to, by sprawdzić jakiego typu jest zmienna. Zainteresuj się tym w wolnym czasie (możesz też o tym przeczytać w mojej prezentacji <a href="http://varjs.com">varjs.com</a>).</p>
<p>Wracając jednak do naszego przykładu z <span class="f">DataManager</span>. Zrobiliśmy coś takiego:</p>
<pre><code>var manager =  DataManager();
manager.add("blog", "jsnews.pl");</code></pre>
<p>I dostaliśmy błąd. </p>
<p>Ale! Poniższa linijka, już bez jakiejkolwiek obstawy, działa:</p>
<pre><code>var manager =  DataManager();</code></pre>
<p>Nie powoduje ona żadnych komplikacji. Co więc stało się z rzeczami, które przypisaliśmy do <em>this</em>? W sensie, w tym miejscu:</p>
<pre><code>var DataManager = function() {
	this.add = function() {
		alert("dodaję!");
	};
	this.get = function() {
		alert("zwracam!");
	};
};</code></pre>
<p>Otóż, drogi Czytelniku, <span class="f">add</span> oraz <span class="f">get</span> są teraz zmiennymi globalnymi! Na przykład:</p>
<pre><code>&lt;script&gt;
	var DataManager = function() {
		this.add = function() {
			alert("dodaję!");
		};
		this.get = function() {
			alert("zwracam!");
		};
	};

	var manager = DataManager();
&lt;/script&gt;

&lt;script&gt;
	add("cos tam", "cos tam"); // dodaję!
	get("cos tam"); // zwracam!
&lt;/script&gt;
</code></pre>
<p>Tak, <span class="f">add</span> i <span class="f">get</span> są dostępne w każdym ze skryptów na stronie (no chyba, że jakiś je nadpisał…). Zupełnie tak, jakbyś zrobił:</p>
<pre><code>&lt;script&gt;
	var add = function() {
		alert("dodaję!");
	};
	var get = function() {
		alert("zwracam!");
	};
&lt;/script&gt;</code></pre>
<p>Ewidentną zdradę popełnioną przez <span class="f">this</span> dokumentuje poniższy kod:</p>
<pre><code>var fn = function() { return this; };
window === fn();</code></pre>
<p>Tak jest, <em>thisem</em> przy wywołaniu funkcji jest domyślnie obiekt globalny, który w środowiskach przeglądarkowych nazywa się <span class="f">window</span>. Jest to zmienna jak każda inna, dodatkowo jest obiektem, więc można coś do niej przypisywać i używać rzeczy już przypisanych po kropce (jak to w obiektach bywa) np. <span class="f">window.alert(&#8222;yeah!&#8221;);</span>.</p>
<p>Przedstawiłem Ci jeden ze sposobów tworzenia obiektów, jak widzisz nie zawsze bezpieczny (szczególnie, jeśli mamy do czynienia z mniej doświadczonymi programistami JS w zespole). Dodatkowo, teraz już wiesz, dlaczego Douglas Crockford nie lubi <span class="f">new</span>. Jakie mamy alternatywy?</p>
<p>Możemy zwracać gotowy obiekt w każdej z funkcji. W naszym przypadku będzie to tak:</p>
<pre><code>var DataManager = function() {
	return {
		add: function() {
			alert("dodaję!");
		},
		get: function() {
			alert("zwracam!");
		}
	};
};</code></pre>
<p>Proste i klarowne! Zauważmy, że zawsze &#8211; bez znaczenia, czy użyliśmy <em>new</em> czy nie &#8211; dostajemy nowy obiekt:</p>
<pre><code>var manager = new DataManager();
manager.add("blog", "ferrante.pl");
manager.get("blog");

var anotherManager = DataManager();
anotherManager.add("blog", "jsnews.pl");
anotherManager.get("blog");</code></pre>
<p>Nie ma też żadnych wycieków do globalnej przestrzeni:</p>
<pre><code>var manager = DataManager();
add("cos tam"); // bląd!</code></pre>
<p>Jak to się stało? Wszystko załatwił tzw. <span class="f">object literal</span>, czyli <em>to coś w klamrach, z dwukropkami oraz  przecinkami</em>. O, to!</p>
<pre><code>return {
	add: function() {
		alert("dodaję!");
	},
	get: function() {
		alert("zwracam!");
	}
};</code></pre>
<p>Najprostszy <span class="f">object literal</span> wygląda tak:</p>
<pre><code>var obj = {
	foo: function() {
		alert("boom!");
	}
};
obj.foo(); // "boom!"</code></pre>
<p>Pusty obiekt:</p>
<pre><code>var obj = {};</code></pre>
<p>Lub obiekt posiadający własności nie będące funkcjami:</p>
<pre><code>var obj = {
	foo: 1,
	bar: 2
};
alert(obj.foo); // 1</code></pre>
<p>Można też umieścić obiekt w obiekcie:</p>
<pre><code>var obj = {
	foo: {
		method: function() { alert("foo method!"); }
	}
};
obj.foo.method(); // foo method!</code></pre>
<p>W ten sposób możemy definiować nowe obiekty bez używania konstruktora. Szybko i łatwo od razu jest gotowy. Pamiętaj, by jego składowe definiować po przecinku, więc jeśli mamy np. trzy metody, to powinny pojawić się 2 przecinki:</p>
<pre><code>var obj = {
	metoda1: function() {},
	metoda2: function() {},
	metoda3: function() {}
};</code></pre>
<p>Jak widać, jest to zwykły obiekt, a <em>literal</em> jest dlatego, że definiujemy go &#8222;od ręki&#8221;, wypisując wszystkie składowe.</p>
<p>Jeśli tworzyłeś do tej pory obiekty w ten sposób: <em>var obj = new Object</em> &#8211; szybko o tym zapomnij. Nieoptymalne, niebezpieczne, wolne.</p>
<p>Jest jeszcze trzeci sposób, jak ugryźć obiekty. Otóż obiekty poprzez zdefiniowanie i użycie konstruktorów można dostać jeszcze w inny sposób, niezwiązany z <em>this</em>. Będzie tutaj potrzebna mityzowana własność <span class="f">prototype</span>, którą posiada każda z funkcji. Tak, tak, np. taka:</p>
<pre><code>var fn = function() {};</code></pre>
<p>Czy taka:</p>
<pre><code>var foobar = function() {
	return "foobar";
};</code></pre>
<p>Każda, no.</p>
<p>Dostajemy się do <em>prototype</em> następująco:</p>
<pre><code>foobar.prototype</code></pre>
<p>Jak widać nie ma tutaj zbędnej filozofii &#8211; <em>foobar</em> to zmienna wskazująca na funkcję, choćby weźmy ją z przykładu parę linijek wyżej. Możesz też sprawdzić, że coś takiego istnieje używając np. włączonego Firebuga i jego konsoli, a konkretnie metody <span class="f">console.log</span>:</p>
<pre><code>var fn = function() {};
console.log(fn.prototype);</code></pre>
<p>Wykorzystajmy też swoją wiedzę o <span class="f">typeof</span> i zobaczmy jakiego typu jest własność <em>prototype</em>:</p>
<pre><code>var fn = function() {};
alert(typeof fn.prototype); // "object"</code></pre>
<p>Tak, <span class="f">prototype</span> to obiekt, który może jakieś składowe przechowywać, można coś do niego przypisać lub coś z niego usunąć.</p>
<p>Przepiszmy teraz nasz przykład z <em>DataManager</em> używając powyższej konstrukcji:</p>
<pre><code>var DataManager = function() {};
DataManager.prototype.add = function() { alert("dodaję!"); };
DataManager.prototype.get = function() { alert("zwracam!"); };</code></pre>
<p>A teraz stwórzmy jakiś obiekt na podstawie konstruktora <em>DataManager</em>:</p>
<pre><code>var manager = new DataManager();
manager.add(); // dodaję!
manager.get(); // zwracam!</code></pre>
<p>Możesz być zaskoczony, że to działa. A jednak. Zero <em>this</em>! Co się dzieje? Otóż <span class="f">.prototype</span> to własność, która jest kopiowana do każdego z nowo utworzonych obiektów na podstawie konstruktora, do którego to <em>.prototype</em> należy. Jeśli więc coś jest w <em>DataManager.prototype</em> to zostanie to skopiowane do jakiegokolwiek obiektu, który utworzymy tak: <span class="f">var obj = new DataManager();</span>. Można więc założyć, że <em>.prototype</em> to obiekt bazowy, z którego korzystają inne obiekty.</p>
<p>Warto jednak uważać. <em>.prototype</em> jest kopiowany przez referencję, więc w każdym obiekcie jest ten sam. Proste sprawdzenie:</p>
<pre><code>var manager = new DataManager();
var anotherManager = new DataManager();
manager.add === anotherManager.add; // true</code></pre>
<p>Porównujemy dwie funkcje należące do dwóch różnych obiektów stworzonych na podstawie konstruktora <em>DataManager</em>. Wynika na to, że są to te same funkcje zapisane w jednym i tym samym obszarze pamięci.</p>
<p>Dokładniej ten problem możemy zbadać na innym przykładzie. Jak powiedziałem, każdy obiekt kopiuje sobie przez referencję obiekt <em>.prototype</em> z konstruktora (tak, tak &#8211; tutaj <em>manager</em> i <em>anotherManager</em> kopiują sobie <em>DataManager.prototype</em>) i gdzieś wewnątrz go przechowuje. W niektórych przeglądarkach możemy dostać się do tej własności. A mianowicie jest nią <span class="f">obj.__proto__</span>:</p>
<pre><code>var manager = new DataManager();
var anotherManager = new DataManager();
manager.__proto__ === anotherManager.__proto__; // true</code></pre>
<p>W przyszłości, używając JS opartego na ECMAScript w piątej edycji, będziemy mogli do tego użyć czegoś  takiego, jak <span class="f">getPrototypeOf</span>:</p>
<pre><code>manager.__proto__ === Object.getPrototypeOf(anotherManager); // true</code></pre>
<p>Nie jest to jednak w tym momencie wiedza niecierpiąca zwłoki.</p>
<p>Głównym zagrożeniem, może okazać się coś następującego:</p>
<pre><code>var fn = function() {};
fn.prototype.foo = function() { alert("foo"); };

var obj = new fn();
obj.foo(); // foo

fn.prototype.foo = function() { alert("bar"); };
obj.foo(); // bar</code></pre>
<p>Każda zmiana w prototypie konstruktora ma wpływ na utworzone już obiekty &#8211; z łatwością podmieniliśmy funkcję <span class="f">foo</span>.</p>
<p>Podsumowując, poznaliśmy właśnie kolejny ze sposobów na definiowanie klasopodobnych konstruktorów oraz uzyskiwanie z nich obiektów. Główną zaletą <span class="f">.prototype</span> jest to, że własności są kopiowane przez referencję, co za tym idzie oszczędzamy pamięć, a także łatwe dziedziczenie, o czym w kolejnych artykułach. Natomiast nadal należy pamiętać o <em>new</em>. Do tego o wiele trudniej o zaimplementowanie metod prywatnych (zauważ, że do tej pory operowaliśmy tylko na publicznych). O nich, o closures i innych w kolejnym odcinku.</p>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/javascript/architektura-aplikacji-javascript-wstep/feed/</wfw:commentRss>
		<slash:comments>38</slash:comments>
		</item>
		<item>
		<title>JavaScript &#8211; podstawowe błędy #1</title>
		<link>http://ferrante.pl/frontend/javascript/javascript-porady/</link>
		<comments>http://ferrante.pl/frontend/javascript/javascript-porady/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 19:33:11 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=1008</guid>
		<description><![CDATA[Czasem ludzie pytają mnie &#8211; przede wszystkim mailowo &#8211; o ocenę ich kodu lub zaproponowanie rozwiązania. W większości podczas analizy problemów przejawia się pewien kanon błędów, jakie popełniają początkujący programiści. Postanowiłem więc wyselekcjonować kilka z nich i opisać ku przestrodze. new Array var a = new Array(); // ŹLE var a = []; // DOBRZE [...]]]></description>
			<content:encoded><![CDATA[<p>Czasem ludzie pytają mnie &#8211; przede wszystkim mailowo &#8211; o ocenę ich kodu lub zaproponowanie rozwiązania. W większości podczas analizy problemów przejawia się pewien kanon błędów, jakie popełniają początkujący programiści. Postanowiłem więc wyselekcjonować kilka z nich i opisać ku przestrodze.<span id="more-1008"></span></p>
<h3>new Array</h3>
<pre><code>var a = new Array(); // ŹLE
var a = []; // DOBRZE </code></pre>
<p>Przykład stary jak świat, ale wart piętnowania. <span class="f">new Array</span> jest wolniejsze (bo wywołujemy konstruktor <em>Array</em>) oraz mniej bezpieczne:</p>
<pre><code>var Array = 1;
var a = new Array(); // boom!</code></pre>
<h3>function mojaFunkcja () {}</h3>
<pre><code>function zrob () {};
function poczekaj () {};
function costamInnego () {};</code></pre>
<p>Wielu ludzi wkleja coś takiego do <span class="f">&lt;script /&gt;</span> i ma w nosie wszystko dookoła. W ten sposób zanieczyszczamy globalną przestrzeń nazw i generalnie brudzimy w kodzie. Można uniknąć tego poprzez jako taką imitację przestrzeni nazw:</p>
<pre><code>var Lib = {
	zrob : function () {},
	poczekaj : function () {},
	costamInnego : function () {}
};

Lib.zrob();</code></pre>
<p>Co do namespacingu polecam <a href="http://peter.michaux.ca/articles/javascript-namespacing">ciekawy artykuł</a>, który przedstawia nieco inny punkt widzenia, ale warto go rozważyć.</p>
<p>Drugi częsty błąd:</p>
<pre><code>var fn = function foobar () {};</code></pre>
<p>W IE coś takiego powoduje wyciek zmiennej <span class="f">foobar</span> jako globalnej.</p>
<h3>el.setAttribute(&#8222;style&#8221;, &#8222;font-weight: bold&#8221;)</h3>
<p>Wolna metoda na ustawianie stylów i dość nienaturalna. Nie działa w IE. Zamiast tego:</p>
<pre><code>var el = document.getElementById("elem");
el.style.fontWeight = "bold";</code></pre>
<p>Warto też powiedzieć, że o wiele lepiej sprawdza się nadanie klasy, zamiast ustawiania kilku stylów naraz. Zamiast:</p>
<pre><code>var el = document.getElementById("elem");
el.style.fontWeight = "bold";
el.style.fontStyle = "italic";
el.style.display = "block";</code></pre>
<p>zrób tak:</p>
<pre><code>.special {
	font-style: italic;
	font-weight: bold;
	display: block;
}</code></pre>
<pre><code>var el = document.getElementById("elem");
el.className = "special";</code></pre>
<p>Przy okazji, jeśli chcesz sprawdzić, czy element zawiera już podaną klasę, w nowych przeglądarkach implementowane jest powoli <span class="f">classList</span>:</p>
<pre><code>var name = "special";
if (el.classList.contains(name)) {
// klasa istnieje
}</code></pre>
<h3>something = true</h3>
<p>Pamiętajcie o <span class="f">var</span>! W powyższy sposób deklarujecie zmienne globalne!</p>
<pre><code>something = true; // ŹLE
var something = true; // DOBRZE</code></pre>
<h3>el.onclick = function () {};</h3>
<p>Pamiętajmy o poprawnym modelu W3C do dodawania zdarzeń, a więc:</p>
<pre><code>el.addEventListener("click", function () {}, false);</code></pre>
<p>W IE:</p>
<pre><code>el.attachEvent('onclick', function () {});</code></pre>
<h3>document.getElementsByTagName</h3>
<p>Nie jest to zarzut, aczkolwiek nowsze przeglądarki implementują coś, dzięki czemu możesz zapomnieć o jQuery tj. <span class="f">document.querySelectorAll</span>:</p>
<pre><code>var specials = document.querySelectorAll("#wrapper .special");</code></pre>
<h3>new Image</h3>
<p>Uwaga, można nadpisać!</p>
<pre><code>var Image = "hej Sokoły!";
var img = new Image(); // boom!</code></pre>
<p>Lepiej oprzeć się na DOM:</p>
<pre><code>var img = document.createElement("img");
img.src = "http://something.com/something.jpg";</code></pre>
<h3>parseInt(&#8222;08&#8243;)</h3>
<pre><code>parseInt("08"); // 0</code></pre>
<p>Pamiętajmy o systemie liczbowym do jakiego chcemy konwertować stringa!</p>
<pre><code>parseInt("08", 10); // 8</code></pre>
<h3>hasOwnProperty</h3>
<p>Do czego służy <span class="f">hasOwnProperty</span>?</p>
<pre><code>Object.prototype.somethingMine = function () {};
var o = { foo : "bar" };

for (var i in o) {
	if (o.hasOwnProperty(i)) {
	}
}</code></pre>
<p>Jeśli nie zawrzemy powyższego warunku, przeiterujemy też wraz z <em>somethingMine</em>.</p>
<h3>undefined</h3>
<pre><code>foo === undefined; // ŹLE
typeof foo === "undefined"; // DOBRZE</code></pre>
<p>Pamiętajmy, że można łatwo nadpisać <em>undefined</em>:</p>
<pre><code>var undefined = 1;</code></pre>
<p>Sposobem na uzyskanie <em>czystego undefined</em> może być np.:</p>
<pre><code>(function(undefined) {
foo == undefined;
})();</code></pre>
<p>Lub:</p>
<pre><code>var undefined = (function () {})();</code></pre>
<p>Lub:</p>
<pre><code>var undefined = void 0;</code></pre>
<h3>for in</h3>
<p>Nie używamy pętli <span class="f">for in</span> dla tablic!</p>
<pre><code>var a = [1, 2, 3];
for (var i in a) {} // ŹLE!</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/javascript/javascript-porady/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>Quiz JavaScript</title>
		<link>http://ferrante.pl/frontend/javascript/quiz-javascript/</link>
		<comments>http://ferrante.pl/frontend/javascript/quiz-javascript/#comments</comments>
		<pubDate>Tue, 21 Dec 2010 17:51:57 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=943</guid>
		<description><![CDATA[Przygotowałem mały quiz JavaScript. Zachęcam do zabawy i podawania wyjaśnień w komentarzach. Jednocześnie uczulam na spoilery. Być może wkrótce pojawią się inne quizy tego typu. Odpowiedź ERROR oznacza błąd &#8211; jakiegokolwiek typu, nie wnikamy tutaj w szczegóły. Kod powinien być zgodny z ECMA w trzeciej edycji plus mały dodatek w postaci funkcji map z kolejnych [...]]]></description>
			<content:encoded><![CDATA[<p>Przygotowałem mały quiz JavaScript. Zachęcam do zabawy i podawania wyjaśnień w komentarzach. Jednocześnie uczulam na spoilery. Być może wkrótce pojawią się inne quizy tego typu. Odpowiedź ERROR oznacza błąd &#8211; jakiegokolwiek typu, nie wnikamy tutaj w szczegóły. Kod powinien być zgodny z ECMA w trzeciej edycji plus mały dodatek w postaci funkcji map z kolejnych edycji.<span id="more-943"></span></p>
<p><script type="text/javascript">
$(document).ready(function() {
(function () {
var g = [[11,3],
    [44,41],
    [75,4],
    [300,8],
    [55,4],
    [145,4],
    [40,6],
    [103,9],
    [165,6],
    [104,10],
    [146,12],
    [289,7],
    [112,5],
    [38,6],
    [65,8],
    [82,9],
    [59,7],
    [66,8],
    [122,10],
    [22,10]];
$("#answer").click(function(e) {
var i =0, j = g.length, v, r = 0;
for (;i < j; i++) {
   v = $("input[name=pyt-"+(i+1)+"]:checked");
   if (v.length) {
var par = $(v).parent().parent();        
v = $(v).parent().parent().find("input").index(v);
       if (v +1 === g[i][0] % g[i][1]) {
r++;
par.removeClass("bad").addClass("ok");
       } else {
par.removeClass("ok").addClass("bad");
}
   }
} 
$("#wynik").text("Twój wynik to: " + r +"/20!");
e.preventDefault();
}); })(); });</script></p>
<style>#quiz input { margin-right: 5px; }
#quiz .question { margin-bottom: 20px; margin-left: 35px; margin-top: -15px; }
.bad { width:672px; background-color: #E8BAC4; }
.ok { background: #BAE8C8;
width:672px; }
</style>
<ol id="quiz" style="list-style-position: inside;">
<li>
<div class="question">
<pre><code>var fn = function x () { return fn; };
x;</code></pre>
<p>
<input type="radio" name="pyt-1" id="pyt-1a" /><label for="pyt-1a">function x() { return fn; };</label></p>
<p>
<input type="radio" name="pyt-1" id="pyt-1b" /><label for="pyt-1b">ERROR</label></p>
<p>
<input type="radio" name="pyt-1" id="pyt-1c" /><label for="pyt-1c">undefined</label></p>
<p>
<input type="radio" name="pyt-1" id="pyt-1d" /><label for="pyt-1d">null</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>["1", "2", "3"].map(parseInt);</code></pre>
<p>
<input type="radio" name="pyt-2" id="pyt-2a" /><label for="pyt-2a">[1, 2, 3]</label></p>
<p>
<input type="radio" name="pyt-2" id="pyt-2b" /><label for="pyt-2b">["1", "2", "3"]</label></p>
<p>
<input type="radio" name="pyt-2" id="pyt-2c" /><label for="pyt-2c">[1, NaN, NaN]</label></p>
<p>
<input type="radio" name="pyt-2" id="pyt-2d" /><label for="pyt-2d">[NaN, NaN, NaN]</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>parseInt("08");</code></pre>
<p>
<input type="radio" name="pyt-3" id="pyt-3a" /><label for="pyt-3a">8</label></p>
<p>
<input type="radio" name="pyt-3" id="pyt-3b" /><label for="pyt-3b">0.8</label></p>
<p>
<input type="radio" name="pyt-3" id="pyt-3c" /><label for="pyt-3c">0</label></p>
<p>
<input type="radio" name="pyt-3" id="pyt-3d" /><label for="pyt-3d">10</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>10.2 | 0;</code></pre>
<p>
<input type="radio" name="pyt-4" id="pyt-4a" /><label for="pyt-4a">10.2</label></p>
<p>
<input type="radio" name="pyt-4" id="pyt-4b" /><label for="pyt-4b">0</label></p>
<p>
<input type="radio" name="pyt-4" id="pyt-4c" /><label for="pyt-4c">102</label></p>
<p>
<input type="radio" name="pyt-4" id="pyt-4d" /><label for="pyt-4d">10</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>typeof Number("2");</code></pre>
<p>
<input type="radio" name="pyt-5" id="pyt-5a" /><label for="pyt-5a">"object"</label></p>
<p>
<input type="radio" name="pyt-5" id="pyt-5b" /><label for="pyt-5b">"string"</label></p>
<p>
<input type="radio" name="pyt-5" id="pyt-5c" /><label for="pyt-5c">"number"</label></p>
<p>
<input type="radio" name="pyt-5" id="pyt-5d" /><label for="pyt-5d">"array"</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>var obj = {
	a : this.obj,
	obj : "foo"
};
typeof obj.a; </code></pre>
<p>
<input type="radio" name="pyt-6" id="pyt-6a" /><label for="pyt-6a">"undefined"</label></p>
<p>
<input type="radio" name="pyt-6" id="pyt-6b" /><label for="pyt-6b">"string"</label></p>
<p>
<input type="radio" name="pyt-6" id="pyt-6c" /><label for="pyt-6c">"object"</label></p>
<p>
<input type="radio" name="pyt-6" id="pyt-6d" /><label for="pyt-6d">ERROR</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>var arr = [1, 2, 3];
arr.splice(1, 0, 1);
arr;</code></pre>
<p>
<input type="radio" name="pyt-7" id="pyt-7a" /><label for="pyt-7a">ERROR</label></p>
<p>
<input type="radio" name="pyt-7" id="pyt-7b" /><label for="pyt-7b">[1, 2, 3]</label></p>
<p>
<input type="radio" name="pyt-7" id="pyt-7c" /><label for="pyt-7c">[1, 1, 2]</label></p>
<p>
<input type="radio" name="pyt-7" id="pyt-7d" /><label for="pyt-7d">[1, 1, 2, 3]</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>var x = [1, 2, 3].splice(1, 1);
x;</code></pre>
<p>
<input type="radio" name="pyt-8" id="pyt-8a" /><label for="pyt-8a">ERROR</label></p>
<p>
<input type="radio" name="pyt-8" id="pyt-8b" /><label for="pyt-8b">undefined</label></p>
<p>
<input type="radio" name="pyt-8" id="pyt-8c" /><label for="pyt-8c">2</label></p>
<p>
<input type="radio" name="pyt-8" id="pyt-8d" /><label for="pyt-8d">[2]</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>0..toString.call(2, 2);</code></pre>
<p>
<input type="radio" name="pyt-9" id="pyt-9a" /><label for="pyt-9a">ERROR</label></p>
<p>
<input type="radio" name="pyt-9" id="pyt-9b" /><label for="pyt-9b">0</label></p>
<p>
<input type="radio" name="pyt-9" id="pyt-9c" /><label for="pyt-9c">"10"</label></p>
<p>
<input type="radio" name="pyt-9" id="pyt-9d" /><label for="pyt-9d">2</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>[1.,.5][0.1 &#038; 0]</code></pre>
<p>
<input type="radio" name="pyt-10" id="pyt-10a" /><label for="pyt-10a">undefined</label></p>
<p>
<input type="radio" name="pyt-10" id="pyt-10b" /><label for="pyt-10b">5</label></p>
<p>
<input type="radio" name="pyt-10" id="pyt-10c" /><label for="pyt-10c">ERROR</label></p>
<p>
<input type="radio" name="pyt-10" id="pyt-10d" /><label for="pyt-10d">1</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>var x = (1, 2, (x = 3), 4);
x;</code></pre>
<p>
<input type="radio" name="pyt-11" id="pyt-11a" /><label for="pyt-11a">3</label></p>
<p>
<input type="radio" name="pyt-11" id="pyt-11b" /><label for="pyt-11b">4</label></p>
<p>
<input type="radio" name="pyt-11" id= "pyt-11c" /><label for="pyt-11c">1</label></p>
<p>
<input type="radio" name="pyt-11" id="pyt-11d" /><label for="pyt-11d">ERROR</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>var var = "100";
var;</code></pre>
<p>
<input type="radio" name="pyt-12" id="pyt-12a" /><label for="pyt-12a">100</label></p>
<p>
<input type="radio" name="pyt-12" id="pyt-12b" /><label for="pyt-12b">ERROR</label></p>
<p>
<input type="radio" name="pyt-12" id="pyt-12c" /><label for="pyt-12c">null</label></p>
<p>
<input type="radio" name="pyt-12" id="pyt-12d" /><label for="pyt-12d">undefined</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>[10, 100, 1][~"2" + + "3"];</code></pre>
<p>
<input type="radio" name="pyt-13" id="pyt-13a" /><label for="pyt-13a">100</label></p>
<p>
<input type="radio" name="pyt-13" id="pyt-13b" /><label for="pyt-13b">10</label></p>
<p>
<input type="radio" name="pyt-13" id="pyt-13c" /><label for="pyt-13c">1</label></p>
<p>
<input type="radio" name="pyt-13" id="pyt-13d" /><label for="pyt-13d">undefined</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>var fn = function gn () {
	var hn = function gn () {
		fn();
		return 100;
	};
	return hn;
};
fn()();</code></pre>
<p>
<input type="radio" name="pyt-14" id="pyt-14a" /><label for="pyt-14a">ERROR</label></p>
<p>
<input type="radio" name="pyt-14" id="pyt-14b" /><label for="pyt-14b">100</label></p>
<p>
<input type="radio" name="pyt-14" id="pyt-14c" /><label for="pyt-14c">hn</label></p>
<p>
<input type="radio" name="pyt-14" id="pyt-14d" /><label for="pyt-14d">undefined</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>"" + [1] + {};
	        </code></pre>
<p>
<input type="radio" name="pyt-15" id="pyt-15a" /><label for="pyt-15a">"1[object Object]"</label></p>
<p>
<input type="radio" name="pyt-15" id="pyt-15b" /><label for="pyt-15b">ERROR</label></p>
<p>
<input type="radio" name="pyt-15" id="pyt-15c" /><label for="pyt-15c">"[object Array]"</label></p>
<p>
<input type="radio" name="pyt-15" id="pyt-15d" /><label for="pyt-15d">"1"</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>var x = ({ "with" : 1} + 1);
x;</code></pre>
<p>
<input type="radio" name="pyt-16" id="pyt-16a" /><label for="pyt-16a">"[object Object]1"</label></p>
<p>
<input type="radio" name="pyt-16" id="pyt-16b" /><label for="pyt-16b">ERROR</label></p>
<p>
<input type="radio" name="pyt-16" id="pyt-16c" /><label for="pyt-16c">2</label></p>
<p>
<input type="radio" name="pyt-16" id="pyt-16d" /><label for="pyt-16d">undefined</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>var x = [[] | 0];
x;</code></pre>
<p>
<input type="radio" name="pyt-17" id="pyt-17a" /><label for="pyt-17a">0</label></p>
<p>
<input type="radio" name="pyt-17" id="pyt-17b" /><label for="pyt-17b">undefined</label></p>
<p>
<input type="radio" name="pyt-17" id="pyt-17c" /><label for="pyt-17c">[0]</label></p>
<p>
<input type="radio" name="pyt-17" id="pyt-17d" /><label for="pyt-17d">-1</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>Infinity > NaN;</code></pre>
<p>
<input type="radio" name="pyt-18" id="pyt-18a" /><label for="pyt-18a">true</label></p>
<p>
<input type="radio" name="pyt-18" id="pyt-18b" /><label for="pyt-18b">false</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>undefined < 1;</code></pre>
<p>
<input type="radio" name="pyt-19" id="pyt-19a" /><label for="pyt-19a">true</label></p>
<p>
<input type="radio" name="pyt-19" id="pyt-19b" /><label for="pyt-19b">false</label></p>
</p></div>
</li>
<li>
<div class="question">
<pre><code>/[a-z]/g == /[a-z]/g;</code></pre>
<p>
<input type="radio" name="pyt-20" id="pyt-20a" /><label for="pyt-20a">true</label></p>
<p>
<input type="radio" name="pyt-20" id="pyt-20b" /><label for="pyt-20b">false</label></p>
</p></div>
</li>
</ol>
<p><button id="answer">wynik!</button></p>
<div id="wynik" style="margin-top: 20px; font-size: 1.2em; font-weight: bold;"></div>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/javascript/quiz-javascript/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>CSS3 &#8211; transitions</title>
		<link>http://ferrante.pl/frontend/vademecum/css3-transitions/</link>
		<comments>http://ferrante.pl/frontend/vademecum/css3-transitions/#comments</comments>
		<pubDate>Wed, 24 Nov 2010 19:41:02 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=898</guid>
		<description><![CDATA[-]]></description>
			<content:encoded><![CDATA[<p>CSS3 coraz śmielej zagląda do naszych przeglądarek. Widząc nowe wydania Firefoxa, Chrome&#8217;a czy IE (w dziewiątej wersji) wypada tylko uśmiechnąć się od ucha do ucha, bo wygląda na to, że &mdash; po 10 latach męki &mdash; będziemy mogli zapomnieć o czymś takim jak IE6, komentarzach warunkowych i wspieraniu się JavaScriptem w najbardziej trywialnych przypadkach.<span id="more-898"></span></p>
<p>Postanowiłem więc &mdash; jeśli wszystko pójdzie według mojego planu &mdash; opisać najważniejsze składniki CSS3 bazując na przykładach. Zacznijmy od <span class="f">transitions</span>, które pozwalają nam czasem zapomnieć o jQuery&#8217;owym <em>animate</em> czy po prostu <em>window.setTimeout</em>.</p>
<h3>Do czego służą CSS3 transitions?</h3>
<p><em>Transitions</em> to specjalne własności w CSS, dzięki którym możemy ustawić, że zmianie jakieś właściwości (np. marginesu lewego) towarzyszyć będzie animacja, zamiast błyskawicznej modyfikacji wartości z x na y. Przykładowo, jeśli ustawimy (bezpośrednio w JS bądź poprzez zmianę klasy/właściwości w CSS) wartość <span class="f">height</span> i zdefiniujemy wcześniej odpowiednie <em>transition</em>, zmiana wysokości zostanie animowana (czyli element będzie się wydłużał albo skracał do podanej wartości). To samo tyczy się np. marginesów czy przeźroczystości &#8211; ustawiasz <em>transition</em> na jakimś elemencie, ktoś zmienia <span class="f">opacity</span> z <strong>0.1</strong> na <strong>1</strong> i obserwujesz, jak zmiana tej wartości następuje stopniowo, od 0.1 do 1, w ciągu jakiegoś (zdefiniowanego przez nas) czasu.</p>
<h3>Teoria</h3>
<p>Powiedzieliśmy sobie, że aby zaobserwować jak to działa, należy ustawić jakieś <em>transition</em> na danym elemencie. Jak to się robi w teorii? Przyjmijmy, że działamy na <span class="f">&lt;p/&gt;</span>:</p>
<pre><code>p {
	transition: height 1s ease-out;
}</code></pre>
<p>W ten sposób mówimy przeglądarce, że jeśli ktokolwiek ustawi nową wartość <span class="f">height</span> dla jakiegokolwiek elementu <em>&lt;p/&gt;</em>, to zmianie tej ma towarzyszyć 1-sekundowa animacja (bądź <em>przejście</em>) typu <em>ease-out</em>. Czyli &mdash; dla przykładu &mdash; robiąc, dajmy na to, w jQuery:</p>
<pre><code>$("p").css("height", 100);</code></pre>
<p><a href="http://ferrante.pl/examples/css/transitions/transitions-jq.html">Przeglądarka odpowiednio zareaguje</a>, zmieniając w ciągu sekundy wysokość każdego elementu <em>p</em> z dotychczasowej na 100 pikseli (jako że taką wartość podaliśmy wyżej).</p>
<p>Podobnie byłoby, gdybyśmy mieli taki kod:</p>
<pre><code>p {
	transition: height 1s ease-out;
}
.odpalTransition {
	height: 100px;
}</code></pre>
<pre><code>$("p").addClass("odpalTransition");</code></pre>
<p>Powyżej dodajemy każdemu z <em>&lt;p/&gt;</em> nową klasę <span class="f">odpalTransition</span>. Jej nazwa jest mało reprezentatywna, ważne jednak, że przy okazji zmieniamy wysokość. W ten sposób zadziała <em>transition</em>, zdefiniowany na początku dla każdego akapitu.</p>
<h3>Przeglądarka przeglądarce nierówna</h3>
<p>Musisz wiedzieć, że przeglądarki zaczęły implementować CSS3 transitions dość dawno temu, a specyfikacja z W3C ma nadal status draftu, dlatego wprowadzono tę opcję z odpowiednim prefiksem. Dla Chrome i Safari jest to <span class="f">-webkit-transition</span>, dla Firefoxa <span class="f">-moz-transition</span>, a dla Opery <span class="f">-o-transition</span>. Z reguły wymienione przeglądarki nie rozumieją czystego <span class="f">transition</span>. Aby zapewnić dla nich wsparcie należy więc aż cztery razy umieścić odpowiednią regułkę. Na naszym przykładzie będzie wyglądało to tak:</p>
<pre><code>p {
	-webkit-transition: height 1s ease-out;
	-moz-transition: height 1s ease-out;
	-o-transition: height 1s ease-out;
	transition: height 1s ease-out;
}</code></pre>
<p>Witaj w świecie <em>cross-browserowych</em> CSSów trzy!</p>
<p>Jak widzisz, w <em>transition:</em> podaliśmy trzy wartości: <em>height</em>, <em>1s</em> i <em>ease-out</em>. Pierwsza to oczywiście własność, na której zmianę ma zareagować przeglądarka. Może być ich kilka:</p>
<pre><code>p {
	-webkit-transition: height 1s ease-out, width 1s ease-out;
	-moz-transition: height 1s ease-out, width 1s ease-out;
	-o-transition: height 1s ease-out, width 1s ease-out;
	transition: height 1s ease-out, width 1s ease-out;
}</code></pre>
<p>Można też podać <span class="f">all</span>:</p>
<pre><code>p {
	-webkit-transition: all 1s ease-out;
	-moz-transition: all 1s ease-out;
	-o-transition: all 1s ease-out;
	transition: all 1s ease-out;
}</code></pre>
<p>Tutaj, niezależnie od tego, jaką własność będziemy chcieli ustawić, <em>brałzer</em> spróbuje włączyć zdefiniowany <em>transition</em>.</p>
<p>Czas to z kolei jakaś część sekundy, może być to np. 100 milisekund (wyrażone przez <span class="f">0.1s</span>):</p>
<pre><code>p {
	-webkit-transition: height 0.1s ease-out, width 0.1s ease-out;
	-moz-transition: height 0.1s ease-out, width 0.1s ease-out;
	-o-transition: height 0.1s ease-out, width 0.1s ease-out;
	transition: height 0.1s ease-out, width 0.1s ease-out;
}</code></pre>
<p>Jeśli chodzi o typ animacji, mamy do wyboru:</p>
<ul>
<li>ease</li>
<li>linear</li>
<li>ease-in</li>
<li>ease-out</li>
<li>ease-in-out</li>
<li>krzywa Béziera trzeciego stopnia (P0, P1, P2, P3)</li>
</ul>
<p>Jak zapewne zauważyłeś, typy animacji są wyliczane na podstawie krzywych Béziera. <a href="http://www.w3.org/TR/css3-transitions/#transition-timing-function">Odpowiednie parametry każdej z nich</a> znajdziesz w specyfikacji.</p>
<p>Kojarzysz zapewne CSSowy <span class="f">border</span>, prawda? Skrótowiec wygląda tak:</p>
<pre><code>border: 1px solid #000;</code></pre>
<p>Dzięki temu nie musimy pisać w ten sposób:</p>
<pre><code>border-style: solid;
border-color: #000;
border-width: 1px;</code></pre>
<p>Podobna sytuacja jest z <em>transitions</em>. Możemy użyć skróconego zapisu:</p>
<pre><code>transition: height 1s ease-out;</code></pre>
<p>Aczkolwiek można też odwołać się bezpośrednio do każdej z pod-własności. W naszym przypadku będzie to wyglądać tak:</p>
<pre><code>transition-property: height;
transition-duration: 1s;
transition-timing-function: ease-out;</code></pre>
<p>Nie jest to jednak zbyt efektywne, wyobraź sobie, że musiałbyś napisać coś takiego dla każdej z przeglądarek (<em>-moz, -webkit</em> itd.). W sumie &#8211; 12 linijek!</p>
<p>Przy okazji, jest jeszcze <span class="f">transition-delay</span>, który oznacza opóźnienie w wykonaniu się animacji:</p>
<pre><code>transition-property: height;
transition-duration: 1s;
transition-timing-function: ease-out;
transition-delay: 1s;</code></pre>
<p>Powyżej będzie to jednosekundowe opóźnienie.</p>
<p>Podsumowując, używając skrótowca, wzór pisania <em>transitions</em> wygląda tak:</p>
<pre><code>[-moz,-webkit,-o]transition: własność czas_trwania typ opóźnienie</code></pre>
<h3>Praktyczny przykład</h3>
<p>Czas na jakiś praktyczny przykład wykorzystania <em>transitions</em>. Zróbmy więc prosty <em>accordion</em> po najechaniu myszką na odpowiedni nagłówek. Oto przykładowy kod HTML:</p>
<pre><code>&lt;h1&gt;Poczytaj o:&lt;/h1&gt;
&lt;ul&gt;
	&lt;li&gt;
		&lt;h2&gt;&lt;a href=&quot;#more&quot;&gt;CSS3&lt;/a&gt;&lt;/h2&gt;
		&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque placerat molestie mauris, ac mollis neque ultricies sit amet. Quisque ligula nisi, facilisis in molestie sit amet, blandit at felis.&lt;/p&gt;
	&lt;/li&gt;
	&lt;li&gt;
		&lt;h2&gt;&lt;a href=&quot;#more&quot;&gt;Transitions&lt;/a&gt;&lt;/h2&gt;
		&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque placerat molestie mauris, ac mollis neque ultricies sit amet. Quisque ligula nisi, facilisis in molestie sit amet, blandit at felis.&lt;/p&gt;
	&lt;/li&gt;
	&lt;li&gt;
		&lt;h2&gt;&lt;a href=&quot;#more&quot;&gt;Czym&#x15B; innym&lt;/a&gt;&lt;/h2&gt;
		&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque placerat molestie mauris, ac mollis neque ultricies sit amet. Quisque ligula nisi, facilisis in molestie sit amet, blandit at felis.&lt;/p&gt;
	&lt;/li&gt;
&lt;/ul&gt;</code></pre>
<p>Mamy więc prostą listę nieuporządkowaną, a wewnątrz trzy nagłówki oraz po jednym akapicie, które powinny być ukryte. Nasz cel to zrobić tak, by po najechaniu na nagłówek wysokość oraz przeźroczystość sąsiadującego akapitu zmieniły na jakieś dodatnie wartości, aby był on widoczny. Ustawmy więc odpowiednie style:</p>
<pre><code>body {
	font-family: "Helvetica", Arial;
}

h1 {
	font-size: 100%;
}

h2 {
	font-size: 90%;
	margin: 0;
	padding: 0;
	margin-bottom: 10px;
	display: inline-block;
}

li {
	padding-bottom: 5px;
	max-height: 150px;
}

li p {
	margin: 0;
	padding: 0;
	color: #fff;
	background: #cc0000;
	overflow: hidden;
}</code></pre>
<p>Chyba nie zrobiliśmy wszystkiego, <a href="http://ferrante.pl/examples/css/transitions/transitions-2.html">bo akapity nie są ukryte i nic się nie dzieje</a>. Ukryjmy je więc:</p>
<pre><code>li p {
	margin: 0;
	padding: 0;
	color: #fff;
	background: #cc0000;
	overflow: hidden;
	height: 0;
	opacity: 0;
}</code></pre>
<p><span class="f">opacity</span> i <span class="f">height</span> ustawione na zero załatwiły sprawę. Pora obsłużyć nasz <span class="f">hover</span> na nagłówku <span class="f">h2</span>:</p>
<pre><code>li h2:hover + p {
	height: 50px;
	opacity: 1;
}</code></pre>
<p>Oznacza to, że jeśli ktoś najedzie myszką na <em>h2</em> silnik CSS poszuka sąsiadującego z nim elementu <em>p</em> i ustawi jego wysokość (<em>height</em>) na 50px oraz przeźroczystość (<em>opacity</em>) na 1.</p>
<p>CSSy wyglądają teraz tak:</p>
<pre><code>body {
	font-family: "Helvetica", Arial;
}

h1 {
	font-size: 100%;
}

h2 {
	font-size: 90%;
	margin: 0;
	padding: 0;
	margin-bottom: 10px;
	display: inline-block;
}

li {
	padding-bottom: 5px;
	max-height: 150px;
}

li p {
	margin: 0;
	padding: 0;
	color: #fff;
	background: #cc0000;
	overflow: hidden;
	height: 0;
	opacity: 0;
}

li h2:hover + p {
	height: 50px;
	opacity: 1;
}</code></pre>
<p><a href="http://ferrante.pl/examples/css/transitions/transitions-3.html">Całość działa dość dobrze</a>. Nie ma jednak animacji! Musimy dodać obsługę <span class="f">transitions</span>. Jak widzimy, w selektorze <span class="f">li h2:hover + p</span> zmieniamy wysokość i przeźroczystość. Jak powiedzieliśmy też wcześniej, <em>transitions</em> mają za zadanie powiedzieć przeglądarce, by w razie zmiany odpowiednich wartości, zmieniła je krok po kroku, używając jakiejś animacji bądź &mdash; to chyba będzie lepsza nazwa &mdash; efektu przejścia z jednej wartości do drugiej. </p>
<p>Tak więc, jako że zmieniamy te wartości dla akapitu <em>p</em>, dodajmy odpowiedni <em>transition</em> właśnie tam:</p>
<pre><code>li p {
	margin: 0;
	padding: 0;
	color: #fff;
	background: #cc0000;
	overflow: hidden;
	height: 0;
	opacity: 0;
	-webkit-transition: opacity 0.5s ease-out, height 0.5s ease-out;
	-moz-transition: opacity 0.5s ease-out, height 0.5s ease-out;
	-o-transition: opacity 0.5s ease-out, height 0.5s ease-out;
	transition: opacity 0.5s ease-out, height 0.5s ease-out;
}</code></pre>
<p><a href="http://ferrante.pl/examples/css/transitions/transitions-4.html">Kilka linijek, a ile radości!</a> Ustawiliśmy właśnie, by włączało się półsekundowe przejście typu <em>ease-out</em>, jeśli ktokolwiek, kiedykolwiek zmieni właściwość <em>opacity</em> bądź <em>height</em> dla elementów <em>&lt;p/&gt;</em>.</p>
<h3>Podsumowanie</h3>
<p>CSS3 transitions to bardzo ciekawe narzędzie, które potrafi zaoszczędzić nam brudzenia sobie rąk JavaScriptem. Wszystko działa pod Firefoxem 4, Chrome 1+, Safari 3.2+ i Operą 10.5+.</p>
<p>Liczę, że wkrótce pojawią się tu kolejne artykuły na temat nowych <em>ficzerów</em>, bo, jak widzicie, jest o czym pisać.</p>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/vademecum/css3-transitions/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>varJS.com &#8211; zaawansowany JavaScript za darmo!</title>
		<link>http://ferrante.pl/frontend/javascript/varjs-com-zaawansowany-javascript-za-darmo/</link>
		<comments>http://ferrante.pl/frontend/javascript/varjs-com-zaawansowany-javascript-za-darmo/#comments</comments>
		<pubDate>Thu, 15 Apr 2010 20:24:11 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=745</guid>
		<description><![CDATA[To nie koniec niespodzianek w tym tygodniu! Uruchomiłem właśnie stronę varJS.com, gdzie wkrótce powstanie blog poświęcony JavaScript i pochodnym. Tym razem po angielsku. Mam zamiar publikować tam także kolejne rozdziały mojej książki o JavaScript zupełnie za darmo. Być może będzie to funkcjonowało na zasadzie wiki, tego jeszcze nie ustaliłem. Co jednak dzisiaj istotne, wydałem prawie [...]]]></description>
			<content:encoded><![CDATA[<p>To nie koniec niespodzianek w tym tygodniu! Uruchomiłem właśnie stronę <a href="http://varjs.com">varJS.com</a>, gdzie wkrótce powstanie blog poświęcony JavaScript i pochodnym. Tym razem po angielsku. Mam zamiar publikować tam także kolejne rozdziały mojej książki o JavaScript zupełnie za darmo. Być może będzie to funkcjonowało na zasadzie wiki, tego jeszcze nie ustaliłem.</p>
<p>Co jednak dzisiaj istotne, wydałem prawie 250-stronicowy, długo oczekiwany materiał PDF ze szkoleń i mojego dotychczasowego researchu o nazwie <span class="f">Just Advanced JavaScript</span>. Książka, a w zasadzie slajdy mają charakter ściągawki &#8211; opisana została lwia część języka oraz mnóstwo ciekawostek i haczyków. Wszystko znajdziecie pod <a href="http://varjs.com">varJS.com</a> &#8211; serdecznie zapraszam! Prawdopodobnie wkrótce rozszerzę to o kolejne rozdziały i linki do innych pożytecznych stron, które również możecie tam spotkać.</p>
<p>Niniejszym dziękuje <a href="http://kukawski.pl">Rafałowi Kukawskiemu</a> oraz <a href="http://leaverou.me">Lei Verou</a>, którzy odpowiadali za korektę i poprawę ewentualnych błędów merytorycznych. Z całego serca polecam współpracę z nimi, prawdziwi eksperci!</p>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/javascript/varjs-com-zaawansowany-javascript-za-darmo/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Klasyczne klasy w JavaScript</title>
		<link>http://ferrante.pl/frontend/javascript/klasyczne-klasy-w-javascript/</link>
		<comments>http://ferrante.pl/frontend/javascript/klasyczne-klasy-w-javascript/#comments</comments>
		<pubDate>Fri, 02 Apr 2010 22:07:39 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=728</guid>
		<description><![CDATA[JavaScript nie oferuje klasycznej obiektowości, wszystko opiera się tutaj na prototypach. Nie ma słówka kluczowego Class i tak dalej. Tego typu pozorna niedogodność, ale przede wszystkim chęć organizacji kodu, wymusza czasem zastosowanie pewnych, dodatkowych narzędzi. Jednym z nich jest abstrakcja klas. Ma to mootools, Prototype, są odpowiednie pluginy do jQuery. O co chodzi? Wyobraźmy sobie, [...]]]></description>
			<content:encoded><![CDATA[<p>JavaScript nie oferuje klasycznej obiektowości, wszystko opiera się tutaj na prototypach. Nie ma słówka kluczowego <em>Class</em> i tak dalej. Tego typu pozorna niedogodność, ale przede wszystkim chęć organizacji kodu, wymusza czasem zastosowanie pewnych, dodatkowych narzędzi. Jednym z nich jest abstrakcja klas. Ma to mootools, Prototype, są odpowiednie pluginy do jQuery. O co chodzi?<span id="more-728"></span></p>
<p>Wyobraźmy sobie, że nie odpowiada nam dzielenie kodu na konstruktory i rozszerzanie ich prototypów:</p>
<pre><code>var Animal = function(age) {
	this.age = age;
};
Animal.prototype.getAge = function() { return this.age; };
Animal.prototype.setAge = function(age) { this.age = age; };</code></pre>
<pre><code>var Dog = function(age) {
	this.setAge(age);
};
Dog.prototype = new Animal; // dziedziczymy po Animal
Dog.prototype.constructor = Dog;
Dog.prototype.getVoice = function() { return "hau hau"; }</code></pre>
<p>Używamy tego w ten sposób:</p>
<pre><code>var dog = new Dog(10);
dog.getVoice(); // hau hau
dog.getAge(); // 10</code></pre>
<p>W przypadku dużych i rozbudowanych systemów może rodzić to pewne kłopoty z utrzymaniem i czystością kodu. W związku z tym powstały abstrakcje klas. Stosując jedną z nich, można by napisać tak:</p>
<pre><code>var Animal = new Klass({
	Init: function(age) {
		this.setAge(age);
	},
	age: null,
	getAge: function() { return this.age; },
	setAge: function(age) { this.age = age; }
});

var Dog = new Klass({
	Extends: Animal,
	getVoice: function() { return "hau hau"; }
});</code></pre>
<p>Powiedzmy sobie szczerze &#8211; jest to bardziej przejrzyste rozwiązanie, pozwalające na stworzenie lepszej dokumentacji, testów i tak dalej. Jest też, sądzę, łatwiejsze do zrozumienia dla developerów nie mających zbyt dużego rozeznania w JavaScript. Zobaczmy więc, jak można coś takiego łatwo stworzyć.</p>
<p>Pierwsze, co jest nam potrzebne, to odpowiedni konstruktor <span class="f">Klass</span>. </p>
<pre><code>var Klass = (function() {
// ...
})();</code></pre>
<p>Jak widać, w tym momencie <em>Klass</em> ma wartość <span class="f">undefined</span> &#8211; to jasne, ponieważ funkcja nie mająca zdefiniowanego <em>return</em> zwraca <em>undefined</em>. Jako że mamy zamiar używać <em>Klass</em> w ten sposób &#8211; <span class="f">new Klass({});</span> &#8211; wiemy, że pod <em>Klass</em> musi znajdować się jakiś konstruktor, przyjmujący argument, który będzie zawierał pola i metody przyszłych klas. Szybka korekta i możemy iść dalej:</p>
<pre><code>var Klass = (function() {
	return function(classDefinition) {};
})();</code></pre>
<p>Dobrze, pora zająć się metodami <span class="f">Init</span>, uruchamiającymi się podczas konstruowania przyszłych obiektów z naszych klas. Zdefiniujmy sobie zmienną <span class="f">dummyClass</span>, która będzie z kolei konstruktorem-funkcją. Będziemy dekorować ją potem atrybutami z <span class="f">classDefinition</span>.</p>
<pre><code>var Klass = (function() {
	return function(classDefinition) {
		var dummyClass = function() {
			this.Init &#038;&#038; typeof this.Init === "function" &#038;&#038; this.Init.apply(this, arguments);
		};

		return dummyClass;
	};
})();</code></pre>
<p>Co dzieje się w <em>dummyClass</em>? Sprawdzamy po kolei, czy po wywołaniu <em>new JakasNaszaKlasa</em> istnieje coś takiego jak metoda <em>Init</em>, która ma pełnić rolę konstruktora. Następnie upewniamy się, że jest to funkcja, by potem odpalić ją poprzez <span class="f">this.Init.apply(this, arguments)</span>.</p>
<p>Nasza <em>dummyClass</em> musi jednak jakoś wiedzieć o <em>Init</em>, którą możemy podać w <em>classDefinition</em>. Zresztą, tak jak o innych polach i metodach naszych przyszłych klas. Najlepiej będzie więc przepisać wszystko z <em>classDefinition</em> do prototypu <em>dummyClass</em>:</p>
<pre><code>var Klass = (function() {
	return function(classDefinition) {
		var dummyClass = function() {
			this.Init &#038;&#038; typeof this.Init === "function" &#038;&#038; this.Init.apply(this, arguments);
		};

		<b>for (var member in classDefinition) {
			if (classDefinition.hasOwnProperty(member)) {
				dummyClass.prototype[member] = classDefinition[member];
				classDefinition[member] = null;
			}
		}</b>
		return dummyClass;
	};
})();</code></pre>
<p>Zrobiliśmy to prostą iteracją przez wszystkie klucze <em>classDefinition</em>, a więc w wypadku klasy <em>Animal</em> iterujemy przez:</p>
<pre><code>Init: function(age) {
	this.setAge(age);
},
age: null,
getAge: function() { return this.age; },
setAge: function(age) { this.age = age; }</code></pre>
<p>Sprawdźmy, czy nasz dotychczasowy kod działa:</p>
<pre><code>var Animal = new Klass({
	Init: function(age) { this.age = age; },
	age: null
});
var zwierze = new Animal(10);
alert(zwierze.age); // 10</code></pre>
<p>Jest fajnie, ale brakuje czegoś istotnego. Oczywiście chodzi o dziedziczenie, które zadziała, kiedy podamy w definicji klasy słówko <span class="f">Extends</span>.</p>
<pre><code>var Klass = (function() {
	return function(classDefinition) {
		var dummyClass = function() {
			this.Init &#038;&#038; typeof this.Init === "function" &#038;&#038; this.Init.apply(this, arguments);
		};

		<b>if (typeof classDefinition.Extends === "function") {}
		delete classDefinition.Extends;</b>

		for (var member in classDefinition) {
			if (classDefinition.hasOwnProperty(member)) {
				dummyClass.prototype[member] = classDefinition[member];
				classDefinition[member] = null;
			}
		}
		return dummyClass;
	};
})();</code></pre>
<p>Umiejętnie rozpoznaliśmy sytuację, kiedy należy rozszerzyć klasę potomną o klasę bazową. Następnie usunęliśmy wartość <em>Extends</em>, by nie była kopiowana w pętli, chociaż to od nas zależy. Równie dobrze można by ją zostawić. </p>
<p>Wiemy, że musimy rozszerzyć <span class="f">dummyClass</span> o <span class="f">classDefinition.Extends</span>. Automatycznie myślimy więc o <em>prototypach</em>, które należy przekazać do <em>classDefinition</em>. Można więc zrobić tak:</p>
<pre><code>dummyClass.prototype = classDefinition.Extends.prototype</code></pre>
<p>Jak wiemy, wartość <span class="f">.prototype</span> jest referencją do obiektu. Jeśli więc coś zmieni się w prototypie <em>classDefinition.Extends</em>, zmieni się również w prototypie <em>dummyClass</em>. </p>
<p>Słowem, dwa różne obiekty korzystałyby z tego samego prototypu, co może wywołać wiele zagrożeń. Zaradzić temu można w ten sposób:</p>
<pre><code>var Klass = (function() {
	return function(classDefinition) {
		var dummyClass = function() {
			this.Init &#038;&#038; typeof this.Init === "function" &#038;&#038; this.Init.apply(this, arguments);
		};

		if (typeof classDefinition.Extends === "function") {
			<b>var temp = function() {};
			temp.prototype = classDefinition.Extends.prototype;
			dummyClass.prototype = new temp;
			temp = null;</b>
		}
		delete classDefinition.Extends;

		for (var member in classDefinition) {
			if (classDefinition.hasOwnProperty(member)) {
				dummyClass.prototype[member] = classDefinition[member];
				classDefinition[member] = null;
			}
		}
		return dummyClass;
	};
})();</code></pre>
<p>I tak właśnie powstała dość funkcjonalna fabryczka klas, choć z wieloma ograniczeniami, które z pewnością łatwo dostrzeżecie. Brakuje, co ważne, metody na wzór <em>super()</em>, która odnosiłaby się do analogicznych metod z klasy bazowej. Zadanie to postaram opisać się później. Temat poruszę też prawdopodobnie także na następnym szkoleniu.</p>
<p>Na koniec wypada przetestować nasz kod:</p>
<pre><code>var Animal = new Klass({
	Init: function(age) {
		this.setAge(age);
	},
	age: null,
	getAge: function() { return this.age; },
	setAge: function(age) { this.age = age; }
});

var Dog = new Klass({
	Extends: Animal,
	getVoice: function() { return "hau hau"; }
});

var pies = new Dog(10);
pies.getVoice(); // "hau hau";
pies.getAge(); // 10
pies.setAge(100);
pies.getAge(); // 100
pies instanceof Animal; // true
pies instanceof Dog; // true</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/javascript/klasyczne-klasy-w-javascript/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>&#8222;this&#8221; w JavaScript</title>
		<link>http://ferrante.pl/frontend/javascript/this-w-javascript/</link>
		<comments>http://ferrante.pl/frontend/javascript/this-w-javascript/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 21:36:51 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=672</guid>
		<description><![CDATA[Niedawno przyznałem, że na podstawie szkolenia pojawią się nowe artykuły. Czasem będą one kopiować jego treść, a innym razem ją rozszerzą, czy dopowiedzą to, co zostało z różnych przyczyn pominięte/uproszczone. Czas na pierwszy temat, czyli co tak naprawdę oznacza mityczne słówko this w JavaScript. this występuje w blokach funkcyjnych bądź w globalnym scope, jak zresztą [...]]]></description>
			<content:encoded><![CDATA[<p>Niedawno przyznałem, że na podstawie szkolenia pojawią się nowe artykuły. Czasem będą one kopiować jego treść, a innym razem ją rozszerzą, czy dopowiedzą to, co zostało z różnych przyczyn pominięte/uproszczone. Czas na pierwszy temat, czyli co tak naprawdę oznacza mityczne słówko <span class="f">this</span> w JavaScript.<span id="more-672"></span></p>
<p><strong>this</strong> występuje w blokach funkcyjnych bądź w globalnym <em>scope</em>, jak zresztą zdążyliście już pewnie nieraz zauważyć. Ciężko tak naprawdę powiedzieć, co dokładnie oznacza. Chyba najlepszą definicją będzie to, że <em>this</em> wskazuje na jakiś obiekt w zależności od <em>kontekstu</em>, w jakim została użyta funkcja, w której go zdefiniowaliśmy. Pisząc kontekst mam nam myśli głównie sposób i miejsce wywołania.</p>
<h3>Obiekt globalny</h3>
<p>O JavaScript w przeglądarkach wiemy, że obiekt globalny wskazuje na <span class="f">window</span>. Tym samym <span class="f">this</span> użyty w globalnym kontekście będzie wskazywał także na <em>window</em>:</p>
<pre><code>&lt;script type="text/javascript"&gt;
	window === this; <strong>// true</strong>
&lt;/script&gt;</code></pre>
<p>W ten sposób z łatwością możemy dojść do wniosku, że poniższa funkcja użyta w globalnym <em>scope </em> zawsze będzie zwracała obiekt globalny:</p>
<pre><code>&lt;script type="text/javascript"&gt;
	var global = (function() { return this; })();
&lt;/script&gt;</code></pre>
<h3>Konstruktory a funkcje</h3>
<p>Zobaczmy, co dzieje się, kiedy zdefiniujemy jakąś funkcję, która dodaje pewną własność do obiektu, na który będzie wskazywał <em>this</em>:</p>
<pre><code>var fn = function() {
	this.foobar = "foo";
};</code></pre>
<p>Mając do dyspozycji coś takiego, jak powyżej, możemy naciąć się na dwa zupełnie różne zachowania. Możemy przecież napisać potem tak:</p>
<pre><code>var fn = function() {
	this.foobar = "foo";
};
var obj = new fn;</code></pre>
<p>Lub tak:</p>
<pre><code>var fn = function() {
	this.foobar = "foo";
};
fn();</code></pre>
<p>W pierwszym przypadku tworzymy instancję nowego obiektu na podstawie konstruktora <span class="f">fn</span>. Jak możemy się domyślić, w ten sposób <em>this</em> będzie wskazywał na nowoutworzony obiekt (<span class="f">obj</span>) i będziemy mogli użyć czegoś podobnego:</p>
<pre><code>var fn = function() {
	this.foobar = "foo";
};
var obj = new fn;
obj.foobar; <strong>// "foo"</strong></code></pre>
<p>W drugim listingu nie korzystamy jednak z operatora <span class="f">new</span>, co za tym idzie nie tworzymy bezpośrednio nowego obiektu na podstawie konstruktora. Uruchamiamy po prostu funkcję jak każdą inną. Po wykonaniu się tego kodu nie dostajemy błędu, tak że możemy być pewni, że wszystko poszło dobrze i jest on &#8211; przynajmniej pod względem składni &#8211; absolutnie poprawny. Co więc dzieje się tutaj?:</p>
<pre><code>fn();</code></pre>
<p>JavaScript w takich przypadkach domyślnie przekierowuje na samą górę scope i <strong>this</strong> będzie wskazywał na obiekt globalny. W ten sposób pod <em>this</em> będzie ukryta referencja do <em>window</em> i będziemy mogli użyć zmiennej globalnej <em>foobar</em> tak:</p>
<pre><code>window.foobar; <strong>// "foo"</strong></code></pre>
<p>Bądź tak:</p>
<pre><code>window['foobar']; <strong>// "foo"</strong></code></pre>
<p>A także tak, jak poniżej, jako że każdy składnik obiektu <em>window</em> jest zmienną globalną:</p>
<pre><code>foobar; <strong>// "foo"</strong></code></pre>
<p>Warto także powiedzieć, że funkcje zdefiniowane w innych konstruktorach/funkcjach nie dziedziczą <em>this</em> z funkcji wyżej, tylko także odwołują się do globalnego obiektu:</p>
<pre><code>var zewnetrzna = function() {
	return function wewnetrzna() {
		return this;
	};
};

var fn = new zewnetrzna();
fn(); <strong>// window</strong></code></pre>
<h3>Object literals</h3>
<p>Ważny jest, jak powiedziałem, kontekst. Definiując sobie obiekt w postaci <em>object literal</em>, <span class="f">this</span> odwołuje się domyślnie do obiektu, w którym został utworzony:</p>
<pre><code>var obj = {
	bar: function() { return this; }
};</code></pre>
<p>Pisząc więc coś takiego:</p>
<pre><code>obj.bar();</code></pre>
<p><em>this</em> wskaże na <em>obj</em>. Przy okazji udowodnijmy kolejny raz, że funkcje wewnętrzne nie dziedziczą <em>this</em>:</p>
<pre><code>var obj = {
	bar: function() {
		console.log(this);
		return function() {
			console.log(this);
			return this;
		}
	}
};</code></pre>
<p>Szybki test potwierdza naszą tezę:</p>
<pre><code>obj.bar()();</code></pre>
<p>Choć pamiętajmy, że równie dobrze można zapisać tak:</p>
<pre><code>var fn = obj.bar();
fn();</code></pre>
<p>Wszystko wygląda tak dlatego, że JavaScript wspiera zwracanie funkcji, które możemy potem uruchomić dodając nawiasy wywołania.</p>
<p>Zobaczymy teraz bardzo ciekawą rzecz, związaną z kontekstem. Zdefiniujmy najpierw <em>object literal</em>:</p>
<pre><code>var obj = {
	bar: function() {
		return this;
	}
};</code></pre>
<p>Uruchamiając to tak:</p>
<pre><code>obj.bar(); <strong>// obj</strong></code></pre>
<p><em>this</em> zwraca <em>obj</em>. Jeśli jednak literalnie zmienimy to, co będzie po kropce, kontekst będzie już inny:</p>
<pre><code>var f = obj.bar;
f(); <strong>// window</strong></code></pre>
<p>Dlaczego tak?</p>
<p>Jako że zmienne globalne możemy pisać tak:</p>
<pre><code>window['globalna'] = "cos";
window['globalna']; // "cos"</code></pre>
<p>Równie dobrze możemy zrobić jak poniżej, co wyjaśni nam, dlaczego <em>this</em> wskazuje na <em>window</em>:</p>
<pre><code>window['f'] = obj.bar;
window['f'](); <strong>// window</strong></code></pre>
<p>Mamy więc po lewej obiekt <em>window</em>, czyli funkcja <strong>f</strong> jest uruchamiana właśnie w jego kontekście i to do niego <em>this</em> będzie odnosił.</p>
<p>Przeanalizujcie też poniższy kod, który wynikł z inicjatywy <a href="http://blog.kukawski.pl">Rafała Kukawskiego</a> w trakcie rozmowy ze mną:</p>
<pre><code>var fn = function() {
	var b = function(){
		return this;
	};
	this.foo = function() {
		return b();
	}
};
var obj = new fn();
obj.foo(); // window</code></pre>
<p><strong>Inne metody</strong></p>
<p><em>this</em> można również zmienić poprzez metody <em>call</em> i <em>apply</em> wywołane na konstruktorach, ale to temat na kolejny artykuł.</p>
<p>Na koniec ćwiczenie ze szkolenia &#8211; co zwróci następujący kod i dlaczego:</p>
<pre><code>var e = !!3;
var fn = function() {
	return {
		foobar: this.e,
		e: !!0
	};
};

var res = fn();
res.foobar; // ?</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/javascript/this-w-javascript/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Ile tu jest błędów &#8211; rozwiązanie</title>
		<link>http://ferrante.pl/frontend/javascript/ile-tu-jest-bledow-rozwiazanie/</link>
		<comments>http://ferrante.pl/frontend/javascript/ile-tu-jest-bledow-rozwiazanie/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 22:58:44 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=611</guid>
		<description><![CDATA[Pora (nie, nie będę liczył ile postów mogło ukazać się przez ten czas &#8211; za dużo&#8230;) na przedstawienie błędów z poprzedniej notki. Mam nadzieję, że się spodobało. Uważam to za jedno z bardziej przydatnych pytań na rozmowę kwalifikacyjną &#8211; potrafi bezstresowo wyłapać kandydata z dużą wiedzą na temat języka. Sprawdziłem w praktyce &#8211; chyba najlepiej [...]]]></description>
			<content:encoded><![CDATA[<p>Pora (nie, nie będę liczył ile postów mogło ukazać się przez ten czas &#8211; za dużo&#8230;) na przedstawienie błędów z poprzedniej notki. Mam nadzieję, że się spodobało. Uważam to za jedno z bardziej przydatnych pytań na rozmowę kwalifikacyjną &#8211; potrafi bezstresowo wyłapać kandydata z dużą wiedzą na temat języka. Sprawdziłem w praktyce &#8211; chyba najlepiej odbierane zadanie.<span id="more-611"></span> Do rzeczy jednak &#8211; mieliśmy za zadanie przeanalizować poniższy kod:</p>
<pre><code>var foobar = {
	property: Infinity,
	enum = {
		10th: "ten",
		20th: "twenty"
	},
	toString: (function() {
		return (NaN || foobar).toString();
	})(),
	copy: false &#038;&#038; this.alert,
	clone: function() {
		this.__proto__ = foobar;
	},
};

var obj = new foobar().clone();</code></pre>
<p>Zróbmy to linijka po linijce.</p>
<pre><code>var foobar = {</code></pre>
<p>Inicjujemy <span class="f">object literal</span>, czyli nic innego, jak gotowy (niepotrzebne jest tworzenie nowej instancji) obiekt.</p>
<pre><code>property: Infinity,</code></pre>
<p>Definiujemy pierwsza składową obiektu (dostęp do niej byłby realizowany poprzez <span class="f">foobar.property</span>). <em>Infinity</em> to po prostu wartość w JS, oznaczająca nieskończoność (typu &#8222;number&#8221; &#8211; <span class="f">typeof Infinity === &#8222;number&#8221;<span>).</p>
<pre><code>enum = {</code></pre>
<p>Kolejna składowa (będąca obiektem) o nazwie enum. Wszystko byłoby w porządku, gdyby nie JScript Microsoftu. <em>Enum</em> jest słowem zarezerwowanym przez ten język, więc wszelkie jego użycie w IE kończy się błędem! Warto też wiedzieć, że <em>enum</em> jest wyrażeniem zarezerwowanym (w kontekście przyszłych rozwiązań) przez standard ECMA, na którym jest oparty JavaScript. Poza tym zamiast <span class="f">=</span> powinno być <span class="f">:</span>.</p>
<pre><code>10th: "ten",</code></pre>
<p>Niestety własności obiektu ani nazwy zmiennych nie mogą zaczynać się od cyfry, więc mamy kolejny błąd.</p>
<pre><code>20th: "twenty"</code></pre>
<p>Jak wyżej.</p>
<pre><code>},</code></pre>
<p>Czysto, uff.</p>
<pre><code>toString: (function() {</code></pre>
<p>Definiujemy kolejną składową obiektu &#8211; nic wielkiego, warto jednak zwrócić uwagę na zapis <span class="f">(function() {})()</span> &#8211; co wywołuje automatycznie funkcję podaną pomiędzy nawiasami (funkcję anonimową). Jeśli funkcja ta zwracałaby jakąś wartość, wtedy <em>toString</em> będzie się jej równać, inaczej będzie równy <em>undefined</em> (ponieważ nic nie zostanie zwrócone, a zmienne w JS domyślnie przyjmują taką wartość).</p>
<pre><code>return (NaN || foobar).toString();</code></pre>
<p>No i chcemy coś zwrócić. Zapis <span class="f">||</span> jest skróconym zapisem poniższej konstrukcji warunkowej:</p>
<pre><code>if (NaN) { return NaN; } else { return foobar; }</code></pre>
<p>Jedna z fajniejszych cech języka. Oczywiście mogą się pojawić głosy o nieczytelności, ale będą to raczej skomlenia programistów przyzwyczajonych do innych języków &#8211; w JS konstrukcja ta jest szybsza i wydaje się bardziej naturalna (o ile oczywiście programujemy na co dzień w JavaScript).</p>
<p>Przechodząc do analizy tej linii mamy prosty warunek. Jako że <span class="f">NaN</span> to jedna z <a href="http://ferrante.pl/2009/09/05/falsy-values-i-operatory-porownania/">falsy values</a> i przy skonwertowaniu do wartości logicznej da <em>false</em>, JS spróbuje wziąć sobie zmienną <em>foobar</em> i na niej uruchomić funkcję <em>toString</em>. Ponieważ zmienna <em>foobar</em> w chwili uruchomienia anonimowej funkcji jest niewidoczna dla obiektu (<em>undefined</em>) &#8211; dostaniemy błąd.</p>
<p>Następnie mamy:</p>
<pre><code>copy: false &#038;&#038; this.alert,</code></pre>
<p>Chcemy przypisać do <em>copy</em>&#8230; no właśnie, co? <span class="f">foobar = foo &#038;&#038; bar</span> to nic innego jak:</p>
<pre><code>if (!foo) {
	return foo;
}
return bar;</code></pre>
<p>Jako że pierwsze jest <em>false</em> to szybko kończymy zabawę i <em>copy</em> przyjmuje wartość <em>false</em> właśnie. Warto wyróżnić <a href="http://ferrante.pl/2009/09/10/ile-tu-jest-bledow/#comment-9245">komentarz mcv</a>:</p>
<blockquote><p>this.alert się nie wykona ze względu na “false &#038;&#038;”. Poza tym… nie wiadomo czy nie ma takiej właściwości w kontekście definiowania tej zmiennej (foobar). A nuż jest? „this” tutaj nie odwołuje się do foobar.</p></blockquote>
<p>Pełna zgoda, popatrzmy na przykład, kiedy powyższa sytuacja występuje:</p>
<pre><code>var fn = function() {
	this.alert = "tadam!"

	var obj = {
		property: this.alert
	}
	return obj;
}

var foobar = new fn;
alert(foobar.property);</code></pre>
<pre><code>clone: function() {</code></pre>
<p>Tworzymy funkcję <em>clone</em>. Nic wielkiego.</p>
<pre><code>this.__proto__ = foobar;</code></pre>
<p>W sumie wszystko w porządku &#8211; o ile obiekt w chwili jego inicjalizacji nie widzi <em>foobar</em>, tak funkcja wewnątrz obiektu owszem (a raczej będzie widziała w chwili użycia)  &#8211; słowo klucz: <em>closures</em>. Gdyby składnia była bez błędów, można by napisać coś podobnego:</p>
<pre><code>(new foobar.clone).__proto__.clone</code></pre>
<pre><code>},</code></pre>
<p>W przypadku ostatniego elementu obiektu nie stawiamy przecinka. Firefox to toleruje, IE natomiast nie.</p>
<pre><code>var obj = new foobar().clone();</code></pre>
<p><em>foobar</em> nie jest konstruktorem, a gotowym obiektem, więc nie możemy stworzyć instancji nowego obiektu korzystając z obiektu.</p>
<p>Gratuluję komentatorom &#8211; wielu z Was wysnuło bardzo ciekawe wnioski i uwagi!</p>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/javascript/ile-tu-jest-bledow-rozwiazanie/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ile tu jest błędów?</title>
		<link>http://ferrante.pl/frontend/javascript/ile-tu-jest-bledow/</link>
		<comments>http://ferrante.pl/frontend/javascript/ile-tu-jest-bledow/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 19:19:25 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=603</guid>
		<description><![CDATA[Właśnie, jak w temacie. Pomyślałem, że niezłym pomysłem będzie po prostu wrzucenie kodu i pytanie do Was, co tutaj jest źle? Ten, kto wymieni najwięcej błędów (najlepiej w komentarzach) i odpowiednio wyjaśni każdy z nich zgarnia główną nagrodę jakimi są prestiż i uznanie tutejszych Czytelniczek i Czytelników. Jest o co walczyć, prawda? Po jakimś czasie [...]]]></description>
			<content:encoded><![CDATA[<p>Właśnie, jak w temacie. Pomyślałem, że niezłym pomysłem będzie po prostu wrzucenie kodu i pytanie do Was, co tutaj jest źle? Ten, kto wymieni najwięcej błędów (najlepiej w komentarzach) i odpowiednio wyjaśni każdy z nich zgarnia główną nagrodę jakimi są prestiż i uznanie tutejszych Czytelniczek i Czytelników. Jest o co walczyć, prawda? Po jakimś czasie opublikuję rozwiązanie zagadki.</p>
<pre><code>var foobar = {
	property: Infinity,
	enum = {
		10th: "ten",
		20th: "twenty"
	},
	toString: (function() {
		return (NaN || foobar).toString();
	})(),
	copy: false &#038;&#038; this.alert,
	clone: function() {
		this.__proto__ = foobar;
	},
};

var obj = new foobar().clone();</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/javascript/ile-tu-jest-bledow/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Falsy values i operatory porównania</title>
		<link>http://ferrante.pl/frontend/javascript/falsy-values-i-operatory-porownania/</link>
		<comments>http://ferrante.pl/frontend/javascript/falsy-values-i-operatory-porownania/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 16:22:15 +0000</pubDate>
		<dc:creator>ferrante</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Vademecum]]></category>

		<guid isPermaLink="false">http://ferrante.pl/?p=596</guid>
		<description><![CDATA[Jest coś takiego w JavaScript, co się zowie jak powyżej. Niestety, bardzo często jest to temat niezrozumiały. Miałem okazję uczestniczyć bądź po prostu układać pytania do kilku rekrutacji na JavaScript developera w dużych firmach i muszę stwierdzić, że czasem bywa wręcz z falsy values dramatycznie. O co takiego chodzi? Falsy values1 to nic innego, jak [...]]]></description>
			<content:encoded><![CDATA[<p>Jest coś takiego w JavaScript, co się zowie jak powyżej. Niestety, bardzo często jest to temat niezrozumiały. Miałem okazję uczestniczyć bądź po prostu układać pytania do kilku rekrutacji na JavaScript developera w dużych firmach i muszę stwierdzić, że czasem bywa wręcz z falsy values dramatycznie.<span id="more-596"></span></p>
<p>O co takiego chodzi? <span class="f">Falsy values</span><a href="#przypis-1" class="hint"><sup>1</sup></a> to nic innego, jak zbiór wartości, które dają fałsz. Coś w ten deseń:</p>
<pre><code>if (!value) {
	console.log('Jedną z falsy values jest: '+ value);
}</code></pre>
<p>Pytanie, jakie są to wartości? Oto one:</p>
<ul>
<li>&#8222;&#8221; &#8211; pusta zmienna typu String</li>
<li>0 &#8211; typu Number</li>
<li>false typu Boolean</li>
<li>undefined</li>
<li>null</li>
<li>NaN typu Number</li>
</ul>
<p>Czyli:</p>
<pre><code>if (!NaN) {
	console.log('Jedną z falsy values jest: '+ NaN);
}</code></pre>
<pre><code>if (!null) {
	console.log('Jedną z falsy values jest: '+ null);
}</code></pre>
<p>Wszystkie te wartości przy konwertowaniu na typ Boolean (np. <span class="f">!!NaN</span>) dają <span class="f">false</span>. Warto zapamiętać!</p>
<h3>Operatory porównania w JavaScript</h3>
<p>Jeśli mowa o <em>falsy values</em> ciekawe rzeczy dzieją się przy ich porównywaniu. Jak wiadomo, mamy operatory <span class="f">==</span> i <span class="f">===</span>. Mnóstwo ludzi wykłada się na tym, banalnym zresztą (po głębszej analizie) problemie.</p>
<p>Warto zapamiętać, że pierwszy operator porównuje jedynie wartości, drugi &#8211; wartości oraz typy. Poniższe przykłady dają więc <span class="f">prawdę</span>:</p>
<pre><code>"0" == 0
"    " == 0
[] == 0
undefined == null
false == new String("")</code></pre>
<p><span class="f">Fałsz</span> zwracają natomiast podobne konstrukcje:</p>
<pre><code>NaN == 0
null == 0
undefined == ""
0 == {}</code></pre>
<p>Kiedy idzie o operator ścisłego porównania robi się ciekawiej &#8211; JavaScript oprócz logicznej wartości porównuje również typy zmiennych (a więc czy są obiektem, stringiem, liczbą itd.). <span class="f">Prawdę</span> zwracają:</p>
<pre><code>0 === 0
"" === ""
[] !== [] // dla kontrastu..</code></pre>
<p><span class="f">Fałsz</span> natomiast poniższe przykłady:</p>
<pre><code>"" === 0 // typ string i number
0 === null // typ number i object
[] === 0 // typ object i number
[] === "    " // typ object i string</code></pre>
<p>Warto więc być ostrożnym w trakcie pisania aplikacji w JavaScript.</p>
<hr />
<ol id="notes">
<li id="przypis-1">Temat falsy values poruszył na przykład Douglas Crockford w swojej znakomitej książce &#8222;JavaScript: The Good Parts&#8221;. Polecam!</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://ferrante.pl/frontend/javascript/falsy-values-i-operatory-porownania/feed/</wfw:commentRss>
		<slash:comments>30</slash:comments>
		</item>
	</channel>
</rss>

