Comments 61
1. копипастим из учебника 12 случайных глав. каждую главу сокращаем до 5 предложений.
2. пишем, что это очень крутые концепции (операторы — это концепции), о которых мало кто знает, но без которых прогу не написать, даже не пытайтесь!
3. PROFIT
это, например, типы Object, Array, Function
В javascript нет типов Array и Function. Есть Object.
Я бы перефразировал эту часть предложения.
Иначе это введет в заблуждение начинающих js'еров.
Ну, что-то напоминающее эти типы всё-таки есть.
"Объект типа Array" — это exotic object, ведущий себя как массив. Отличается от объекта переопределенным слотом [[DefineOwnProperty]]
, который корректирует length при добавлении элементов.
"Объект типа Function" — это объект с определёнными слотами [[Call]]
и [[Construct]]
хотя для опытных разработчиков они могут показаться утомительными и разочаровывающими
Согласен с вами, меня удивила destructuring assignment, не во всех браузерах это поддерживается. Может я не прав?
push() позволяет добавлять элементы в конец массива. <...> после завершения работы, возвращает элемент, добавленный в массив.Ну неправда же. Хоть бы посмотрели на своём любимом MDN.
<...> в отличие от трёх других рассмотренных здесь методов, unshift() возвращает новую длину массива.
[].push(10); // => 1
Когда-то давно меня очень удивили методы reduceRight() и copyWithin(). Прошли годы, а я так и не столкнулся ни с одним случаем их применения. :)
Было бы интересно узнать о таких, если кто-то знает.
[1, 2, 3].reduceRight((sum, x) => {
console.log(x);
return sum + x;
}, 0); // выводит 3, 2, 1; возвращает 6
Метод Array#copyWithin() копирует участок (slice) массива в него же, начиная с указанной позиции. MDN сравнивает его с сишной memmove().
let arr = [1, 2, 3, 4, 5, 6];
arr.copyWithin(/* target = */ 1, /* start = */ 4, /* end = */ 6);
// arr теперь [1, 5, 6, 4, 5, 6]
пример с copyWithin:
heap.copyWithin(target, start, end)
пример без copyWithin:
heap.set(new Uint8Array(heap.buffer, start, end - start), target)
много времени теряется на создание Uint8Array (особенно в Firefox и Edge) в ситуации, когда нужно копировать большое количество мелких блоков.
Его, в целом можно обобщить — copyWithin() позволяет реализовать быструю фильтрацию массива in-place. :)
Ну да, абсолютно точно не в том смысле, как функциональный filter(). Поэтому я использовал (придуманный на ходу) термин «фильтрация in-place», как мне кажется, он неплохо передаёт суть. Есть более общепринятый термин для такого алгоритма?
Выбрать в массиве все элементы, удовлетворяющие некоторому условию
какое условие? нужно читать описание метода, а не слушать голоса в своей голове.
Я ничего не писал про условие в copyWithin(), я написал что этот метод "позволяет реализовать быструю фильтрацию массива in-place" — собственно, так же, как это делает asm.js при реализации кучи.
Само собой, copyWithin() будет только частью такого алгоритма — реализуя перемещение непрерывных последовательностей элементов, удовлетворяющих условию, в начало массива.
И вот тут оказался как нельзя кстати reduceRight. Конечно, есть и другие варианты, но этот, возможно, самый лаконичный. Перебор, устойчивый к выкидыванию элементов в процессе.
Перебор, устойчивый к выкидыванию элементов в процессе.Ох, возможно, он и лаконичный, но мне лично пришлось немного поломать голову. Как-то я никогда не воспринимал так reduceRight(). :)
Насколько я понимаю, код в целом был примерно такой:
const array = [
{ value: 1, removed: false },
{ value: 2, removed: false },
{ value: 3, removed: true },
{ value: 4, removed: false }
];
array.reduceRight((_, value, index, array) => {
console.log(value);
if (value.removed) {
array.splice(index, 1);
}
}, null);
По-хорошему надо удалять непрерывными последовательностями — например через copyWithin(), чтобы было комбо. :)
Но мне важнее было получить простейший и наглядный пример.
let n = array.length
while (n--) {
if (array[n].removed) {
const swap = array.pop()
if (array.length != n)
array[n] = swap
}
}
Так будет эффективнее, хотя порядок элементов изменится.
В целом, ничто не мешает аналогичный код написать внутри reduceRight() — если в процессе обработки нужно свернуть массив. Но это уже дело вкуса.
{
const Node = (next, value) => ({next, value})
const array = [1, 2, 3, 4]
// create a linked list from the array
const listA = array.slice().reverse().reduce(Node, null)
// a better way of doing it:
const listB = array.reduceRight(Node, null)
}
Методы find(), findIndexOf() и indexOf()
В JS нет метода findIndexOf().
Я бы добавил раздел про mutable ("изменчивость"?), Array.concat(), Object.keys(), Object.values() и Object.entries().
И это довольно логично, поскольку создаются они с целью быть мощнее и выразительнее JS — теми, кому не хватило его возможностей.
Ошибки типизации разбирать не сложнее, чем ошибки runtime. Тем более, что многие сейчас импользуют typescript.
Elm еще избавляет от работы с DOM, которая привносит много сложности.
В общем страх перед функциональщиной совершенно не обоснован.
В общем страх перед функциональщиной совершенно не обоснован.Совершенно согласен.
Но это не отменяет того, что очень многим (включая и меня) разработчикам, выросшим (профессионально) на императивном программировании, функциональное даётся отнюдь не «просто».
многие сейчас импользуют typescriptИ TypeScript объективно сложнее JS.
Как в плане планки входа в язык (нужно знать JS + систему типов TS + как одно преобразуется в другое), так и в плане оверхеда при разработке (что на маленьких проектах часто делает TS избыточным).
Я наконец то нашёл адекватно и простое для моего понимания описание замыканий. Яба-даба-ду!!! XD XD XD.
Не вот серьёзно — куда бы не посмотрел какая-то муть. Т.е. описание что это такое — есть, а вот ЗАЧЕМ ОНО — в большинстве случаев опускается.
В следующем примере деструктурирование используется для аккуратной передачи значений, хранящихся в свойствах объекта person, функции introduce().
Что означает «для аккуратной передачи значений»? Есть еще и не аккуратная передача значений?
let [a, b, c] = shuffle([1, 2, 3]);
function shuffle(a) {
var j, x, i;
for (i = a.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
x = a[i];
a[i] = a[j];
a[j] = x;
}
return a;
}
Вообще в оригинале «destructuring is used to cleanly pass the person object to the introduce function» — т. е. скорее «для опрятной» (в плане самого кода).
Какие ещё концепции JavaScript вы добавили бы в эту статью?
сall()/bind()/apply(), примеры MDN.
call:
function Product(name, price) {
this.name = name;
this.price = price;
if (price < 0) {
throw RangeError('Нельзя создать продукт ' +
this.name + ' с отрицательной ценой');
}
return this;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'еда';
}
Food.prototype = Object.create(Product.prototype);
function Toy(name, price) {
Product.call(this, name, price);
this.category = 'игрушка';
}
Toy.prototype = Object.create(Product.prototype);
var cheese = new Food('фета', 5);
var fun = new Toy('робот', 40);
bind:
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var getX = module.getX;
getX(); // 9, поскольку в этом случае this ссылается на глобальный объект
// создаём новую функцию с this, привязанным к module
var boundGetX = getX.bind(module);
boundGetX(); // 81
apply:
/* мин/макс числа в массиве */
var numbers = [5, 6, 2, 3, 7];
/* используем apply к Math.min/Math.max */
var max = Math.max.apply(null, numbers); /* Это эквивалентно Math.max(numbers[0], ...)
или Math.max(5, 6, ...) */
var min = Math.min.apply(null, numbers);
/* сравним с простым алгоритмом с циклом */
max = -Infinity, min = +Infinity;
for (var i = 0; i < numbers.length; i++) {
if (numbers[i] > max) {
max = numbers[i];
}
if (numbers[i] < min) {
min = numbers[i];
}
}
Вы делаете reject, но не делаете обработку этого реджекта.
catch !== reject
А это тогда что?
.catch(function(err) {
console.log('Error: ' + err);
});
Например, throw new Error.
Важно понимать, что catch !== reject
12 концепций JavaScript, о которых нужно знать