JavaScript — это мощный язык, который является частью фундамента интернета. У этого мощного языка также есть некоторые свои особенности. Например, знаете ли вы, что значение
0 === -0
равно true, или что Number("")
дает 0
?Дело в том, что иногда эти причуды могут заставить вас почесать в затылке или даже задаться вопросом, был ли Брендан Эйч под кайфом в тот день, когда он изобретал JavaScript. Что ж, дело здесь не в том, что JavaScript — плохой язык программирования или он — зло, как говорят его критики. Со всеми языками программирования связаны какие-то странности, и JavaScript не является исключением.
В этом материале мы покажем подробное объяснение некоторых важных вопросов на интервью по JavaScript. Моя цель будет состоять в том, чтобы тщательно объяснить эти вопросы, чтобы мы могли понять лежащие в их основе концепции.
❯ 1 – Более пристальный взгляд на операторы + и -
console.log(1 + '1' - 1);
Можете ли вы угадать поведение операторов + и — в ситуациях, подобных описанной выше?
Когда JavaScript встречает
1 + '1'
, он обрабатывает выражение с помощью оператора +. Одним интересным его свойством является то, что он предпочитает объединение строк, когда один из операндов является строкой. В нашем случае '1'
— это строка, поэтому JavaScript неявно преобразует числовое значение 1 в строку. Следовательно, 1+'1'
становится '1'+'1'
, в результате чего получается строка '11'
.Теперь наше уравнение равно
'11' - 1
. Поведение оператора — совершенно противоположное. Он отдает приоритет числовому вычитанию, независимо от типов операндов. Когда операнды не относятся к типу number
, JavaScript выполняет принуждение для преобразования их в числа. В этом случае '11'
преобразуется в числовое значение 11
, и выражение упрощается до 11 - 1
.Собирая все это воедино:
'11' - 1 = 11 - 1 = 10
❯ 2 – Дублирующие элементы массива
Рассмотрите следующий код JavaScript и попытайтесь найти какие-либо ошибки в нем:
function duplicate(array) {
for (var i = 0; i < array.length; i++) {
array.push(array[i]);
}
return array;
}
const arr = [1, 2, 3];
const newArr = duplicate(arr);
console.log(newArr);
В этом фрагменте кода нам требуется создать новый массив с дублированными элементами. На первым взгляд, код создает новый массив
newArr
путем дублирования каждого элемента из исходного массива arr
. Однако критическая проблема возникает внутри самой дублирующей функции.Функция
duplicate
использует цикл для перебора каждого элемента в заданном массиве. Но внутри цикла он добавляет новый элемент в конец массива, используя метод push()
. Это делает массив длиннее каждый раз, создавая проблему, при которой цикл никогда не остановится. Условие цикла (i < array.length
) всегда остается верным, потому что массив продолжает увеличиваться. Это приводит к тому, что цикл продолжается вечно, в результате чего программа зависает.Чтобы решить проблему бесконечного цикла, вы можете сохранить начальную длину массива в переменной перед входом в цикл. Затем вы можете использовать эту начальную длину в качестве ограничения для итерации цикла. Таким образом, цикл будет выполняться только для исходных элементов массива и не будет затронут ростом массива из-за добавления дубликатов.
Вот измененная версия кода:
function duplicate(array) {
var initialLength = array.length; // Store the initial length
for (var i = 0; i < initialLength; i++) {
array.push(array[i]); // Push a duplicate of each element
}
return array;
}
const arr = [1, 2, 3];
const newArr = duplicate(arr);
console.log(newArr);
На выходе будут дублированные элементы, и не будет бесконечного цикла:
[1, 2, 3, 1, 2, 3]
❯ 3 – Разница между prototype и __proto__
prototype
— это атрибут, связанный с функциями конструктора в JavaScript. Функции конструктора используются для создания объектов. Когда вы определяете функцию-конструктор, вы также можете присоединить свойства и методы к ее свойству prototype
. Затем они становятся доступными для всех объектов, созданных из этого конструктора. Таким образом, prototype
служит общим хранилищем для методов и свойств, которые совместно используются экземплярами.Рассмотрим следующий фрагмент кода:
// Constructor function
function Person(name) {
this.name = name;
}
// Adding a method to the prototype
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}.`);
};
// Creating instances
const person1 = new Person("Haider Wain");
const person2 = new Person("Omer Asif");
// Calling the shared method
person1.sayHello(); // Output: Hello, my name is Haider Wain.
person2.sayHello(); // Output: Hello, my name is Omer Asif.
В этом примере у нас есть функция-конструктор с именем
Person
. Расширяя Person.prototype
с помощью метода sayHello
, мы добавляем его в цепочку всех экземпляров Person
. Это позволяет каждому экземпляру Person
получать доступ к общему методу и использовать его. Вместо того, чтобы каждый экземпляр имел свою собственную копию метода.С другой стороны, свойство
__proto__
, часто произносимое как «dunder proto», существует в каждом объекте JavaScript. В JavaScript всё, кроме примитивных типов, может рассматриваться как объект. Каждый из этих объектов имеет прототип, который служит ссылкой на другой объект. Свойство __proto__
— это просто ссылка на этот объект-прототип. Он используется в качестве резервного источника для свойств и методов, когда исходный объект ими не обладает. По умолчанию, когда вы создаете объект, его прототипу присваивается значение Object.prototype
.Когда вы пытаетесь получить доступ к свойству или методу объекта, JavaScript выполняет процесс поиска, чтобы найти его. Этот процесс включает в себя два основных этапа:
- Собственные свойства объекта: JavaScript сначала проверяет, обладает ли сам объект непосредственно нужным свойством или методом. Если свойство найдено внутри объекта, оно используется напрямую.
- Поиск по цепочке прототипов: Если свойство не найдено в самом объекте, JavaScript просматривает прототип (на который ссылается свойство
__proto__
) и выполняет поиск свойства там. Этот процесс продолжается рекурсивно вверх по цепочке до тех пор, пока свойство не будет найдено или пока поиск не достигнетObject.prototype
.
Если свойство не найдено даже в
Object.prototype
, JavaScript возвращает undefined
, указывая, что свойство не существует.❯ 4 – Области применения
При написании кода на JavaScript, важно понимать концепцию области видимости. Область видимости показывает доступность переменных в различных частях вашего кода. Прежде чем перейти к примеру, если вы не знакомы с “поднятием” (hoisting) и с тем, как выполняется JavaScript-код, вы можете узнать об этом по этой ссылке. Это поможет вам более подробно понять, как работает JavaScript-код.
Давайте подробнее рассмотрим фрагмент кода:
function foo() {
console.log(a);
}
function bar() {
var a = 3;
foo();
}
var a = 5;
bar();
Код определяет 2 функции
foo()
и bar()
и переменную a
со значением 5
. Все эти операции делаются в общей области. Внутри функции bar()
объявляется переменная a
, которой присваивается значение 3
. Итак, когда вызывается функция bar()
, как вы думаете, какое значение a
она выведет?Когда движок JavaScript выполняет этот код, объявляется глобальная переменная a и ей присваивается значение
5
. Затем вызывается функция bar()
. Внутри функции bar()
объявляется локальная переменная a
, которой присваивается значение 3
. Эта локальная переменная a
отличается от глобальной переменной a
. После этого функция foo()
вызывается из функции bar()
.Внутри функции
foo()
оператор console.log(a)
пытается записать значение a
. Поскольку в области видимости функции foo()
не определена локальная переменная a, JavaScript просматривает цепочку областей видимости, чтобы найти ближайшую переменную с именем a
. Цепочка областей относится ко всем различным областям, к которым функция имеет доступ, когда она пытается найти и использовать переменные.Теперь давайте обратимся к вопросу о том, где JavaScript будет искать переменную
a
. Будет ли поиск в рамках функции bar
или будет охватывать глобальную область? Как оказалось, JavaScript будет выполнять поиск в глобальной области видимости, и такое поведение определяется концепцией, называемой лексической областью видимости.Лексическая область относится к области функции или переменной на момент ее написания в коде. Когда мы определили функцию
foo
, ей был предоставлен доступ как к ее собственной локальной области видимости, так и к глобальной. Эта характеристика остается неизменной независимо от того, где мы вызываем функцию foo
— внутри функции bar
или если мы экспортируем ее в другой модуль и запускаем там. Лексическая область не определяется там, где мы вызываем функцию.Результатом этого является то, что выходные данные всегда будут одинаковыми: значение
a
, найденное в глобальной области видимости, которое в данном случае равно 5
.Однако, если бы мы определили функцию
foo
внутри функции bar
, возник бы другой сценарий:function bar() {
var a = 3;
function foo() {
console.log(a);
}
foo();
}
var a = 5;
bar();
В этой ситуации лексическая область
foo
охватывала бы три различные области: его собственную локальную область, область функции bar
и глобальную область. Лексическая область определяется тем, куда вы помещаете свой код в исходном коде во время компиляции.Когда этот код запускается,
foo
находится внутри функции bar
. Такое расположение изменяет динамику масштаба. Теперь, когда foo
попытается получить доступ к переменной a
, он сначала выполнит поиск в своей собственной локальной области видимости. Поскольку он не находит там a
, он расширит свой поиск до области действия функции bar
. О чудо, там есть a со значением 3
. В результате консольный оператор выведет значение 3
.❯ 5 – Принуждение объекта
Одним из интригующих аспектов, требующих изучения, является то, как JavaScript обрабатывает преобразование объектов в примитивные значения, такие как строки, числа или логические значения. Это интересный вопрос, который проверяет, знаете ли вы, как принуждение работает с объектами.
Это преобразование имеет решающее значение при работе с объектами в таких сценариях, как объединение строк или арифметические операции. Чтобы достичь этого, JavaScript полагается на два специальных метода:
valueOf
и toString
.Метод
valueOf
является фундаментальной частью механизма преобразования объектов JavaScript. Когда объект используется в контексте, требующем примитивного значения, JavaScript сначала ищет метод valueOf
внутри объекта. В случаях, когда valueOf
либо отсутствует, либо не возвращает соответствующее значение, JavaScript возвращается к методу toString
. Он отвечает за предоставление строкового представления объекта.Возвращаясь к нашему исходному фрагменту кода:
const obj = {
valueOf: () => 42,
toString: () => 27
};
console.log(obj + '');
Когда мы запускаем этот код, объект
obj
преобразуется в примитивное значение. В этом случае метод valueOf
возвращает значение 42
, которое затем неявно преобразуется в строку из-за объединения с пустой строкой. Следовательно, на выходе код будет равен 42
.Однако в случаях, когда метод
valueOf
либо отсутствует, либо не возвращает соответствующее примитивное значение, JavaScript
возвращается к методу toString
. Давайте изменим наш предыдущий пример:const obj = {
toString: () => 27
};
console.log(obj + '');
Здесь мы удалили метод
valueOf
, оставив только метод toString
, который возвращает число 27
. В этом сценарии JavaScript прибегнет к методу toString
для преобразования объекта.❯ 6 – Понимание объектных ключей
При работе с объектами в JavaScript важно понимать, как обрабатываются и назначаются ключи в контексте других объектов. Рассмотрим следующий фрагмент кода и потратим некоторое время на то, чтобы угадать результат:
let a = {};
let b = { key: 'test' };
let c = { key: 'test' };
a[b] = '123';
a[c] = '456';
console.log(a);
На первый взгляд может показаться, что этот код должен создавать объект a с двумя различными парами ключей и значений. Однако результат совершенно иной из-за особенностей JavaScript.
JavaScript использует метод
toString()
по умолчанию для преобразования объектных ключей в строки. Но почему? В JavaScript объектные ключи всегда являются строками (или символами), или они автоматически преобразуются в строки с помощью неявного принуждения. Когда вы используете любое значение, отличное от строки (например, число, объект или символ), в качестве ключа в объекте, JavaScript внутренне преобразует это значение в его строковое представление, прежде чем использовать его в качестве ключа.Следовательно, когда мы используем объекты
b
и c
в качестве ключей в объекте a, оба преобразуются в одно и то же строковое представление: [object Object]
. Из-за такого поведения второе присвоение a[b] = '123';
перезапишет первое присвоение a[c] = '456';
(прим. переводчика: возможно, ошибка в оригинале: «Due to this behaviour, the second assignment, a[b] = '123'; will overwrite the first assignment a[c] = '456';» Но в коде все ровно наоборот, вторая запись a[c]='456' перезаписывает a[b]='123'). Давайте разберем код шаг за шагом:-
let a = {};
: Инициализирует пустой объектa
. -
let b = { key: 'test' };
: Создает объектb
с ключом свойства, имеющим значение'test'
. -
let c = { key: 'test' };
: Определяет другой объект c с той же структурой, что иb
. -
a[b] = '123';
: Присваивает значение'123'
свойству с ключом[object Object]
в объектеa
. -
a[c] = '456';
: Обновляет значение до'456'
для того же свойства с ключом[object Object]
в объекте a, заменяя предыдущее значение.
В обоих назначениях используется идентичная ключевая строка
[object Object]
. В результате второе присвоение перезаписывает значение, установленное первым присвоением.Когда мы регистрируем объект a, мы наблюдаем следующий вывод:
{ '[object Object]': '456' }
❯ 7 – Оператор двойного равенства
console.log([] == ![]);
Это немного сложно. Итак, как вы думаете, каков будет результат? Давайте рассмотрим шаг за шагом. Давайте сначала рассмотрим типы обоих операндов:
typeof([]) // "object"
typeof(![]) // "boolean"
[]
это объект, что ясно. Поскольку все в JavaScript является объектом, включая массивы и функции. Но почему операнд ![]
имеет тип boolean
? Давайте попробуем разобраться в этом. Когда вы используете! при использовании примитивного значения выполняются следующие преобразования:-
Ложные значения: Если исходное значение является ложным значением (например,
false
,0
,null
,undefined
,NaN
или пустая строка''
), применение!
преобразует его в значениеtrue
. -
Истинные значения: Если исходное значение является истинным значением (любое значение, которое не является ложным), применение
!
преобразует его в значениеfalse
.
В нашем случае
[]
— это пустой массив, который является истинным значением в JavaScript. Поскольку []
является истиной, ![]
становится ложью. Таким образом, наше выражение становится:[] == ![]
[] == false
Теперь давайте продвинемся вперед и разберемся с оператором
==
. Всякий раз, когда сравниваются 2 значения с использованием оператора ==
, JavaScript выполняет Алгоритм Сравнения Абстрактного Равенства. Алгоритм состоит из следующих шагов:Abstract Equality Comparison Algorithm
Как вы можете видеть, этот алгоритм учитывает типы сравниваемых значений и выполняет необходимые преобразования.
Для нашего случая давайте обозначим
x
как []
, а y как ![]
. Мы проверили типы x
и y
и обнаружили, что x
является объектом, а y
— boolean. Поскольку y является boolean, а x
— объектом, применяется условие 7 из алгоритма сравнения абстрактного равенства:Если Type(y) – Boolean, верни результат сравнения x == ToNumber(y).
Это означает, что если один из типов является логическим, нам нужно преобразовать его в число перед сравнением. Каково значение ToNumber(y)? Как мы видели,
[]
— это истинное значение, отрицание делает его false
. В результате Number(false)
равно 0
.[] == false
[] == Number(false)
[] == 0
Теперь у нас есть сравнение
[] == 0
, и на этот раз вступает в игру условие 8:Если Type(x) является String или Number, а Type(y) — Object, верни результат сравнения x == ToPrimitive(y).
Исходя из этого условия, если один из операндов является объектом, мы должны преобразовать его в примитивное значение. Вот тут-то и появляется алгоритм ToPrimitive. Нам нужно преобразовать
x
, который равен []
, в примитивное значение. Массивы — это объекты в JavaScript. Как мы видели ранее, при преобразовании объектов в примитивы в игру вступают методы valueOf
и toString
. В этом случае valueOf возвращает сам массив, который не является допустимым примитивным значением. В результате мы переходим к toString
для получения выходных данных. Применение метода toString
к пустому массиву приводит к получению пустой строки, которая является допустимым примитивом:[] == 0
[].toString() == 0
"" == 0
Преобразование пустого массива в строку дает нам пустую строку
""
и теперь мы сталкиваемся со сравнением: "" == 0
.Теперь, когда один из операндов имеет тип
string
, а другой — тип number
, выполняется условие 5:Если Type(x) — строка, а Type(y) — число, верни результат сравнения ToNumber(x) == y.
Следовательно, нам нужно преобразовать пустую строку
""
в число, которое дает нам 0
."" == 0
ToNumber("") == 0
0 == 0
Наконец, оба операнда имеют одинаковый тип, и выполняется условие 1. Поскольку оба имеют одинаковое значение, конечный результат равен:
0 == 0 // true
До сих пор мы использовали принуждение, что является важной концепцией при освоении JavaScript и решении подобных вопросов в интервью, которые, как правило, задают часто. Я действительно рекомендую вам ознакомиться с моим подробным постом в блоге о принуждении. В нем ясно и досконально объясняется эта концепция. Вот ссылка.
❯ 8 – Замыкания
Это один из самых известных вопросов, задаваемых в интервью, связанных с замыканиями:
const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log('Index: ' + i + ', element: ' + arr[i]);
}, 3000);
}
Если вы знаете результат, то это хорошо. Итак, давайте попробуем разобраться в этом фрагменте. На первый взгляд, результат будет таким:
Index: 0, element: 10
Index: 1, element: 12
Index: 2, element: 15
Index: 3, element: 21
Но здесь дело обстоит иначе. Из-за концепции замыканий и того, как JavaScript обрабатывает область видимости переменной, фактический вывод будет другим. Когда обратные вызовы
setTimeout
выполняются после задержки в 3000 миллисекунд, все они будут ссылаться на одну и ту же переменную i, которая будет иметь конечное значение 4
после завершения цикла. В результате вывод кода будет следующим:Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
Index: 4, element: undefined
Такое поведение возникает из-за того, что ключевое слово var не обладает видимостью блока, а обратные вызовы setTimeout фиксируют ссылку на ту же переменную i. Когда выполняются обратные вызовы, все они видят конечное значение
i
, равное 4
, и пытаются получить доступ к arr[4]
, которое undefined
.Чтобы достичь желаемого результата, вы можете использовать ключевое слово let для создания новой области видимости для каждой итерации цикла, гарантируя, что каждый обратный вызов фиксирует правильное значение
i
:const arr = [10, 12, 15, 21];
for (let i = 0; i < arr.length; i++) {
setTimeout(function() {
console.log('Index: ' + i + ', element: ' + arr[i]);
}, 3000);
}
С помощью этой модификации вы получите ожидаемый результат:
Index: 0, element: 10
Index: 1, element: 12
Index: 2, element: 15
Index: 3, element: 21
Использование
let
создает новую привязку для i
на каждой итерации, гарантируя, что каждый обратный вызов ссылается на правильное значение.Часто разработчики знакомятся с решением, использующим ключевое слово
let
. Однако собеседования иногда могут пойти еще дальше и предложить вам решить проблему без использования let
. В таких случаях альтернативный подход предполагает создание замыкания путем немедленного вызова функции (IIFE – Immediately Invoking Function Expression) внутри цикла. Таким образом, каждый вызов функции имеет свою собственную копию i
. Вот как вы можете это сделать:const arr = [10, 12, 15, 21];
for (var i = 0; i < arr.length; i++) {
(function(index) {
setTimeout(function() {
console.log('Index: ' + index + ', element: ' + arr[index]);
}, 3000);
})(i);
}
В этом коде немедленно вызываемая функция
(function(index) { ... })(i);
создает новую область видимости для каждой итерации, захватывая текущее значение i
и передавая его в качестве параметра index
. Это гарантирует, что каждая функция обратного вызова получит свое собственное отдельное значение index, предотвращая проблему, связанную с закрытием, и предоставляя вам ожидаемый результат:Index: 0, element: 10
Index: 1, element: 12
Index: 2, element: 15
Index: 3, element: 21
Спасибо вам за чтение. Я надеюсь, что этот пост будет полезен вам в процессе подготовки к собеседованию.
Возможно, захочется почитать и это:
- ➤ JavaScript: разрабатываем приложение для записи звука
- ➤ JavaScript: заметка о requestAnimationFrame и requestIdleCallback
- ➤ Эти кристаллы доживают последние деньки — почему мощные процессоры и видеокарты середины нулевых умирают?
- ➤ Как создать API в облаке менее чем в 200 строках кода
- ➤ Хотели сделать Alan Wake 2, а вышло…
Комментарии (35)
Cere8ellum
25.10.2023 15:28+3Статья конечно интересная. Но уровень Senior...? А джун тогда кто?
Frevv
25.10.2023 15:28-1Джун то же самое только без опыта. И может ещё сказать "не знаю" на некоторые вопросы. А вот кто давно работает не может сказать не знаю", вот и вся разница на собеседование, плюс он должен показать портфолио.
SergTsumbal
25.10.2023 15:28Без опыта это трейни, джун как раз должен знать подобные тонкости. Сеньор их просто уже не помнит
YegorP
25.10.2023 15:28+16Чему равно
[] == ![]
?Либо я угадаю и мои тесты пройдут; либо не угадаю и тесты обвалятся, и я тут же поправлю. Если вообще когда-нибудь напишу такое. А если напишет кто-то другой, то на ревью его заверну. Вот и всё сеньорство.
meet2code
25.10.2023 15:28+4Ну вот, теперь новоиспечённые интервьюеры понесут дальше в массы эти свежие и интересные задачи, вместо нормальной подготовки к собеседованию.
yerzintimur
25.10.2023 15:28+4Наличие таких вопросов на собесе, это сразу звоночек. Ну а те, кто реально умеют проводить собеседования, конечно не понесут такое к себе
meet2code
25.10.2023 15:28+2В том и проблема, что хабр имеет авторитет при поиске информации.
Т.е. в кейсе, когда начинающий интервьюер будет собирать пул задач, он примет эти советы как актуальные.
Про звоночек согласен. Вероятность сильно повышается, что технологии и процессы в команде такие же актуальные как и вопросы :)
den_rad
25.10.2023 15:28+2Помню первое собеседование, интервьювер задавал кучу вопросов, вроде "что будет если написать fn(--i++), на что я ему ответил что если такой код напишу в проекте, мне нужно по рукам бить. Даже прошел собеседование )
meet2code
25.10.2023 15:28Ну тут не угадать, задают тебе вопрос на проверку адекватности и рассуждений или слепо следуют советам аналогичных сухих статей.
Просто статья в контексте собеседования, а не только про особенности работы JS. Хорошо бы какой-то пример привести из реальности в каждом пункте.
В целом, с начинающим разработчиком может быть интересно порассуждать на такие темы, но интервьюеру нужно чётко понимать для чего и как задавать вопросы и каких ответов ждать.
alexerisov
25.10.2023 15:28+4Когда уже люди поймут, что это вопросы просто на знание принципов работы языка, и это не значит, что это нужно писать в реальном проекте. Точно также, как решения и победы в спортивном программирование почти всегда не будут иметь общее с реальным кодом коммерчески продуктов. Но победитель олимпиад, как минимум не плохо будет разбираться в принципа работы языков, математике, структурах данных.
Ну и надо понимать, что разным компаниям нужны разные кадры. Для вебстудии заказной разработки может быть вообще достаточно человека с сугубо прикладными навыками составления простых реакт компонентов. Заказы сдаются, зарплата платится, все счастливы.
ImagineTables
25.10.2023 15:28+4console.log(1 + '1' - 1);
Можете ли вы угадать поведение операторов + и — в ситуациях, подобных описанной выше?А теперь правильный ответ: если я увижу такое в коде, посмотрю, кто его наложил, и напишу менеджеру злое письмо.
Ещё более правильный ответ: выбирая между диалектами EcmaScript (а у меня, слава богу, есть такая возможность для своей браузерной сборки), я выберу тот, который выкинет исключение вместо имплиситных конверсий. Нестандартный диалект это, конечно, не очень хорошо, но надёжность того стоит.
surarus
25.10.2023 15:28+3В отличии от джуна, сеньор на такую чепуху наверное и не ответит, но по факту сделает в миллион раз больше продуктовых задач и проектов от 0 до production.
Ужас любой компании когда к ним приходят теоретики, с SOLID(упоротыми) заветами и вопросами на собесе подобно данной статьи.
Истинный сеньор шлет всех подальше на первом примере console.log(1 + '1' - 1);
i360u
25.10.2023 15:28+6Если на позицию сеньора вам задают подобные вопросы - разворачивайтесь и уходите. По вопросам на собеседовании можно многое понять о адекватности собеседующего и о общей культуре разработки в компании. Такие вопросы - это сразу красный флаг.
funca
25.10.2023 15:28+2Мне кажется это не для синьеров, а для грандов). Весь пост пронизан тем самым теплым ламповым джаваскриптом - без strict modе, let/const, arrow functions, async/await и статического код анализа. Эх, где ты мой 2003?
Boilerplate
25.10.2023 15:28+3Во втором вопросе не только вопрос туп, так еще и ответ неверный. Функция duplicate(arr) кроме того, что создаёт новый массив, еще и меняет старый... Бред какой-то, если честно
aleksandy
25.10.2023 15:28+1А где там создаётся новый массив? Метод возвращает изменённый переданный массив.
Boilerplate
25.10.2023 15:28+1Ну по ТЗ у них было создание: "В этом фрагменте кода нам требуется создать новый массив с дублированными элементами. На первым взгляд, код создает новый массив
newArr
путем дублирования каждого элемента из исходного массиваarr
. "Другое дело, что они по ссылке меняли объект, в общем функция не делает то, что нужно и делает то, что не нужно. Причём как исходная, так и полученная...
Pest85
25.10.2023 15:28Мдя. Человек который собеседует либо пытается узнать что ты знаешь чтобы понять как это применить в проекте, либо показать как много он знает по сравнению с тобой.
Здесь явно второй вариант. Хуже чем собесевование с таким человеком может быть только работа с ним\ней.
exchange12rocks
25.10.2023 15:28+1Настоящий сеньор глядя на такое говорит, что так просто делать не надо - код должен быть явным. А там, где по какой-то причине неявное поведение надо, должен быть понятный комментарий, описывающий что и почему.
Andy_Francev
25.10.2023 15:28+3Простите, но что за срань-то? Сейчас, в свете популярности TypeScript ответ на вопрос:
что выведется в "1 + '1' - 1"
будет однозначный:
TS2362: The left-hand side of an arithmetic operation must be of type any , number , bigint or an enum type.
souls_arch
25.10.2023 15:28+2Вот так, благодаря автору статьи, я сразу стал сиьнором JS, хотя я даже джуном JS никогда не был, но с JS немного знаком.
pavelsc
25.10.2023 15:28-1уже по наличию var и хренотятине в duplicate, в результате которой новый массив так и не получили, я понял, что статью выдавил из себя июнь или трейни, и дальше чисто до комментов долистал )
VasiliyMakogon
25.10.2023 15:28❯ 7 – Оператор двойного равенства
Какой же это ужас. Почему до сих пор никто не озадачился создать внятный и интуитивно понятный JS какой-нибудь "второй версии" без всей этой мозговыносящей дряни? Это же какое-то хождение по мукам: интуитивно не понятно, сложно. Ради чего всё это?
Вот в контексте языка PHP:
<?php var_dump([] == ![]); // false
тут не нужен рассказ на лист А4, тут достаточно знания, что пустой массив, приводимый к типу bool является false.
В 21 веке язык программирования должен позволять быстро решать задачи, а не быть сам по себе задачей.
Leetc0deM0nkey
25.10.2023 15:28+1Отличие сеньйора от джуна в том что сеньйор скажет что это срань собачья и в реальной разработке использовать такое нельзя. Но если очень хочется позаниматься ментальной гимнастикой, всегда можно просто открыть мануалы и разобраться что на самом деле произойдёт. Джун же считает что это сакральные знания, которые отличают айти помазанных от черни.
fathergorry
25.10.2023 15:28+2Спасибо, никогда не поздно напомнить, что js - это ад на земле, но альтернатив нету. Добавлю свой пример, который стоил мне двух дней дебага : оказывается в for(var i in []) i - это строка. То, что во всех других циклах - число и в этом контексте не может быть ничем иным кроме числа, внутри такого цикла даётся как строка.
JordanCpp
25.10.2023 15:28Всё же софт в большей части состоит не из такого шаманского и узкоспециализированного кода. Знать наверное приятно, такие мелочи добавленные из за несовершенства языка и недальновидностью создаелей этого языка. Но всё же для программиста в первую очередь, без деления на касты требуется знать архитектурные паттерны, алгоритмы, подходы и т.д
Если такими вопросами опеределяют сеньера, это забавно.
Rusty_Fox
Опять квизы под вопросы замаскировали. Ну, такое. На любителя.