За какво ще си говорим днес:
Не че нещо,
но JavaScript има характер.
Въпреки това, е чаровен.
Научете се да го обичате.
Как да разберем дали нещо е Array?
> typeof []
'object'
A дали е RegExp?
> typeof /./
'object'
Дори null?
> typeof null
'object'
Накратко — горе–долу
> ([]) instanceof Array
true
> (/./) instanceof RegExp
true
> null instanceof Object
false
Чупи се при null,
но не това е по-голямото зло.
document.body.appendChild(document.createElement('iframe'));
OtherArray = window.frames[window.frames.length - 1].Array;
var array = new OtherArray(1, 2, 3);
array instanceof Array; // false
array.constructor === Array; // false
Array === OtherArray; // false
Доста добро четиво по въпроса, може да намерите тук.
> {}.toString.call([]) === '[object Array]'
true
> {}.toString.call(/./) === '[object RegExp]'
true
> {}.toString.call(null) === '[object Null]'
true
За сравнение на стойност с null
value == null
true
Единствената смислена употреба на ==
Унарен оператор, който връща undefined за всичко, което му дадем отдясно.
void 0 === undefined
true
Какво ще направи следният код?
var i, link;
for (i = 0; i < 5; i++) {
link = document.createElement('a');
link.innerHTML = 'Link: ' + i;
link.onclick = function() {
alert(i);
};
document.body.appendChild(link);
}
Как да го оправим?
var i, link;
for (i = 5; i < 10; i++) {
link = document.createElement('a');
link.innerHTML = 'Link: ' + i;
link.onclick = (function(i) {
return function() {
alert(i);
}
})(i);
document.body.appendChild(link);
}
Тук, JavaScript е невинен!
Това е проблем при повечето динамични езици, като се среща при:
Внимавайте, къде и как правите анонимни фунцкии!
Искам да именувам първият от аргументите си като останалите да са вариадични.
var sum = function(first) {
var rest = arguments.slice(1);
var result = first;
for (var i = 0, len = rest.length; i < len; i++) {
result += rest[i];
}
return result;
};
sum(1, 2, 3);
TypeError: Object #<Object> has no method 'slice'
Това е интересно, нека видим какво става.
(function() {
console.log(typeof arguments); // object
console.log(arguments instanceof Array); // false
})();
arguments не е Array, въпреки че изглежда като такъв.
Как да го излъжем?
var sum = function(first) {
var rest = [].slice.call(arguments, 1);
var result = first;
for (var i = 0, len = rest.length; i < len; i++) {
result += rest[i];
}
return result;
};
sum(1, 2, 3);
6
Всъщност, това работи и за други Array подобни обекти.
var fragments = document.querySelectorAll('.fragment');
console.log(fragments instanceof Array); // false
console.log([].slice.call(fragments) instanceof Array); // true
Проблеми има колкото искаш.
Underscore is a utility-belt library for JavaScript that provides a lot of the functional programming support that you would expect in Prototype.js (or Ruby), but without extending any of the built-in JavaScript objects.
Функциите, предоставени от Underscore са групирани в следните категории:
Ще започнем с функциите за работа с обекти.
Сещате се за проблемите с typeof и instanceof?
console.log(_.isArray([])); // true
console.log(_.isObject([])); // true
console.log(_.isRegExp(/./)); // true
console.log(_.isBoolean(new Boolean)); // true
console.log(_.isDate(new Date)); // true
console.log(_.isNull(void 0)); // false
console.log(_.isUndefined(void 0)); // true
console.log(_.isNaN(NaN)); // true
_.isEmpty проверява дали обект е празен.
console.log(_.isEmpty({})); // true
console.log(_.isEmpty({option: true})); // false
_.isEqual сравнява обекти в дълбочина.
console.log(_({a: {b: 1}}).isEqual({a: {b: 1}})); // true
console.log(_({a: {b: 1}}).isEqual({a: {b: "1"}})); // false
_.extend(destination, *sources)
Събира ключовете на два или повече обекта в един.
Последният ключ печели.
_.extend({name : 'moe'}, {age : 50})
Хипер удобно!
_.pick(object, *keys)
Избира ключове от обект.
Връша нов обект само с тях.
Искам само name
и age
от
{name : 'moe', age: 50, userid : 'moe1'}
_.pick({name : 'moe', age: 50, userid : 'moe1'}, 'name', 'age');
Ключовете могат да са в масив.
_.pick({name : 'moe', age: 50, userid : 'moe1'}, ['name', 'age']);
Под колекции ще разбираме обекти, масиви и подобни
_.each(list, iterator, [context])
По-добрият начин за итерация
Контекстът може да бъде пропуснат, но е добра идея, ако ви трябва
При масиви и подобни, фунцкията се вика с:
(element, index, list)
При обекти, фунцкията се вика с:
(value, list)
Спомняте си проблемите с анонимните фунцкии?
_.each(_.range(5), function(i) {
var link = document.createElement('a');
link.innerHTML = 'Link: ' + i;
link.onclick = function() {
alert(i);
};
document.body.appendChild(link);
});
Предпочитайте го пред for!
_.map(list, iterator, [context])
Взима колекция и съпоставя функция за всеки елемент
Акумулира върнатите стойностти и ги връща в масив
_.map(_.range(4), function(i) {
return i * i;
});
_.filter(list, iterator, [context])
Взима колекция и съпоставя функция за всеки елемент
Събира елементите, за които функцията е била истина, в масив
_.filter(_.range(10), function(i) {
return i % 2 === 0;
});
_.reduce(list, iterator, memo, [context])
iterator(memo, value, key/index, list)
Без крави тука ☹
Събира голяма колекция в един резултат
_.reduce([1, 2, 3], function(memo, num) { return memo + num; }, 0);
_.toArray(obj)
Спомняте си [].slice
?
Това е по-добро и по-четимо
Ако не сте се досетили, хваща какво-да-е и го прави на масив.
(function(){ return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
Има още интересни фунцкии, които няма да можем да покажем сега. Разгледайте документацията.
Полезни фунцкии за масиви и подобни
_.flatten(array, [shallow])
Изглажда дълбоки масиви (колкото си искате дълбоки)
Ако shallow
е истина, изглажда само едно ниво
_.flatten([1, [2], [3, [[4]]]]);
_.flatten([1, [2], [3, [[4]]]], true);
_.compact(array)
Връща нов масив, без лъжливи стойностти
Лъжливи стойностти:
_.compact([0, 1, false, 2, '', 3]);
Има още интересни фунцкии, които няма да можем да покажем сега. Разгледайте документацията.
Позволява ни да извикваме редица от Underscore методи, върху една и съща колекция.
var lyrics = [
{line : 1, words : "I'm a lumberjack and I'm okay"},
{line : 2, words : "I sleep all night and I work all day"},
{line : 3, words : "He's a lumberjack and he's okay"},
{line : 4, words : "He sleeps all night and he works all day"}
];
_.chain(lyrics)
.map(function(line) { return line.words.split(' '); })
.flatten()
.reduce(function(counts, word) {
counts[word] = (counts[word] || 0) + 1;
return counts;
}, {})
.value();
За още информация последвайте следните връзки:
jQuery is a fast, small, and feature-rich JavaScript library. It makes things like HTML document traversal and manipulation, event handling, animation, and Ajax much simpler with an easy-to-use API that works across a multitude of browsers. With a combination of versatility and extensibility, jQuery has changed the way that millions of people write JavaScript.
Задължително минете през интерактивният урок, ако за пръв път чувате какво е jQuery. Прегледайте още:
Благодаря ☺