On Github miroslavpopovic / i-hate-love-js
Prezentacija za HTML5/JavaScript korisnicku grupu, Banja Luka
Autor Miroslav Popovic / @miroslavpopovic
// DOM Level 0 (< IE5.5)
var form = document.forms['formId'];
// DOM Level 1+
var form = document.getElementById('formId');
// DOM - Web standard (IE9+ i svi ostali)
var text = element.textContent;
// IE, WebKit (Safari, Chrome), Opera
var text = element.innerText;
// Prije DOM Level 2
element.onclick = function() { ... }
// < IE9
element.attachEvent('onclick', function() { ... });
// DOM Level 2
element.addEventListener('click', function() { ... });
Starije verzije IE i Opere vracaju element po imenu, ne po id-u
innerText ne vraca sadrzaj style i script elemenata kao ni nevidljive elemente
if (navigator.userAgent.indexOf('MSIE') != -1) {
// IE kod ovdje...
} else {
// Non-IE kod ovdje...
}
<!--[if IE 6]>
<html lass="ie6">
<![endif]-->
<!--[if !IE]>
<html lass="non-ie">
<![endif]-->
Odredjivanje tipa i verzije browsera
IE 10 je izbacio conditional comments
var modifyText = function() { ... };
if (element.addEventListener) {
element.addEventListener('click', modifyText);
} else {
element.attachEvent('onclick', modifyText);
}
Polyfill - JavaScript shim - replicira ponasanje API-a prema web standardima
Primjer - window.WebSockets
jQuery
var form = $('#formId');
var text = $(element).text();
$(element).click(function () { ... });
$(element).on('click', function () { ... });
Modernizr
Modernizr.load({
test: Modernizr.geolocation,
yep : 'geo.js',
nope: 'geo-polyfill.js'
});
if (Modernizr.touch) {
// ...
} else {
// ...
}
alert('Ne radi ti ovo...');
IE prije 10 godina
Editori: Front Page, Dreamweaver
window objekat, global objekat
var glob = 'globalna varijabla';
function localScope() {
var local = 'lokalna varijabla';
glob2 = 'globalna varijabla - nema var';
}
window.alert = function(message) {
console.log(message);
}
alert('ovaj tekst ce biti ispisan u konzoli');
ne postoji block scope
if (condition) {
var local = 'da li je ovo lokalna varijabla?';
}
console.log(local);
var local;
if (condition) {
local = 'da li je ovo lokalna varijabla?';
}
console.log(local);
Hoisting
Automatic semicolon insertion
return
{
status: true
};
return; // undefined
{
status: true
};
// Ispravno koristenje
return {
status: true
};
abstract boolean break byte case catch char class const continue
debugger default delete do double else enum export extends false
final finally float for function goto if implements import in
instanceof int interface long native new null package private
protected public return short static super switch synchronized this
throw throws transient true try typeof var volatile void while with
var method; // OK
var class; // greska
object = {box: value}; // OK
object = {case: value}; // greska
object = {'case': value}; // OK
object.box = value; // OK
object.case = value; // greska
object['case'] = value; // OK
Vecina rezervisanih rijeci se ne koristi unutar JavaScript jezika
typeof 55.4 // 'number' - OK
var vrijednost = null;
typeof vrijednost // 'object' !!
// bolje rjesenje za null provjeru
vrijednost === null
// provjera da li varijabla sadrzi objekat
if (vrijednost && typeof vrijednost === 'object') {
// vrijednost je objekat ili niz (array)
}
// regularni izrazi
typeof /a/ // 'object' ili 'function', zavisno od browsera
Posto typeof ne moze da razlikuje izmedju null i object, moramo koristiti cinjenicu da je
null falsy vrijednost, a da su objekti truthy;
var prvi = 100;
var drugi = '50';
prvi + drugi // '10050' - konverzija u string
parseInt('20') // 20
parseInt('20 kg') // 20
parseInt('8') // 8
parseInt('08') // 0 !! - oktalni broj
parseInt('08', 10) // 8 - radix parametar
0.1 + 0.2 === 0.3 // false, 0.1 + 0.2 = 0.30000000000000004
10 + 20 === 30 // true
Skaliranje brojeva sa pokretnim zarezom u integer rijesava problem... Npr. mnozenje sa 100
typeof NaN === 'number' // true
34 + NaN // NaN
NaN === NaN // false
NaN !== NaN // true
isNaN(NaN) // true
isNaN(0) // false
isNaN('greska') // true
isNaN('0') // false
0 // Number
NaN // Number
'' // String
false // Boolean
null // Object
undefined // Undefined
var value = myObject[name];
if (value == null) {
console.log(name + ' not found.');
}
var value = myObject[name];
if (typeof value === 'undefined') {
console.log(name + ' not found.');
}
Falsy vrijednosti ne mogu da se zamjenjuju medjusobno;
Prvi primjer je pogresan nacin za provjeru da li objekat sadrzi property.
var x = [1,2,3,]; //ERROR
var y = {'a': 1, 'b': 2, 'c': 3,}; //ERROR
Problem za IE < 9
'' == '0' // false
0 == '' // true
0 == '0' // true
false == 'false' // false
false == '0' // true
false == undefined // false
false == null // false
null == undefined // true
Preporuka: Uvijek koristiti === i !==
== i != nisu tranzitivni Svi navedeni izrazi vracaju false sa ===
with (obj) {
a = b;
}
eval('a = a + 1');
setTimeout('...JS kod...', 1000);
setInterval('...JS kod...', 1000);
// ...
with usporava JS procesor;
eval takodje - pokrece kompajler - moguce izvrsiti bilo kakav JS kod;
JSLint - By Douglas Crockford - za izbjegavanje ovakvih problema; JSHint;
var myObject = {
'prop1': 'value 1',
'prop2': 2,
'prop3': true,
'prop4': function() {}
};
var myObject = {
prop1: 'value 1',
prop2: 2,
'class': 'info',
prop4: function() {},
complex: {
prop1: true,
prop2: [ 1, 2, 10 ]
}
};
var arr = [ 1, 15, 54, 3, function() {}, 'test', { prop1: true} ];
// JSON - JavaScript object notation
{
isLoaded: true,
message: 'ovo je JSON',
items: [
{ id: 1, name: 'item 1' },
{ id: 2, name: 'item 2' },
{ id: 3, name: 'item 3' }
]
}
new Object() i new Array() nisu preporucljivi;
literali su jednostavniji za citanje i sigurniji (Object i Array je moguce redefinisati)
Ne samo sintaksa... vrijednost
// Mogu biti smjestene u varijablu, niz ili neki drugi objekat
var myFunc = function() { };
var myFuncs = [ function() { /*...*/ }, function() { /*...*/ } ];
var myObject = { val1: true, val2: 10, func1: function() { /*...*/ }};
// Mogu biti argument neke druge funkcije
var max = function(val1, val2) { return val1 > val2 ? val1 : val2; },
min = function(val1, val2) { return val1 < val2 ? val1 : val2; };
var find = function(items, compare) {
var result = items[0];
for (var i = 1; i < items.length; i++) {
result = compare(result, items[i]);
}
return result;
};
var numbers = [5, 19, 44, 56, 2, 4];
var maxNumber = find(numbers, max); // 56
var minNumber = find(numbers, min); // 2
// Mogu biti povratna vrijednost neke druge funkcije
var logFactory = function(type) {
var
consoleLog = function(message) {
console.log(message);
},
alertLog = function(message) {
alert(message);
};
return type == 'alert' ? alertLog : consoleLog;
};
var log = logFactory('console');
log('Ovo ce biti ispisano u konzoli');
// Imaju sopstvene properties, posto su pravi objekti
var myFunc = function() { /*...*/ };
myFunc.prop1 = 10;
myFunc.prop2 = true;
myFunc();
// Prototypal inheritance
var Animal = function() {
this.name = '-no name-';
};
Animal.prototype = {
introduce: function() {
console.log('Hi, I am ' + this.Name);
}
}
var Cat = function() { /* ... */ };
Cat.prototype = new Animal();
var myCat = new Cat();
myCat.name = 'Kitty';
myCat.introduce();
var logFactory = function(type) {
var logCount = 0,
consoleLog = function(message) {
logCount++;
console.log('LOG ' + logCount + ': ' + message);
},
alertLog = function(message) {
logCount++;
alert('LOG ' + logCount + ': ' + message);
};
return type == 'alert' ? alertLog : consoleLog;
};
var log = logFactory('console');
log('Ovo ce biti ispisano u konzoli sa rednim brojem');
Ne postoji block scope, ali postoji function scope.
var numberRegex = /^-?\d+(?:\.\d*)?$/i;
var isNumber = function(num) {
return numberRegex.test(num);
};
isNumber('10'); // true
isNumber('number'); // false
isNumber('-5.3'); // true
isNumber('12.34.55.11'); // false
i flag u regularnom izrazu - ignore case
Pattern (sablon) je dokazano/testirano rjesenje odredjenog problema u razvoju softvera
Ponovno su iskoristivi su za slicne probleme
class Point extends Base {
constructor(x,y) {
super();
this[px] = x, this[py] = y;
this.r = function() { return Math.sqrt(x*x + y*y); }
}
get x() { return this[px]; }
get y() { return this[py]; }
proto_r() {
return Math.sqrt(this[px] * this[px] + this[py] * this[py]);
}
equals(p) {
return this[px] === p[px] && this[py] === p[py];
}
}
module math {
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
}
import {sum, pi} from math;
alert(sum(pi,pi));