Skip to main content

Вопросы по JavaScript. Версия 1

Каким будет вывод?

Вопрос № 1

function sayHi() {
console.log(name)
console.log(age)
var name = "John"
let age = 30
}

sayHi()
  • A: John и undefined
  • B: John и ошибка
  • C: ошибка
  • D: undefined и ошибка
Ответ

Правильный ответ: D

В функции sayHi мы сначала определяем переменную name с помощью ключевого слова var. Это означает, что name поднимается в начало функции. name будет иметь значение undefined до тех пор, пока выполнение кода не дойдет до строки, где ей присваивается значение John. Мы еще не определили значение name, когда пытаемся вывести ее значение в консоль, поэтому получаем undefined. Переменные, объявленные с помощью ключевых слов let и const, также поднимаются в начало области видимости, но в отличие от переменных, объявленных с помощью var, не инициализируются, т.е. такие переменные поднимаются без значения. Доступ к ним до инициализации невозможен. Это называется временной мертвой зоной. Когда мы пытаемся обратиться к переменным до их определения, JavaScript выбрасывает исключение ReferenceError.

Вопрос № 2

for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)
}

for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1)
}
  • A: 0 1 2 и 0 1 2
  • B: 0 1 2 и 3 3 3
  • C: 3 3 3 и 0 1 2
  • D: 3 3 3 и 3 3 3
Ответ

Правильный ответ: C

Из-за очереди событий в JavaScript функция обратного вызова setTimeout выполняется после освобождения стека вызовов. Так как переменная i в первом цикле определяется с помощью ключевого слова var, она является глобальной. В цикле мы каждый раз увеличиваем значение i на 1, используя оператор ++. К моменту выполнения setTimeout в первом примере значение i равняется 3. Во втором цикле переменная i определяется с помощью ключевого слова let. Такие переменные (а также переменные, объявленные с помощью ключевого слова const) имеют блочную область видимости (блок - это код внутри фигурных скобок - {}). На каждой итерации i будет иметь новое значение, и это значение будет замкнуто в области видимости внутри цикла.

Вопрос № 3

const shape = {
radius: 10,
diameter() {
return this.radius * 2
},
perimeter: () => 2 * Math.PI * this.radius
}

console.log(shape.diameter())
console.log(shape.perimeter())
  • A: 20 и 62.83185307179586
  • B: 20 и NaN
  • C: 20 и 63
  • D: NaN и 63
Ответ

Правильный ответ: B

Обратите внимание, что diameter - это обычная функция, а perimeter - стрелочная. У стрелочных функций, в отличие от обычных, значение this указывает на внешнее/лексическое окружение. Это значит, что при вызове метода perimeter его this указывает не на объект shape, а на глобальный объект window. У этого объекта нет свойства radius, поэтому возвращается undefined.

Вопрос № 4

console.log(+true)
console.log(!"John")
  • A: 1 и false
  • B: 0 и true
  • C: false и NaN
  • D: false и false
Ответ

Правильный ответ: A

Унарный плюс (+) приводит операнд к числу. true - это 1, а false - 0. Строка John - это истинное значение. Мы спрашиваем, является ли это значение ложным? Ответ: false.

Вопрос № 5

let c = { greeting: "Hey!" }
let d

d = c
c.greeting = "Hello!"
console.log(d.greeting)
  • A: Hello!
  • B: Hey!
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: A

В JavaScript все объекты являются "ссылочными" типами данных, т.е. значения объектов передаются по ссылкам. Сначала в переменной c создается ссылка на объект. Затем мы указываем переменной d ссылаться на тот же объект, на который ссылается c. При изменении объекта меняются значения всех указывающих на него ссылок.

Вопрос № 6

let a = 3
let b = new Number(3)
let c = 3

console.log(a == b)
console.log(a === b)
console.log(b === c)
  • A: true false true
  • B: false false true
  • C: true false false
  • D: false true true
Ответ

Правильный ответ: C

new Number - это встроенная функция-конструктор. И хотя она выглядит как число, это не настоящее число: у него имеется ряд дополнительных возможностей. На самом деле это объект. Оператор == (абстрактное/нестрогое равенство) разрешает преобразование типов данных, он проверяет равенство значений. Оба значения равны 3, поэтому возвращается true. При использовании оператора === (строговое равенство, оператор идентичности) должны совпадать не только значения, но и типы данных. В данном случае это не так: new Number() - это не число, а объект. Поэтому два последних сравнения возвращают false.

Вопрос № 7

class Chameleon {
static colorChange(newColor) {
this.newColor = newColor
return this.newColor
}

constructor({ newColor = "green" } = {}) {
this.newColor = newColor
}
}

const freddie = new Chameleon({ newColor: "pink" })
freddie.colorChange("orange")
  • A: orange
  • B: pink
  • C: green
  • D: ошибка
Ответ

Правильный ответ: D

Метод colorChange является статическим. Такие методы не имеют доступа к экземплярам класса. Так как freddie - это экземпляр, статический метод в нем не доступен. Поэтому выбрасывается исключение TypeError.

Вопрос № 8

// обратите внимание: код выполняется в нестрогом режиме
let greeting
greetign = {} // опечатка!
console.log(greetign)
  • A:
  • B: ошибка
  • C: undefined
  • D: ""
Ответ

Правильный ответ: A

С помощью выражения greetign = {} мы создаем новый глобальный пустой объект, который выводится в консоль. Когда мы вместо greeting написали greetign, интерпретатор выполнил global.greetign = {} в Node.js (или window.greetign = {} в браузере). В строгом режиме ("use strict") будет выброшено исключение ReferenceError: greetign is not defined.

Вопрос № 9

function bark() {
console.log("Woof!")
}

bark.animal = "dog"

console.log(bark.animal)
  • A: dog
  • B: ошибка
  • C: undefined
  • D: ""
Ответ

Правильный ответ: A

В JavaScript такое возможно, т.к. функции в JS - это тоже объекты. Точнее, функция — это специальный тип объекта, который можно вызывать (такой объект имеет внутренний слот callable). Кроме того, функция — это объект со свойствами, вызывать которые нельзя, поскольку они не являются функциями.

Вопрос № 10

function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}

const person = new Person("John", "Smith")
Person.getFullName = function () {
return `${this.firstName} ${this.lastName}`
}

console.log(person.getFullName())
  • A: ошибка
  • B: ""
  • C: John Smith
  • D: undefined undefined
Ответ

Правильный ответ: A

Нельзя добавлять свойства к конструктору как к обычному объекту. Если необходимо добавить свойство или метод всем экземплярам, то следует использовать прототипы. В данном случае выражение Person.prototype.getFullName = function () { return ${this.firstName} ${this.lastName} } сделает метод getFullName рабочим. В чем здесь преимущество? Предположим, что мы добавили этот метод к конструктору. Возможно, он нужен не каждому экземпляру класса Person. Это приведет к лишнему расходованию памяти, т.к. все экземпляры будут иметь указанный метод. Напротив, если мы добавим данный метод к прототипу, у нас будет только одно место в памяти, к которому смогут обращаться все экземпляры. Такие методы называются совместными или распределенными (shared).

Вопрос № 11

function Person(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}

const john = new Person("John", "Smith")
const jane = Person("Jane", "Air")

console.log(john)
console.log(jane)
  • A: Person {firstName: "John", lastName: "Smith"} и undefined
  • B: Person {firstName: "John", lastName: "Smith"} и Person {firstName: "Jane", lastName: "Air"}
  • C: Person {firstName: "John", lastName: "Smith"} и {}
  • D: Person {firstName: "Smith", lastName: "Smith"} и ошибка
Ответ

Правильный ответ: A

Мы создаем объект jane без помощи ключевого слова new. Использование new приводит к созданию нового объекта (экземпляра). Без new создается глобальный объект. Мы указали, что this.firstName равняется Jane и this.lastName равняется Air. На самом деле, мы определили global.firstName = 'Jane' и global.lastName = 'Air'. Значением jane является undefined, поскольку мы ничего не возвращаем из функции Person.

Вопрос № 12

function sum(a, b) {
return a + b
}

console.log(sum(1, "2"))
  • A: NaN
  • B: ошибка
  • C: "12"
  • D: 3
Ответ

Правильный ответ: C

JavaScript - это динамически типизированный язык: мы не определяем тип данных при объявлении переменных (для этого был придуман TypeScript). Значения переменных могут быть автоматически преобразованы из одного типа в другой без нашего участия. Это называется "неявным приведением типов". Приведение - это преобразование данных из одного типа в другой. В рассматриваемом примере JavaScript конвертировал число 1 в строку, чтобы операция имела смысл и вернула хоть какое-то значение. При сложении числа (1) и строки ("2") число преобразуется в строку. Мы можем объединять строки так: "Hello" + "World". Это называется конкатенацией строк. Таким образом, 1 + "2" возвращает "12".

Вопрос № 13

let number = 0
console.log(number++)
console.log(++number)
console.log(number)
  • A: 1 1 2
  • B: 1 2 2
  • C: 0 2 2
  • D: 0 1 2
Ответ

Правильный ответ: C

Постфиксный оператор ++:

  • возвращает значение (0);
  • увеличивает (инкрементирует) значение (после чего значением переменной number становится 1). Префиксный оператор ++:
  • инкрементирует значение (теперь number === 2);
  • возвращает значение (2). Результат: 0 2 2.

Вопрос № 14

function getPersonInfo(one, two, three) {
console.log(one)
console.log(two)
console.log(three)
}

const person = "John"
const age = 30

getPersonInfo`${person} is ${age} years old`
  • A: John 30 ["", " is ", " years old"]
  • B: ["", " is ", " years old"] John 30
  • C: John ["", " is ", " years old"] 30
  • D: undefined
Ответ

Правильный ответ: B

При использовании тегированных шаблонных литералов (tagged template literals) первым значением, возвращаемым функцией, является массив строк. Прочими значениями являются значения, переданные функции в качестве аргументов.

Вопрос № 15

function checkAge(data) {
if (data === { age: 18 }) {
console.log("Ты взрослый!")
} else if (data == { age: 18 }) {
console.log("Ты по-прежнему взрослый.")
} else {
console.log("Хм... У тебя что, нет возраста?")
}
}

checkAge({ age: 18 })
  • A: Ты взрослый!
  • B: Ты по-прежнему взрослый.
  • C: Хм... У тебя что, нет возраста?
  • D: undefined
Ответ

Правильный ответ: C

В операциях сравнения примитивы сравниваются по значениям, а объекты - по ссылкам. JavaScript проверяет, чтобы объекты указывали на одну и ту же область памяти. Сравниваемые объекты в рассматриваемом примере не такие: объект, переданный в качестве аргумента, указывает на другое место в памяти, нежели объекты, используемые в сравнениях. Поэтому выражения { age: 18 } === { age: 18 } и { age: 18 } == { age: 18 } возвращают false.

Вопрос № 16

function getAge(...args) {
console.log(typeof args)
}

getAge(30)
  • A: number
  • B: array
  • C: object
  • D: NaN
Ответ

Правильный ответ: C

Оператор распространения или расширения (spread, ...) возвращает массив с аргументами, переданными функции. Массив - это объект, поэтому выражение typeof args возвращает object.

Вопрос № 17

function getAge() {
"use strict"
age = 30
console.log(age)
}

getAge()
  • A: 30
  • B: undefined
  • C: ошибка
  • D: NaN
Ответ

Правильный ответ: C

"use strict", среди прочего, позволяет предотвратить случайное объявление глобальных переменных. Мы не объявляли переменную age, поэтому (в строгом режиме) выбрасывается исключение ReferenceError. В нестрогом режиме ошибки не возникнет, а переменная age станет свойством глобального объекта window.

Вопрос № 18

const sum = eval("10*10+5")

console.log(sum)
  • A: 105
  • B: "105"
  • C: ошибка
  • D: "10*10+5"
Ответ

Правильный ответ: A

Функция eval выполняет код, переданный ей в виде строки. Если это выражение (как в данном случае), то оно вычисляется (оценивается). Выражение 10 * 10 + 5 возвращает число 105. Использовать eval не рекомендуется по причинам безопасности.

Вопрос № 19

var num = 8
var num = 10

console.log(num)
  • A: 8
  • B: 10
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: B

С помощью ключевого слова var можно определять любое количество одноименных переменных. Переменная будет хранить последнее присвоенное ей значение. Однако, такой трюк нельзя проделать с let и const, т.к. переменные, объявленные с помощью этих ключевых слов, имеют блочную область видимости.

Вопрос № 20

const obj = { 1: "a", 2: "b", 3: "c" }
const set = new Set([1, 2, 3, 4, 5])

console.log(obj.hasOwnProperty("1"))
console.log(obj.hasOwnProperty(1))
console.log(set.has("1"))
console.log(set.has(1))
  • A: false true false true
  • B: false true true true
  • C: true true false true
  • D: true true true true
Ответ

Правильный ответ: C

Ключи объектов (кроме Symbol) являются строками, даже если заданы не в виде строк (например, индексы в массиве). Поэтому выражение obj.hasOwnProperty('1') также возвращает true. Однако, это не работает с Set. Значение 1 отсутствует в set: set.has('1') возвращает false, а set.has(1) - true.

Вопрос № 21

const obj = { a: "one", b: "two", a: "three" }
console.log(obj)
  • A: { a: "one", b: "two" }
  • B: { b: "two", a: "three" }
  • C: { a: "three", b: "two" }
  • D: ошибка
Ответ

Правильный ответ: C

Если в объекте имеется два ключа с одинаковыми именами, то первый ключ перезаписывается. Его позиция сохраняется, а значением становится последнее из присвоенных.

Вопрос № 22

for (let i = 1; i < 5; i++) {
if (i === 3) continue
console.log(i)
}
  • A: 1 2
  • B: 1 2 3
  • C: 1 2 4
  • D: 1 3 4
Ответ

Правильный ответ: C

Оператор continue пропускает текущую итерацию (цикл), если условие удовлетворяется (является истинным).

Вопрос № 23

String.prototype.giveMePizza = () => {
return "Give me pizza!"
}

const name = "John"

console.log(name.giveMePizza())
  • A: Give me pizza!
  • B: ошибка
  • C: ""
  • D: undefined
Ответ

Правильный ответ: A

String - это встроенный конструктор, к которому можно добавлять новые свойства. Мы добавили метод giveMePizza к его прототипу. Строки-примитивы автоматически конвертируются (преобразуются) в строки-объекты (благодаря объектной обертке). Поэтому все строки (объекты) имеют доступ к указанному методу.

Вопрос № 24

const a = {}
const b = { key: "b" }
const c = { key: "c" }

a[b] = 123
a[c] = 456

console.log(a[b])
  • A: 123
  • B: 456
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: B

Ключи объекта (кроме Symbol) автоматически преобразуются в строки (даже индексы в массиве). Мы пытаемся добавить объект в качестве ключа со значением 123 к объекту a. Однако, когда мы приводим объект к строке, он превращается в [object Object]. Таким образом, мы говорим, что a["object Object"] = 123. Затем мы повторяем процедуру. c - это другой объект, который мы также неявно приводим к строке. Поэтому a["object Object"] = 456. Наконец, когда мы выводим a[b] в консоль, мы на самом деле обращаемся к a["object Object"]. Поэтому в консоль выводится 456.

Вопрос № 25

const foo = () => console.log("first")
const bar = () => setTimeout(() => console.log("second"))
const baz = () => console.log("third")

bar()
foo()
baz()
  • A: first second third
  • B: first third second
  • C: second first third
  • D: second third first
Ответ

Правильный ответ: B

Сначала мы вызываем функцию setTimeout. Однако, ее колбек выполняется последним. Это происходит из-за того, что в браузерах у нас имеется не только движок для запуска (выполнения) кода, но и WebAPI. WebAPI предоставляет нам setTimeout и много других возможностей, например, DOM. После того, как setTimeout отправляется в WebAPI, функция bar удаляется из стека вызовов (call stack). После этого вызывается функция foo, и first выводится в консоль. foo удаляется из стека и вызывается функция baz. third выводится в консоль. WebAPI отправляет функцию обратного вызова setTimeout в очередь событий (task queue, второе слово читается как "кью"). Цикл событий (event loop) проверяет стек вызовов и очередь задач. Если стек оказывается пустым, то в него помещается первый элемент из очереди. Вызывается функция bar и в консоль выводится second.

Вопрос № 26

<div onclick="console.log('div')">
<p onclick="console.log('p')">
Нажми меня!
</p>
</div>
  • A: p div
  • B: div p
  • C: p
  • D: div
Ответ

Правильный ответ: A

После клика по элементу p в консоль будет выведено p и div. Поток события (распространение события) имеет три фазы: захват, цель и всплытие. По умолчанию обработчики событий выполняются на фазе всплытия (если не установлен параметр useCapture со значением true). Всплытие происходит от самого глубоко вложенного элемента до самого внешнего.

Вопрос № 27

const person = { name: "John" }

function sayHi(age) {
console.log(`${this.name} is ${age}`)
}

sayHi.call(person, 30)
sayHi.bind(person, 30)
  • A: undefined is 30 и John is 30
  • B: function и function
  • C: John is 30 и John is 30
  • D: John is 30 и function
Ответ

Правильный ответ: D

В обоих случаях мы передаем объект, на который будет указывать this. Но метод call выполняется сразу, а метод bind возвращает копию функции с привязанным контекстом. Эту функцию следует вызывать отдельно или можно сделать так: sayHi.bind(person, 30)().

Вопрос № 28

function sayHi() {
return (() => 0)()
}

console.log(typeof sayHi())
  • A: object
  • B: number
  • C: function
  • D: undefined
Ответ

Правильный ответ: B

Функция sayHi возвращает значение немедленно вызываемого функционального выражения (Immediately Invoked Function Expression, IIFE). Результатом является число 0 типа number. Для информации: в JavaScript имеется 8 встроенных типов данных: string, number, bigint, boolean, null, undefined, object и symbol. function не является отдельным типом, функции - это объекты.

Вопрос № 29

console.log(typeof typeof 1)
  • A: number
  • B: string
  • C: object
  • D: undefined
Ответ

Правильный ответ: B

Выражение typeof 1 возвращает number. Выражение typeof number возвращает string.

Вопрос № 30

const numbers = [1, 2, 3]
numbers[10] = 11
console.log(numbers)
  • A: [1, 2, 3, 7 x null, 11]
  • B: [1, 2, 3, 11]
  • C: [1, 2, 3, 7 x empty, 11]
  • D: ошибка
Ответ

Правильный ответ: C

Когда в массив добавляется значение, которое выходит за пределы длины массива, JavaScript создает "пустые ячейки". На самом деле они имеют значение undefined, но в консоль выводятся как [1, 2, 3, 7 x empty, 11] (зависит от среды выполнения кода, от браузера).

Вопрос № 31

(() => {
let x, y
try {
throw new Error()
} catch (x) {
(x = 1), (y = 2)
console.log(x)
}
console.log(x)
console.log(y)
})()
  • A: 1 undefined 2
  • B: undefined undefined undefined
  • C: 1 1 2
  • D: 1 undefined undefined
Ответ

Правильный ответ: A

Блок catch принимает параметр x. Это не тот x, который объявлен перед блоком try. Мы присваиваем этому аргументу значение 1, а переменной y - 2. После этого мы выводим в консоль значение x, т.е. 1. За пределами catch x все еще имеет значение undefined, а y - 2. Когда мы вызываем console.log(x) за пределами catch, возвращается undefined, а console.log(y) возвращает 2.

Вопрос № 32

const result =
[[0, 1], [2, 3]].reduce(
(acc, cur) => {
return acc.concat(cur)
},
[1, 2]
)

console.log(result)
  • A: [0, 1, 2, 3, 1, 2]
  • B: [6, 1, 2]
  • C: [1, 2, 0, 1, 2, 3]
  • D: [1, 2, 6]
Ответ

Правильный ответ: C

[1, 2] - начальное значение переменной acc. После первого прохода acc равняется [1, 2], а cur - [0, 1]. После конкатенации (объединения) acc равняется [1, 2, 0, 1], а cur - [2, 3]. После их объединения, мы получаем [1, 2, 0, 1, 2, 3].

Вопрос № 33

console.log(!!null)
console.log(!!"")
console.log(!!1)
  • A: false true false
  • B: false false true
  • C: false true true
  • D: true true false
Ответ

Правильный ответ: B

null - это false. !null возвращает true. !true возвращает false. "" - это false. !"" возвращает true. !true возвращает false. 1 - это true. !1 возвращает false. !false возвращает true.

Вопрос № 34

console.log([..."John"])
  • A: ["J", "o", "h", "n"]
  • B: ["John"]
  • C: [[], "John"]
  • D: [["J", "o", "h", "n"]]
Ответ

Правильный ответ: A

Строка является итерируемой (перебираемой) сущностью. Оператор распространения или расширения (spread, ...) преобразует строку в массив, состоящий из символов этой строки.

Вопрос № 35

function* generator(i) {
yield i
yield i * 2
}

const gen = generator(10)

console.log(gen.next().value)
console.log(gen.next().value)
  • A: [0, 10] и [10, 20]
  • B: 20 и 20
  • C: 10 и 20
  • D: 0, 10 и 10, 20
Ответ

Правильный ответ: C

Выполнение обычных функций не может быть остановлено после их запуска. Однако, генераторы можно останавливать в процессе выполнения, а затем продолжать с места остановки. Каждый раз, когда в функции-генераторе встречается ключевое слово yield, функция возвращает значение, указанное после него. Обратите внимание, что в генераторе вместо return используется yield. Сначала мы инициализируем генератор с i равным 10. Мы вызываем генератор, используя метод next. Когда мы в первый раз вызываем генератор, i равняется 10. Движок JavaScript встречает первое ключевое слово yield и возвращает значение i. После этого выполнение функции приостанавливается и 10 выводится в консоль. Затем мы снова вызываем функцию посредством next(). Она запускается с того места, где остановилась, с i равным 10. Движок встречает следующее ключевое слово yield и возвращает i * 2. i равно 10, поэтому возвращается 20.

Вопрос № 36

const firstPromise = new Promise((res, rej) => {
setTimeout(res, 500, "one")
})

const secondPromise = new Promise((res, rej) => {
setTimeout(res, 100, "two")
})

Promise.race([firstPromise, secondPromise]).then(res => console.log(res))
  • A: one
  • B: two
  • C: two one
  • D: one two
Ответ

Правильный ответ: B

Когда мы передаем несколько промисов методу race, он возвращает первый разрешенный (выполненный или отклоненный) промис. В функцию setTimeout мы передаем задержку в 500 мс для первого промиса и в 100 мс - для второго. Это означает, что secondPromise разрешается первым со значением two. Переменная res имеет значение two, которое и выводится в консоль.

Вопрос № 37

let person = { name: "John" }
const members = [person]
person = null

console.log(members)
  • A: null
  • B: [null]
  • C: [{}]
  • D: [{ name: "John" }]
Ответ

Правильный ответ: D

Сначала мы объявляем переменную person со значением объекта, содержащего свойство name. Затем мы объявляем переменную members. Мы делаем первый элемент этого массива равным [person]. Объекты взаимодействуют посредством ссылок при установке их равными друг другу. Когда мы назначаем ссылку из одной переменной в другую, создается копия этой ссылки (обратите внимание, что у этих переменных не одинаковые ссылки). Затем мы присваиваем переменной person значение null. Мы изменили только значение person, а не первый элемент массива, поскольку этот элемент имеет другую (скопированную) ссылку на объект. Первый элемент в members по-прежнему содержит ссылку на исходный объект. Когда мы выводим в консоль массив members, первый элемент этого массива содержит значение объекта, который и выводится в консоль.

Вопрос № 38

const person = {
name: "John",
age: 30
}

for (const item in person) {
console.log(item)
}
  • A: { name: "John" } и { age: 30 }
  • B: name и age
  • C: John и 30
  • D: ["name", "John"] и ["age", 30]
Ответ

Правильный ответ: B

С помощью цикла for..in мы перебираем ключи объекта, в данном случае name и age. Ключи объекта (кроме Symbol) являются строками. В каждом цикле мы устанавливаем значение item равным текущему ключу, по которому он перебирается. Сначала item равен name, и выводится в консоль. Затем item равен age, что также выводится в консоль.

Вопрос № 39

console.log(3 + 4 + "5")
  • A: "345"
  • B: "75"
  • C: 12
  • D: "12"
Ответ

Правильный ответ: B

Ассоциативность операторов - это порядок оценивания выражения движком JavaScript, слева направо или справа налево. Это происходит только в том случае, если все операторы имеют одинаковый приоритет. У нас есть только один тип оператора: +. Ассоциативность - слева направо. 3 + 4 оценивается первым. Это приводит к числу 7. 7 + "5" приводит к "75" из-за неявного приведения типов. JavaScript преобразует число 7 в строку. Мы можем объединять (конкатенировать) две строки с помощью оператор +. Выражение '7' + '5' возвращает 75.

Вопрос № 40

const num = parseInt("7*6", 10)

console.log(num)
  • A: 42
  • B: "42"
  • C: 7
  • D: NaN
Ответ

Правильный ответ: C

Функция parseInt проверяет, являются ли символы в строке допустимыми с точки зрения используемой системы счисления (второй необязательный аргумент). Как только встречается недопустимый символ, синтаксический анализ строки прекращается и последующие символы игнорируются. * является недопустимым числом. Поэтому parseInt прекращает разбор строки и возвращает 7.

Вопрос № 41

const result =
[1, 2, 3].map(num => {
if (typeof num === "number") return
return num * 2
})

console.log(result)
  • A: []
  • B: [null, null, null]
  • C: [undefined, undefined, undefined]
  • D: [ 3 x empty ]
Ответ

Правильный ответ: C

Метод map возвращает новый массив с обработанными с помощью функции обратного вызова элементами исходного массива. В данном случае элементы исходного массива являются числами, поэтому условие if typeof num === 'number' удовлетворяется. После этого выполнение функции останавливается, в новый массив попадает значение переменной num, равное undefined.

Вопрос № 42

function greeting() {
throw "Всем привет!"
}

function sayHi() {
try {
const data = greeting()
console.log("Работает!", data)
} catch (error) {
console.log("Ошибка: ", error)
}
}

sayHi()
  • A: Работает! Всем привет!
  • B: Ошибка: undefined
  • C: ошибка
  • D: Ошибка: Всем привет!
Ответ

Правильный ответ: D

С помощью оператора throw мы можем создавать собственные ошибки. Другими словами, с помощью этого оператора мы можем генерировать пользовательские исключения. Исключением может быть строка, число, логическое значение или объект. В данном случае, исключением является строка Всем привет!. С помощью оператора catch мы можем указать, что делать, если в блоке try возникла ошибка. Исключение - Всем привет!. error равняется этой строке. Это приводит к Ошибка: Всем привет!.

Вопрос № 43

function Car() {
this.make = "Lamborghini"
return { make: "Maserati" }
}

const myCar = new Car()
console.log(myCar.make)
  • A: Lamborghini
  • B: Maserati
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

Когда возвращается свойство, его значение равняется возвращаемому значению, а не значению, установленному в функции-конструкторе. Мы возвращаем строку Maserati, поэтому значением myCar.make является Maserati.

Вопрос № 44

(() => {
let x = (y = 10)
})()

console.log(typeof x)
console.log(typeof y)
  • A: undefined и number
  • B: number и number
  • C: object и number
  • D: number и undefined
Ответ

Правильный ответ: A

Выражение let x = y = 10 на самом деле является сокращением для y = 10; let x = y. Когда мы устанавливаем y равным 10, мы фактически добавляем свойство y к глобальному объекту (window в браузере, global в Node.js). В браузере window.y теперь равняется 10. Затем мы объявляем переменную x со значением y. Переменные, объявленные с помощью ключевых слов let и const, имеют блочную область видимости, они доступны только в том блоке, в котором они объявлены. Таким блоком в данном случае является немедленно вызываемое функциональное выражение (Immediately Invoked Function Expression, IIFE). Когда мы используем оператор typeof, операнд x не определен: мы пытаемся получить доступ к x вне блока его объявления. Это означает, что x имеет значение undefined. Переменные, которым не присвоено значение, по умолчанию имеют значение undefined. Выражение console.log(typeof x) возвращает undefined. Однако, мы создали глобальную переменную y, присвоив ей значение 10. Это значение доступно в любом месте кода. y определена и содержит значение типа number. Поэтому выражение console.log(typeof y) возвращает number.

Вопрос № 45

class Dog {
constructor(name) {
this.name = name
}
}

Dog.prototype.bark = function() {
console.log(`Woof I am ${this.name}`)
}

const pet = new Dog("Rex")

pet.bark()

delete Dog.prototype.bark

pet.bark()
  • A: "Woof I am Rex" и ""
  • B: "Woof I am Rex" и "Woof I am Rex"
  • C: "Woof I am Rex" и undefined
  • D: "Woof I am Rex" и ошибка
Ответ

Правильный ответ: D

Оператор delete позволяет удалять свойства объектов, включая свойства прототипов. Удаленное свойство прототипа становится недоступным в цепочке прототипов. Другими словами, функция bark после delete Dog.prototype.bark становится недоступной, однако мы все же пытаемся получить к ней доступ. Когда мы пытаемся вызвать нечто, не являющееся функцией, выбрасывается исключение TypeError: в данном случае TypeError: pet.bark is not a function, поскольку значением свойства bark объекта pet является undefined.

Вопрос № 46

const set = new Set([1, 1, 2, 3, 4])

console.log(set)
  • A: [1, 1, 2, 3, 4]
  • B: [1, 2, 3, 4]
  • C: 4
  • D: 4
Ответ

Правильный ответ: D

Set является коллекцией уникальных значений. Мы передаем в new Set() массив [1, 1, 2, 3, 4] с повторяющимся значением 1. Поскольку в set не может быть двух одинаковых значений, одно из них удаляется. Это приводит к { 1, 2, 3, 4 }.

Вопрос № 47

// counter.js
let counter = 10
export default counter

// index.js
import myCounter from "./counter.js"

myCounter += 1

console.log(myCounter)
  • A: 10
  • B: 11
  • C: ошибка
  • D: NaN
Ответ

Правильный ответ: C

Импортируемый модуль доступен только для чтения: мы не можем его изменять. Это можно сделать только перед экспортом. Когда мы пытаемся увеличить значение переменной myCounter, возникает ошибка myCounter доступен только для чтения и не может быть изменен.

Вопрос № 48

const name = "John"
age = 30

console.log(delete name)
console.log(delete age)
  • A: false и true
  • B: John и 30
  • C: true и true
  • D: undefined и undefined
Ответ

Правильный ответ: A

Оператор delete возвращает логическое значение: true при успешном удалении, иначе - false. Однако, переменные, объявленные с помощью ключевых слов, не могут быть удалены с помощью delete. Переменная name была объявлена ​​с помощью ключевого слова const, поэтому возвращается false. Когда мы устанавливаем переменную age равной 30, мы фактически добавляем свойство age к глобальному объекту (window.age в браузере, global.age в Node.js). Свойства объектов, включая глобальный, удалять можно, поэтому выражение delete age возвращает true.

Вопрос № 49

const numbers = [1, 2, 3, 4, 5]
const [y] = numbers

console.log(y)
  • A: [[1, 2, 3, 4, 5]]
  • B: [1, 2, 3, 4, 5]
  • C: 1
  • D: [1]
Ответ

Правильный ответ: C

Мы можем распаковывать элементы из массивов или свойства из объектов путем деструктуризации. Например: [a, b] = [1, 2] Значение a теперь равно 1, а значение b - 2. Что мы на самом деле сделали в приведенном примере, так это: [y] = [1, 2, 3, 4, 5] Это означает, что y равняется первому элементу массива, которым является число 1. Поэтому в консоль выводится 1.

Вопрос № 50

const user = { name: "John", age: 30 }
const admin = { admin: true, ...user }

console.log(admin)
  • A: { admin: true, user: { name: "John", age: 30 } }
  • B: { admin: true, name: "John", age: 30 }
  • C: { admin: true, user: [John, 30] }
  • D: { admin: true }
Ответ

Правильный ответ: B

Оператор распространения или расширения (spread, ...) позволяет объединять объекты - создавать копии пар ключ/значение одного объекта и добавлять их в другой объект. В данном случае мы создаем копию объекта user и добавляем ее в объект admin. Объект admin содержит скопированные пары ключ/значение, что приводит к { admin: true, name: 'John', age: 30 }.

Вопрос № 51

const person = { name: "John" }

Object.defineProperty(person, "age", { value: 30 })

console.log(person)
console.log(Object.keys(person))
  • A: { name: "John", age: 30 } и ["name", "age"]
  • B: { name: "John", age: 30 } и ["name"]
  • C: { name: "John"} и ["name", "age"]
  • D: { name: "John"} и ["age"]
Ответ

Правильный ответ: B

С помощью метода defineProperty мы можем добавлять новые свойства к объекту или изменять существующие. Когда мы добавляем свойство к объекту с помощью defineProperty(), они по умолчанию являются не перечисляемыми (enumerable: false). Метод keys возвращает все перечисляемые свойства объекта, в данном случае только name. Свойства, добавленные с помощью defineProperty(), по умолчанию также иммутабельны (неизменяемы, writable: false). Это поведение можно переопределить, используя свойства writable, configurable и enumerable. Таким образом, метод defineProperty позволяет осуществлять тонкую настройку свойств, добавляемых к объекту.

Вопрос № 52

const settings = {
username: "johnsmith",
level: 19,
health: 88
}

const data = JSON.stringify(settings, ["level", "health"])
console.log(data)
  • A: {"level": 19, "health": 88}
  • B: {"username": "johnsmith"}
  • C: ["level", "health"]
  • D: {"username": "johnsmith", "level": 19, "health": 88}
Ответ

Правильный ответ: A

Второй аргумент JSON.stringify() - это заменитель (replacer). Заменитель может быть либо функцией, либо массивом, и позволяет контролировать, что и как должно быть преобразовано в значения. Если заменитель является массивом, только свойства, указанные в нем, будут добавлены в JSON-строку. В данном случае в строку включаются только свойства level и health, свойство username исключается. Значение переменной data равняется { "level": 19, "health": 90 }. Если заменитель является функцией, она вызывается для каждого свойства объекта. Значение, возвращаемое функцией, будет значением свойства при добавлении в строку. Если значением свойства является undefined, такое свойство исключается из состава строки.

Вопрос № 53

let num = 10

const increaseNumber = () => num++
const increasePassedNumber = number => number++

const num1 = increaseNumber()
const num2 = increasePassedNumber(num1)

console.log(num1)
console.log(num2)
  • A: 10 и 10
  • B: 10 и 11
  • C: 11 и 11
  • D: 11 и 12
Ответ

Правильный ответ: A

Постфиксный оператор ++ сначала возвращает значение операнда, затем увеличивает его. Значение переменной num1 равняется 10, так как функция сначала возвращает значение переменной num и только после этого увеличивает его на 1. num2 равняется 10, так как мы передали num1 в функцию increasePassedNumber. Аргумент number равняется 10. Снова оператор ++ сначала возвращает значение операнда, а затем увеличивает его на 1. Поскольку аргумент number равняется 10, num2 также равняется 10.

Вопрос № 54

const value = { number: 10 }

const multiply = (x = { ...value }) => {
console.log((x.number *= 2))
}

multiply()
multiply()
multiply(value)
multiply(value)
  • A: 20 40 80 160
  • B: 20 40 20 40
  • C: 20 20 20 40
  • D: NaN NaN 20 40
Ответ

Правильный ответ: C

В ES6 мы можем присваивать параметрам функции значения по умолчанию. Параметр будет иметь значение по умолчанию, если другое значение не было передано функции или, если значением переданного аргумента является undefined. В данном случае, мы распаковываем свойства объекта value в новый объект, поэтому значение x по умолчанию равняется { number: 10 }. Аргумент по умолчанию реализуется в момент вызова функции. Каждый раз, когда мы вызываем функцию, создается новый объект. Мы вызываем функцию multiply первые два раза, не передавая ей никаких аргументов, поэтому x имеет значение { number: 10 }. Затем мы умножаем значение x.number на 2, получаем 20. В третий раз, когда мы вызываем multiply(), мы передаем объект value в качестве. Оператор *= является сокращением для x.number = x.number * 2: мы меняем значение x.number, теперь оно равняется 20. В четвертый раз мы снова передаем multiply() объект value. x.number равняется 20, поэтому выражение x.number *= 2 возвращает 40.

Вопрос № 55

[1, 2, 3, 4].reduce((x, y) => console.log(x, y))
  • A: 1 2 3 3 6 4
  • B: 1 2 2 3 3 4
  • C: 1 undefined 2 undefined 3 undefined 4 undefined
  • D: 1 2 undefined 3 undefined 4
Ответ

Правильный ответ: D

Первый агрумент метода reduce - аккумулятор, в данном случае x. Второй аргумент - текущее значение, y. С помощью reduce мы применяем функцию обратного вызова к каждому элементу массива, что, в конечном счете, приводит к единственному значению. В приведенном примере мы не возвращаем никаких значений из функции, а просто регистрируем значение аккумулятора и текущее значение. Значение аккумулятора равняется ранее возвращенному значению колбека. Если методу reduce не передается необязательный аргумент initialValue (начальное значение), аккумулятор равняется первому элементу при первом вызове. При первом вызове аккумулятор (x) равняется 1, а текущее значение (y) - 2. Мы не выходим из функции, а регистрируем значение аккумулятора и текущее значение: 1 и 2, соответственно. Если из функции не возвращается значения, она возвращает undefined. При следующем вызове аккумулятор равняется undefined, а текущее значение - 3. undefined и 3 выводятся в консоль. При четвертом вызове мы снова не возвращаем значение из функции. Аккумулятор равняется undefined, а текущее значение - 4: undefined и 4 выводятся в консоль.

Вопрос № 56

// index.js
console.log('Выполнение index.js')
import { sum } from './sum.js'
console.log(sum(1, 2))

// sum.js
console.log('Выполнение sum.js')
export const sum = (a, b) => a + b
  • A: Выполнение index.js Выполнение sum.js 3
  • B: Выполнение sum.js Выполнение index.js 3
  • C: Выполнение sum.js 3 Выполнение index.js
  • D: Выполнение index.js undefined Выполнение sum.js
Ответ

Правильный ответ: B

При импорте модулей с помощью ключевого слова import, они являются предварительно разобранными (распарсенными). Это означает, что модули запускаются первыми, а код в файле, который импортирует модуль, выполняется позже. В этом разница между require() в CommonJS и import() в ES6. С помощью метода require мы можем загружать зависимости динамически во время выполнения кода. При использовании require() вместо import() в консоль будет выведено Выполнение index.js Выполнение sum.js 3.

Вопрос № 57

console.log(Number(2) === Number(2))
console.log(Boolean(false) === Boolean(false))
console.log(Symbol('foo') === Symbol('foo'))
  • A: true true false
  • B: false true false
  • C: true false true
  • D: true true true
Ответ

Правильный ответ: A

Каждый Symbol уникален. Цель аргумента, переданного Symbol, состоит в том, чтобы дать Symbol описание. Значение Symbol не зависит от переданного аргумента. Когда мы проверяем равенство, мы создаем два разных Symbol: первый Symbol('foo') и второй Symbol('foo'). Эти значения уникальны и не равны друг другу, поэтому выражение "Symbol('foo') === Symbol('foo')" возвращает false.

Вопрос № 58

const name = "John Smith"
console.log(name.padStart(12))
console.log(name.padStart(2))
  • A: "John Smith" и "John Smith"
  • B: " John Smith" и " John Smith" ("[12x whitespace]John Smith" "[2x whitespace]John Smith")
  • C: " John Smith" и "John Smith" ("[2x whitespace]John Smith", "John Smith")
  • D: "John Smith" и "Jo"
Ответ

Правильный ответ: C

С помощью метода padStart мы добавляем отступы в начало строки. Значение, передаваемое этому методу, представляет собой общую длину строки вместе с отступом. Строка John Smith имеет длину, равную 10. name.padStart(12) вставляет 2 пробела в начало строки, потому что 10 + 2 есть 12. Если аргумент, переданный методу padStart, меньше длины строки, заполнение не выполняется.

Вопрос № 59

console.log("📱" + "💻")
  • A: "📱💻"
  • B: 257548
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: A

С помощью оператора + мы можем объединять строки. Это называется конкатенацией. В данном случае, мы объединяем строку 📱 со строкой 💻, что приводит к 📱💻.

Вопрос № 60

function* startGame() {
const answer = yield "Ты любишь JavaScript?"
if (answer !== "Да") {
return "Как интересно... В таком случае, что ты здесь делаешь?"
}
return "JavaScript тоже тебя любит ❤️"
}

const game = startGame()
console.log(/* 1 */) // Ты любишь JavaScript?
console.log(/* 2 */) // JavaScript тоже тебя любит ❤️
  • A: game.next("Да").value и game.next().value
  • B: game.next.value("Да") и game.next.value()
  • C: game.next().value и game.next("Да").value
  • D: game.next.value() и game.next.value("Да")
Ответ

Правильный ответ: C

Когда движок JavaScript встречает ключевое слово yield, выполнение функции-генератора приостанавливается. Во-первых, мы должны позволить функции вернуть строку Ты любишь JavaScript?, что можно сделать, вызвав game.next().value. Код функции выполняется последовательно до тех пор, пока не встретится ключевое слово yield. В первой строке имеется yield: выполнение останавливается с первым результатом. Это означает, что переменная answer на данный момент еще не определена. Когда мы вызываем game.next("Да").value, предыдущий yield заменяется значением аргумента, переданного методу next, в данном случае Да. Значение переменной answer равняется Да. Условие if (answer !== "Да") возвращает false, и JavaScript тоже тебя любит ❤️ выводится в консоль.

Вопрос № 61

console.log(String.raw`Hello\nWorld!`)
  • A: Hello World!
  • B: Hello (на следующей строке) World!
  • C: Hello\nWorld!
  • D: Hello\n (на следующей строке) World!
Ответ

Правильный ответ: C

String.raw() возвращает строку, в которой обратные последовательности (\n, \v, \t и т.д.) игнорируются. Иногда обратная косая черта может стать проблемой, например, такой код: const path = C:\Documents\Projects\table.html Будет преобразован в следующее: C:DocumentsProjects able.html String.raw() игнорирует управляющие символы: C:\Documents\Projects\table.html

Вопрос № 62

async function getData() {
return await Promise.resolve("Я сделал это!")
}

const data = getData()
console.log(data)
  • A: Я сделал это!
  • B: Promise {\<resolved\>: "Я сделал это!"}
  • C: Promise {\<pending\>}
  • D: undefined
Ответ

Правильный ответ: C

Асинхронная функция всегда возвращает промис. await ожидает разрешения промиса: промис разрешается, когда мы вызываем getData(), чтобы присвоить его переменной data. Если бы мы хотели получить доступ к разрешенному значению Я сделал это!, мы могли бы использовать метод then для data: data.then(res => console.log(res)). Тогда бы мы получили Я сделал это!.

Вопрос № 63

function addToList(item, list) {
return list.push(item)
}

const result = addToList("apple", ["banana"])
console.log(result)
  • A: ['apple', 'banana']
  • B: 2
  • C: true
  • D: undefined
Ответ

Правильный ответ: B

Метод push возвращает длину нового массива. Изначально массив содержал только один элемент (строку banana) и имел длину, равную 1. После добавления в массив строки apple, длина массива увеличилась до 2. Именно это значение возвращается из функции addToList. Метод push модифицирует исходный массив. Если мы хотим получить сам массив, а не его длину, из функции необходимо вернуть list после добавления в него item.

Вопрос № 64

const box = { x: 10, y: 20 }

Object.freeze(box)

const shape = box
shape.x = 100

console.log(shape)
  • A: { x: 100, y: 20 }
  • B: { x: 10, y: 20 }
  • C: { x: 100 }
  • D: ошибка
Ответ

Правильный ответ: B

Object.freeze() делает невозможным добавление, удаление или изменение свойств объекта (если только значение свойства не является другим объектом). Когда мы создаем переменную shape и устанавливаем ее равной замороженному объекту box, shape ссылается на этот объект. Заморожен ли объект, можно определить посредством Object.isFrozen(). В даном случае Object.isFrozen(shape) вернет true, поскольку переменная shape ссылается на замороженный объект. Поскольку shape заморожен, а значение свойства x не является объектом, мы не можем его изменять. x по-прежнему равняется 10, и { x: 10, y: 20 } выводится в консоль.

Вопрос № 65

const { name: myName } = { name: "John" }

console.log(name)
  • A: John
  • B: myName
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: D

Когда мы распаковываем свойство name из правого объекта, мы присваиваем значение John переменной myName. С помощью выражения { name: myName } мы сообщаем JavaScript, что хотим создать новую переменную с именем myName и со значением свойства name из правой части выражения. Поскольку мы пытаемся вывести в консоль name, переменную, которая не определена, выбрасывается исключение ReferenceError.

Вопрос № 66

const add = () => {
const cache = {}
return num => {
if (num in cache) {
return `Из кеша! ${cache[num]}`
} else {
const result = num + 10
cache[num] = result
return `Вычислено! ${result}`
}
}
}

const addFunction = add()
console.log(addFunction(10))
console.log(addFunction(10))
console.log(addFunction(5 * 2))
  • A: Вычислено! 20 Вычислено! 20 Вычислено! 20
  • B: Вычислено! 20 Из кеша! 20 Вычислено! 20
  • C: Вычислено! 20 Из кеша! 20 Из кеша! 20
  • D: Вычислено! 20 Из кеша! 20 ошибка
Ответ

Правильный ответ: C

Функция add является функцией запоминания (мемоизации). С помощью запоминания мы можем кешировать результаты вызова функции, чтобы ускорить ее повторное выполнение. В данном случае мы создаем объект cache для хранения возвращаемых функцией значений. Если мы повторно вызовем функцию addFunction с тем же аргументом, она сначала проверит, имеется ли соответствующее значение в кеше. Если такое значение имеется, оно возвращается, что экономит время на выполнение функции. Иначе, если значение в кеше отсутствует, оно вычисляется и сохраняется. Мы вызываем addFunction() 3 раза с одним и тем же аргументом: при первом вызове для num, равном 10, значение, возвращаемое функцией, в кеше отсутствует. Условие if (num in cache) возвращает false, и выполняется блок else: Вычислено! 20 выводится в консоль, а результат добавляется в объект cache. cache теперь выглядит как { 10: 20 }. При повторном вызове значение для аргумента 10 возвращается из кеша. Условие if (num in cache) возвращает true, и Из кеша! 20 выводится в консоль. В третий раз мы передаем в функцию выражение 5 * 2, что оценивается (вычисляется) как 10. Объект cache содержит искомое значение. Условие if (num in cache) возвращает true, и Из кеша! 20 выводится в консоль.

Вопрос № 67

const myLifeSummedUp = ["☕", "💻", "🍷", "🍫"]

for (let item in myLifeSummedUp) {
console.log(item)
}

for (let item of myLifeSummedUp) {
console.log(item)
}
  • A: 0 1 2 3 "☕" "💻" "🍷" "🍫"
  • B: "☕" "💻" "🍷" "🍫" "☕" "💻" "🍷" "🍫"
  • C: "☕" "💻" "🍷" "🍫" 0 1 2 3
  • D: 0 1 2 3 { 0: "☕", 1: "💻", 2: "🍷", 3: "🍫" }
Ответ

Правильный ответ: A

С помощью цикла for-in мы перебираем перечисляемые свойства объекта. В массиве перечисляемые свойства являются "ключами" элементов массива, которые фактически являются их индексами. Вы можете представить массив как: {0: "☕", 1: "💻", 2: "🍷", 3: "🍫"}, где ключи - перечисляемые свойства. 0 1 2 3 выводится в консоль. С помощью цикла for-of мы перебираем значения итерируемых сущностей (сущностей, поддающихся перебору). Массив является итерируемой сущностью. Когда мы выполняем итерацию по массиву, переменная item равняется итерируемому элементу, "☕" "💻" "🍷" "🍫" выводится в консоль.

Вопрос № 68

const list = [1 + 2, 1 * 2, 1 / 2]
console.log(list)
  • A: ["1 + 2", "1 * 2", "1 / 2"]
  • B: ["12", 2, 0.5]
  • C: [3, 2, 0.5]
  • D: [1, 1, 1]
Ответ

Правильный ответ: C

Элементами массива могут быть любые типы данных. Числа, строки, объекты, другие массивы, null, логические значения, undefined, а также даты, функции и выражения. Элемент будет равен возвращаемому значению. Выражение 1 + 2 возвращает 3, 1 * 2 - 2, а 1 / 2 - 0.5.

Вопрос № 69

function sayHi(name) {
return `Hello, ${name}`
}

console.log(sayHi())
  • A: Hello,
  • B: Hello, undefined
  • C: Hello, null
  • D: ошибка
Ответ

Правильный ответ: B

По умолчанию аргументы функции имеют значение undefined, если значение не было передано при вызове функции или присвоено по умолчанию. В данном случае мы не передаем значения для аргумента name. name равняется undefined. В ES6 мы можем перезаписывать undefined значениями по умолчанию. Например: function sayHi(name = "John") { ... }. В данном случае, если мы не передали значение или передали undefined, аргумент name будет иметь значение John.

Вопрос № 70

var status = "😎"

setTimeout(() => {
const status = "😍"

const data = {
status: "😉",
getStatus() {
return this.status
}
}

console.log(data.getStatus())
console.log(data.getStatus.call(this))
}, 0)
  • A: "😉" "😍"
  • B: "😉" "😎"
  • C: "😍" "😎"
  • D: "😎" "😎"
Ответ

Правильный ответ: B

Значение ключевого слова this зависит от того, в каком контексте оно используется. В методе getStatus this указывает на объект, которому принадлежит метод. Метод принадлежит объекту data, поэтому this указывает на этот объект. Когда мы выводим в консоль this.status, выводится свойство status объекта data или 😉. С помощью метода call мы можем изменить объект, на который ссылается this (изменить контекст this). В функциях ключевое слово this относится к объекту, которому принадлежит функция, либо к объекту, создаваемому с помощью функции-конструктора. Мы объявили функцию setTimeout для объекта global, поэтому в функции setTimeout ключевое слово this указывает на объект global. В глобальном объекте есть переменная status со значением 😎, которое и выводится в консоль.

Вопрос № 71

const person = {
name: "John",
age: 30
}

let city = person.city
city = "New York"

console.log(person)
  • A: { name: "John", age: 30 }
  • B: { name: "John", age: 30, city: "New York" }
  • C: { name: "John", age: 30, city: undefined }
  • D: New York
Ответ

Правильный ответ: A

Мы устанавливаем переменную city равной значению свойства city объекта person. У этого объекта нет свойства city, поэтому переменная city имеет значение undefined. Обратите внимание, что мы не ссылаемся на person. Мы просто устанавливаем переменную city равной текущему значению свойства city объекта person. Затем мы устанавливаем переменную city равной строке New York. Это не изменяет объект person.

Вопрос № 72

function checkAge(age) {
if (age < 18) {
const message = "Ты слишком молод."
} else {
const message = "Ты достаточно взрослый!"
}
return message
}

console.log(checkAge(30))
  • A: "Ты слишком молод."
  • B: "Ты достаточно взрослый!"
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: C

Переменные, объявленные с помощью ключевых слов const и let, имеют блочную область видимости. Блок - это любой код между фигурными скобками ({}) - в данном случае в фигурных скобках операторов if-else. Мы не можем получить доступ к переменной за пределами блока, в котором она объявлена - выбрасывается исключение ReferenceError.

Вопрос № 73

function getName(name) {
const hasName = /* ? */
}
  • A: !!name
  • B: name
  • C: new Boolean(name)
  • D: name.length
Ответ

Правильный ответ: A

С помощью выражения !!name мы определяем, является ли значение аргумента name истинным. Если name равняется true, то !name возвращает false. А !false (это то, чем на самом деле является !!name) возвращает true. Устанавливая hasName равным name, мы устанавливаем hasName равным любому значению, которое передается функции getName, а не логическому значению true. new Boolean(true) возвращает объектную обертку, а не само логическое значение. name.length возвращает длину переданного аргумента.

Вопрос № 74

console.log("Я хочу пиццу!"[0])
  • A: ""
  • B: "Я"
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

Чтобы получить символ по определенному индексу из строки, мы можем использовать скобочную нотацию. Первый символ в строке имеет индекс 0, второй - индекс 1 и т.д. В данном случае мы хотим получить элемент с индексом 0, символ Я, который и выводится в консоль. Альтернативой получения символа по индексу является метод charAt.

Вопрос № 75

function sum(num1, num2 = num1) {
console.log(num1 + num2)
}

sum(10)
  • A: NaN
  • B: 20
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

Мы можем установить значение параметра по умолчанию равным другому параметру функции, если такой параметр был определен до параметра по умолчанию. Мы передаем значение 10 функции sum. Если sum() получает только один аргумент, значит, значение для num2 не передано, ей присваивается значение по умолчанию, т.е. 10. Выражение num1 + num2 возвращает 20. Если попытаться установить значение параметра по умолчанию равным параметру, который определяется позже, то возникнет ошибка.

Вопрос № 76

// module.js
export default () => "Hello World!"
export const name = "John"

// index.js
import * as data from "./module"

console.log(data)
  • A: { default: function default(), name: "John" }
  • B: { default: function default() }
  • C: { default: "Hello World!", name: "John" }
  • D: глобальный объект module.js
Ответ

Правильный ответ: A

С помощью import * as name мы импортируем все экспорты из файла module.js в файл index.js, создается новый объект data. В файле module.js имеется два экспорта: экспорт по умолчанию и именованный экспорт. Экспорт по умолчанию - это функция, которая возвращает строку Hello World!, а именованный экспорт - это переменная nam", которая имеет значение John. Объект data имеет свойство default для экспорта по умолчанию, другие свойства - именованные экспорты и соответствующие значения.

Вопрос № 77

class Person {
constructor(name) {
this.name = name
}
}

const member = new Person("John")
console.log(typeof member)
  • A: class
  • B: function
  • C: object
  • D: string
Ответ

Правильный ответ: C

Классы являются синтаксическим сахаром для функций-конструкторов. Эквивалентом класса Person в качестве функции-конструктора будет function Person() { this.name = name }. Вызов функции-конструктора с ключевым словом new приводит к созданию нового экземпляра объекта Person. Выражение typeof member возвращает object.

Вопрос № 78

let newList = [1, 2, 3].push(4)

console.log(newList.push(5))
  • A: [1, 2, 3, 4, 5]
  • B: [1, 2, 3, 5]
  • C: [1, 2, 3, 4]
  • D: ошибка
Ответ

Правильный ответ: D

Метод push возвращает длину нового массива, а не сам массив. Устанавливая newList равным [1, 2, 3].push(4), мы устанавливаем newList равным 4. Затем мы пытаемся использовать метод push для newList. Поскольку newList является числом 4, мы не можем использовать push - выбрасывается исключение TypeError.

Вопрос № 79

function giveMePizza() {
return "А вот и пицца!"
}

const giveMeChocolate = () => "Вот шоколад... теперь дуй в тренажерку."

console.log(giveMePizza.prototype)
console.log(giveMeChocolate.prototype)
  • A: { constructor: ...} { constructor: ...}
  • B: {} { constructor: ...}
  • C: { constructor: ...} {}
  • D: { constructor: ...} undefined
Ответ

Правильный ответ: D

Обычные функции, такие как giveMePizza, имеют свойство prototype, которое является объектом (прототипом объекта) со свойством constructor. Однако стрелочные функции, такие как giveMeChocolate, не имеют прототипа. Поэтому при попытке получить доступ к giveMeChocolate.prototype возвращается undefined.

Вопрос № 80

const person = {
name: "John",
age: 30
}

for (const [x, y] of Object.entries(person)) {
console.log(x, y)
}
  • A: name John и age 30
  • B: ["name", "John"] и ["age", 30]
  • C: ["name", "age"] и undefined
  • D: ошибка
Ответ

Правильный ответ: A

Object.entries(person) возвращает массив вложенных массивов, содержащий ключи и значения: [ [ 'name', 'John' ], [ 'age', 30 ] ]. С помощью цикла for-of мы перебираем элементы массива - в данном случае подмассивы. Мы можем деструктурировать подмассивы в цикле, используя const [x, y]. x равняется первому элементу в подмассиве, y - второму. Первым подмассивом является [ "name", "John" ], где x равняется name, а y - John. Вторым подмассивом является [ "age", 30 ], где x равняется age, а y - 30.

Вопрос № 81

function getItems(fruitList, ...args, favoriteFruit) {
return [...fruitList, ...args, favoriteFruit]
}

console.log(getItems(["banana", "apple"], "pear", "orange"))
  • A: ["banana", "apple", "pear", "orange"]
  • B: [ ["banana", "apple"], "pear", "orange" ]
  • C: ["banana", "apple", ["pear"], "orange"]
  • D: ошибка
Ответ

Правильный ответ: D

...args - это прочие параметры (оператор rest). Значение прочих параметров - это массив, содержащий неиспользованные аргументы и в этой связи передаваемый последним. В приведенном примере rest является вторым аргументом. Это приводит к синтаксической ошибке.

function getItems(fruitList, favoriteFruit, ...args) {
return [...fruitList, ...args, favoriteFruit]
}
getItems(["banana", "apple"], "pear", "orange")

Данный код работает, как ожидается, и возвращает массив [ 'banana', 'apple', 'orange', 'pear' ].

Вопрос № 82

function nums(a, b) {
if
(a > b)
console.log('a больше')
else
console.log('b больше')
return
a + b
}

console.log(nums(4, 2))
console.log(nums(1, 2))
  • A: a больше, 6 и b больше, 3
  • B: a больше, undefined и b больше, undefined
  • C: undefined и undefined
  • D: ошибка
Ответ

Правильный ответ: B

В JavaScript мы не обязаны явно указывать точку с запятой (;), однако, интерпретатор автоматически добавляет их после операторов. Оператором могут быть переменные или ключевые слова, такие как throw, return, break и др. В приведенном примере имеется оператор return и выражение a + b на новой строке. Поскольку это новая строка, движок не знает, что это значение, которое мы хотим вернуть. Он автоматически добавляет точку с запятой после return. Это выглядит так: return; a + b. Это означает, что строка a + b никогда не достигается, функция возвращает управление после ключевого слова return. Если значение не возвращается явно, как в приведенном примере, функция возвращает undefined. Обратите внимание, что после операторов if-else точки с запятой автоматически не вставляются.

Вопрос № 83

class Person {
constructor() {
this.name = "John"
}
}

Person = class AnotherPerson {
constructor() {
this.name = "Jane"
}
}

const member = new Person()
console.log(member.name)
  • A: John
  • B: Jane
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

Мы можем установить классы равными другим классам/функциям-конструкторам. В данном случае мы устанавливаем класс Person равным классу AnotherPerson. Свойство name этого конструктора имеет значение Jane, поэтому свойство name для нового экземпляра класса Person member - это также Jane.

Вопрос № 84

const info = {
[Symbol("a")]: "b"
}

console.log(info)
console.log(Object.keys(info))
  • A: { Symbol('a'): 'b' } и ["{Symbol('a')"]
  • B: {} и []
  • C: { a: 'b' } и ['a']
  • D: { Symbol('a'): 'b' } и []
Ответ

Правильный ответ: D

Symbol не является перечисляемым (enumerable: false). Метод keys возвращает все перечисляемые ключи объекта. Symbol не просматривается таким способом, поэтому возвращается пустой массив. При выводе в консоль объекта будут видны все его свойства, даже не перечисляемые. Это одно из качеств символа: помимо представления совершенно уникального значения (которое предотвращает случайное пересечение имен в объектах, например, при работе с 2 библиотеками, которые хотят добавить свойства с одинаковыми именами к одному и тому же объекту). Мы также можем "скрыть" свойства объектов таким способом (хотя и не полностью: мы можем получить доступ к символам с помощью Object.getOwnPropertySymbols()).

Вопрос № 85

const getList = ([x, ...y]) => [x, y]
const getUser = user => { name: user.name; age: user.age }

const list = [1, 2, 3, 4]
const user = { name: "John", age: 30 }

console.log(getList(list))
console.log(getUser(user))
  • A: [1, [2, 3, 4]] и undefined
  • B: [1, [2, 3, 4]] и { name: "John", age: 30 }
  • C: [1, 2, 3, 4] и { name: "John", age: 30 }
  • D: null и { name: "John", age: 30 }
Ответ

Правильный ответ: A

Функция getList принимает массив в качестве аргумента. В getList() мы деструктурируем этот массив. Это выглядит так: [x, ...y] = [1, 2, 3, 4]. С помощью rest-оператора ...y мы помещаем прочие аргументы (все аргументы, кроме первого) в массив. Такими аргументами являются 2, 3 и 4. Значением переменной y является массив, содержащий прочие параметры. В данном случае значение x равно 1, поэтому, в консоль попадает [x, y], т.е. [1, [2, 3, 4]]. Функция getUser в качестве аргумента принимает нечто, похожее на объект (обратите внимание, что свойства "объекта" разделяются ;, а не ,). В случае стрелочных функций мы можем обойтись без фигурных скобок, если возвращаем только одно значение. Однако, если мы хотим вернуть объект из стрелочной функции, то должны указать его в круглых скобках, в противном случае, при разборе кода, когда движок встретит , будет выброшено исключение SyntaxError. Такая функция вернула бы объект: const getUser = user => ({ name: user.name, age: user.age }). Поскольку "свойства" разделены ; и отсутствует оператор return, функция возвращает undefined.

Вопрос № 86

const name = "John"

console.log(name())
  • A: SyntaxError
  • B: ReferenceError
  • C: TypeError
  • D: undefined
Ответ

Правильный ответ: C

Переменная name содержит строку, которая не является функцией, поэтому не может быть вызвана. TypeError возникает, когда значение не соответствует ожидаемому типу. Движок JavaScript ожидает, что значением переменной name является функция, так как мы пытаемся ее вызвать. Однако, значением name является строка, поэтому выбрасывается исключение TypeError: name is not a function (name не является функцией). SyntaxError генерируются, когда мы написали нечто недопустимое с точки зрения JavaScript, например, когда ключевое слово return написано как retrun. ReferenceError генерируются, когда JavaScript не может найти ссылку на значение, к которому мы обращаемся.

Вопрос № 87

const one = (false || {} || null)
const two = (null || false || "")
const three = ([] || 0 || true)

console.log(one, two, three)
  • A: false null []
  • B: null "" true
  • C: "" []
  • D: null null true
Ответ

Правильный ответ: C

Оператор || (логическое ИЛИ) возвращает первый истинный операнд. Если все значения ложны, возвращается последний операнд. (false || {} || null): пустой объект ({}) является истинным значением. Это первое (и единственное) истинное значение, которое и возвращается. Переменная one имеет значение {}. (null || false ||""): все операнды являются ложными. Это означает, что возвращается последний операнд - пустая строка (""). Переменная two имеет значение "". ([] || 0 || true): пустой массив ([]) является истинным значением. Это первое истинное значение, которое и возвращается. Переменная three имеет значение [].

Вопрос № 88

const myPromise = () => Promise.resolve('I have resolved!')

function firstFunction() {
myPromise().then(res => console.log(res))
console.log('first')
}

async function secondFunction() {
console.log(await myPromise())
console.log('second')
}

firstFunction()
secondFunction()
  • A: I have resolved! first и I have resolved! second
  • B: first I have resolved! и second I have resolved!
  • C: I have resolved! second и first I have resolved!
  • D: first I have resolved! и I have resolved! second
Ответ

Правильный ответ: D

С промисами дело обстоит следующим образом: "Я хочу отложить выполнение этой функции, поскольку это может занять некоторое время" (promise переводится как "обещание"). Только когда промис выполнен или отклонен (разрешен), и когда стек вызовов (call stack) пуст, я хочу получить возвращаемое им значение. Мы можем получить значение с помощью ключевого слова then или await в асинхронной функции. Эти ключевые слова работают по-разному. В firstFunction() мы (вроде бы) приостановили выполнение функции myPromise, и продолжили выполнение другого кода, в данном случае console.log('first'). Затем функция разрешается строкой I have resolved!, которая выводится в консоль после освобождения стека вызовов. С помощью ключевого слова await в secondFunction() мы приостанавливаем выполнение асинхронной функции до тех пор, пока промис не будет разрешен. Это означает, что мы ожидаем разрешения myPromise() со значением I have resolved!, и только после того, как это произошло, мы переходим к следующей строке. Поэтому строка second выводится в консоль последней.

Вопрос № 89

const set = new Set()

set.add(1)
set.add("John")
set.add({ name: "John" })

for (let item of set) {
console.log(item + 2)
}
  • A: 3 NaN NaN
  • B: 3 7 NaN
  • C: 3 John2 [object Object]2
  • D: "12" John2 [object Object]2
Ответ

Правильный ответ: C

Оператор + используется не только для сложения чисел, но и для объединения (конкатенации) строк. Всякий раз, когда движок JavaScript видит, что одно или несколько значений не являются числом, он приводит число к строке. Первым значением является 1 - число. Выражение 1 + 2 возвращает 3. Вторым значением является John. John является строкой, а 2 - числом: 2 приводится к строке. John и 2 объединяются, что приводит к John2. { name: "John" } является объектом. Ни число, ни объект не являются строкой, поэтому они приводятся к строке. Когда объект приводится к строке он превращается в [object Object]. [object Object], объединенный с 2, становится [object Object]2.

Вопрос № 90

console.log(Promise.resolve(5))
  • A: 5
  • B: Promise {<pending>: 5}
  • C: Promise {<resolved>: 5}
  • D: ошибка
Ответ

Правильный ответ: C

Мы можем передавать в Promise.resolve() любой тип данных. Данный метод возвращает промис с разрешенным значением. Если мы передадим ему обычную функцию, промис разрешится с обычным значением. Если мы передадим промис, промис разрешится с разрешенным значением переданного промиса. В данном случае мы передаем Promise.resolve() число 5. Поэтому возвращается разрешенный промис со значением 5.

Вопрос № 91

function compareMembers(person1, person2 = person) {
if (person1 !== person2) {
console.log("Не одинаковые!")
} else {
console.log("Одинаковые!")
}
}

const person = { name: "Игорь" }

compareMembers(person)
  • A: Не одинаковые!
  • B: Одинаковые!
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

Объекты в JavaScript передаются по ссылке. Когда мы проверяем объекты на строгое равенство (идентичность) с помощью оператора ===, мы сравниваем их ссылки. Мы устанавливаем значение по умолчанию для параметра person2, равное объекту person, и передаем объект person в качестве значения для параметра person1. Это означает, что оба параметра содержат ссылку на одно и то же место в памяти, поэтому они равны. Выполняется код в блоке else, и в консоль выводится Одинаковые!.

Вопрос № 92

const colorConfig = {
red: true,
blue: false,
green: true,
black: true,
yellow: false,
}

const colors = ["pink", "red", "blue"]

console.log(colorConfig.colors[1])
  • A: true
  • B: false
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: D

В JavaScript у нас есть два способа получить доступ к свойствам объекта: скобочная нотация и точечная нотация. В данном случае, мы используем точечную нотацию (colorConfig.colors) вместо скобочной (colorConfig["colors"]). При точечной нотации движок пытается найти свойство объекта с указанным именем. В приведенном примере JavaScript пытается найти свойство colors в объекте colorConfig. Такого свойства не существует, поэтому возвращается undefined. Затем мы пытаемся получить доступ к значению первого элемента массива, используя [1]. Мы не можем сделать этого для undefined, поэтому выбрасывается исключение TypeError: Cannot read property '1' of undefined. JavaScript интерпретирует (распаковывает) операторы. Когда мы используем скобочную нотацию, JavaScript видит открывающуюся скобку ([) и продолжает разбирать код, пока не встретит закрывающуюся скобку (]). Только после этого выражение оценивается. Если бы мы использовали colorConfig[colors[1]], то вернулось бы значение свойства red объекта colorConfig.

Вопрос № 93

console.log('❤️' === '❤️')
  • A: true
  • B: false
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: A

Смайлики - это юникоды. Юникод для сердца - U+2764 U+FE0F. Юникоды одинаковы для одних и тех же смайликов. Таким образом, мы сравниваем две одинаковые строки, поэтому возвращается true.

Вопрос № 94

const food = ['🍕', '🍫', '🍳', '🍔']
const info = { favoriteFood: food[0] }

info.favoriteFood = '🍝'

console.log(food)
  • A: ['🍕', '🍫', '🍳', '🍔']
  • B: ['🍝', '🍫', '🍳', '🍔']
  • C: ['🍝', '🍕', '🍫', '🍳', '🍔']
  • D: undefined
Ответ

Правильный ответ: A

Мы устанавливаем значение свойства favourFood объекта info равным строке 🍕. Строка является примитивным типом данных. В JavaScript примитивные типы данных (все, что не является объектом) передаются по значению. Затем мы меняем значение свойства favourFood. Массив food не изменился, поскольку значение favourFood было скопировано из значения первого элемента в массиве и не имеет ссылки на то же место в памяти, что и food[0]. Поэтому в консоль выводится исходный массив ['🍕', '🍫', '🍳', '🍔'].

Вопрос № 95

let name = 'John'

function getName() {
console.log(name)
let name = 'Jane'
}

getName()
  • A: John
  • B: Jane
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: D

Каждая функция имеет собственный контекст выполнения (или область видимости). Функция getName сначала ищет переменную name в собственном контексте (области видимости). getName() содержит переменную name: мы объявляем переменную name с помощью ключевого слова let и присваиваем ей значение Jane. Переменные, объявленные с помощью ключевых слов let и const не поднимаются в начало области видимости (в данном случае функции), в отличие от переменных, объявленных с помощью ключевого слова var. Они недоступны до инициализации (присваивания им значения). Это называется "временной мертвой зоной". Когда мы пытаемся получить доступ к таким переменным, JavaScript выбрасывает исключение ReferenceError. Если бы мы не объявили переменную name в функции getName, движок продолжал бы поиск переменной по цепочке областей видимости. Внешняя область видимости содержит переменную name со значением John. В этом случае в консоль было бы выведено John.

Вопрос № 96

function* generatorOne() {
yield ['a', 'b', 'c']
}

function* generatorTwo() {
yield* ['a', 'b', 'c']
}

const one = generatorOne()
const two = generatorTwo()

console.log(one.next().value)
console.log(two.next().value)
  • A: a a
  • B: a undefined
  • C: ['a', 'b', 'c'] a
  • D: a ['a', 'b', 'c']
Ответ

Правильный ответ: C

С помощью ключевого слова yield мы получаем значения в функциях-генераторах. С помощью yield* мы можем получить значение из другой функции-генератора или итерируемого объекта (например, массива). В generatorOne() мы получаем весь массив [' a ',' b ',' c '], используя yield. Значение свойства value, возвращаемого методом next объекта one (one.next().value), равняется массиву ['a', 'b', 'c'].

console.log(one.next().value) // ['a', 'b', 'c']
console.log(one.next().value) // undefined

В функции generatorTwo мы используем ключевое слово yield*. Это означает, что первое значение равняется первому значению итератора. Итератор - это массив ['a', 'b', 'c']. Первым значением этого массива является a, поэтому когда мы вызываем two.next().value, возвращается a.

console.log(two.next().value) // 'a'
console.log(two.next().value) // 'b'
console.log(two.next().value) // 'c'
console.log(two.next().value) // undefined

Вопрос № 97

console.log(`${(x => x)('Я люблю')} писать код`)
  • A: Я люблю писать код
  • B: undefined писать код
  • C: ${(x => x)('Я люблю') писать код
  • D: ошибка
Ответ

Правильный ответ: A

Выражения внутри шаблонных литералов оцениваются первыми. Это означает, что строка будет содержать значение выражения - в данном случае значение немедленно вызываемого функционального выражения (IIFE) (x => x)('Я люблю'). Мы передаем значение Я люблю в качестве аргумента стрелочной функции x => x. Аргумент x имеет значение Я люблю, которое и возвращается. Это приводит к Я люблю писать код.

Вопрос № 98

const person = {
name: "John",
age: 29
}

const changeAge = (x = { ...person }) => x.age += 1
const changeAgeAndName = (x = { ...person }) => {
x.age += 1
x.name = "Jane"
}

changeAge(person)
changeAgeAndName()

console.log(person)
  • A: { name: "Jane", age: 30 }
  • B: { name: "Jane", age: 31 }
  • C: { name: "John", age: 30 }
  • D: { name: "John", age: 31 }
Ответ

Правильный ответ: C

Функции changeAge и changeAgeAndName имеют параметры по умолчанию, а именно: вновь созданный объект { ...person }. Этот объект имеет копии всех ключей/значений объекта person. Сначала мы вызываем changeAge() и передаем ей объект person в качестве аргумента. Эта функция увеличивает значение свойства age на 1. person теперь равняется { name: 'John', age: 30 }. Затем мы вызываем changeAgeAndName() без аргументов. Поэтому значение аргумента x равняется новому объекту { ...person }. Поскольку это новый объект, он не влияет на свойства исходного объекта person. Таким образом, person по-прежнему равняется { name: 'John', age: 30 }.

Вопрос № 99

function sumValues(x, y, z) {
return x + y + z // 6
}
  • A: sumValues([...1, 2, 3])
  • B: sumValues([...[1, 2, 3]])
  • C: sumValues(...[1, 2, 3])
  • D: sumValues([1, 2, 3])
Ответ

Правильный ответ: C

С помощью spread-оператора (...) мы разбиваем итерируемые сущности на отдельные элементы. Функция sumValues принимает три аргумента: x, y и z. Для того, чтобы эта функция вернула 6, ей в качестве аргумента необходимо передать ...[1, 2, 3].

Вопрос № 100

let num = 1
const list = ['a', 'b', 'c', 'd']

console.log(list[(num += 1)])
  • A: b
  • B: c
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

С помощью оператора += мы увеличиваем значение переменной num на 1. Начальным значением num является 1, выражение 1 + 1 оценивается как 2. Элементом массива со вторым индексом является c, что и выводится в консоль.

Вопрос № 101

const person = {
firstName: 'John',
lastName: 'Smith',
pet: {
name: 'Rex',
},
getFullName() {
return `${this.firstName} ${this.lastName}`
}
}]
const member = {}

console.log(person.pet?.name)
console.log(person.pet?.family?.name)
console.log(person.getFullName?.())
console.log(member.getLastName?.())
  • A: undefined undefined undefined undefined
  • B: Rex undefined John Smith undefined
  • C: Rex null John Smith null
  • D: ошибка
Ответ

Правильный ответ: B

Благодаря оператору опциональной последовательности (?.) нам больше не нужно предварительно определять наличие глубоко вложенных свойств. Если мы попытаемся получить доступ к свойству значения undefined или null, выражение вернет undefined. person.pet?.name: объект person имеет свойство pet, pet имеет свойство name - возвращается Rex. person.pet?.family?.name: объект person имеет свойство pet, pet не имеет свойства family - возвращается undefined. person.getFullName?.(): объект person имеет метод getFullName - возвращается John Smith. member.getLastName?.(): объект member не имеет метода getLastName, возвращается undefined.

Вопрос № 102

const groceries = ['банан', 'яблоко', 'апельсин']

if (groceries.indexOf('банан')) {
console.log('Нам нужно купить бананы!')
} else {
console.log('Нам не нужно покупать бананы!')
}
  • A: Нам нужно купить бананы!
  • B: Нам не нужно покупать бананы!
  • C: undefined
  • D: 1
Ответ

Правильный ответ: B

Условие groceries.indexOf('banana') возвращает значение 0, которое является ложным. Поскольку условие не удовлетворяется, выполняется код в блоке else, в консоль выводится Нам не нужно покупать бананы!

Вопрос № 103

const config = {
languages: [],
set language(lang) {
return this.languages.push(lang)
}
}

console.log(config.language)
  • A: function language(lang) { this.languages.push(lang }
  • B: 0
  • C: []
  • D: undefined
Ответ

Правильный ответ: D

Метод language - это сеттер. Сеттеры не имеют собственных значений, их задача - модифицировать свойства объекта. Поэтому вызов сеттера возвращает undefined.

Вопрос № 104

const name = 'John Smith'

console.log(!typeof name === 'object')
console.log(!typeof name === 'string')
  • A: false true
  • B: true false
  • C: false false
  • D: true true
Ответ

Правильный ответ: C

Выражение typeof name возвращает string. string - это истинное значение, поэтому выражение !typeof name возвращает false. false === 'object' и false === 'string' возвращают false (если мы хотим сравнить типы значений вместо !typeof следует использовать !==).

Вопрос № 105

const add = x => y => z => {
console.log(x, y, z)
return x + y + z
}

add(4)(5)(6)
  • A: 4 5 6
  • B: 6 5 4
  • C: 4 function function
  • D: undefined undefined 6
Ответ

Правильный ответ: A

Функция add возвращает стрелочную функцию, которая возвращает стрелочную функцию, которая возвращает стрелочную функцию (вы еще здесь?). Это называется каррированием (currying). Первая функция принимает аргумент x со значением 4. Мы вызываем вторую функцию с аргументом y, имеющим значение 5. Затем мы вызываем третью функцию с аргументом z со значением 6. Когда мы пытаемся получить доступ к значениям x и y, движок JavaScript поднимается по цепочке областей видимости в поисках соответствующих значений. Возвращается 4 5 6.

Вопрос № 106

async function* range(start, end) {
for (let i = start; i <= end; i++) {
yield Promise.resolve(i)
}
}

;(async () => {
const gen = range(1, 3)
for await (const item of gen) {
console.log(item)
}
})()
  • A: Promise {1} Promise {2} Promise {3}
  • B: Promise {<pending>} Promise {<pending>} Promise {<pending>}
  • C: 1 2 3
  • D: undefined undefined undefined
Ответ

Правильный ответ: C

Функция-генератор range возвращает асинхронный объект с промисами для каждого переданного значения: Promise{1}, Promise{2}, Promise{3}. Мы присваиваем переменной gen этот объект и перебираем его элементы с помощью цикла for-await-of. Мы устанавливаем значение переменной item равным значению промиса. Поскольку мы ожидаем значения item, т.е. разрешения промиса, то получаем 1 2 3.

Вопрос № 107

const myFunc = ({ x, y, z }) => {
console.log(x, y, z)
}

myFunc(1, 2, 3)
  • A: 1 2 3
  • B: { 1: 1 } { 2: 2 } { 3: 3 }
  • C: { 1: undefined } undefined undefined
  • D: undefined undefined undefined
Ответ

Правильный ответ: D

Функция myFunc в качестве аргумента ожидает получить объект со свойствами x, y и z. Поскольку мы передаем ей 1, 2, 3, а не { x: 1, y: 2, z: 3 }, то возвращается значение x, y и z по умолчанию, т.е. undefined.

Вопрос № 108

const spookyItems = ['👻', '🎃', '👿']
({ item: spookyItems[3] } = { item: '💀' })

console.log(spookyItems)
  • A: ["👻", "🎃", "👿"]
  • B: ["👻", "🎃", "👿", "💀"]
  • C: ["👻", "🎃", "👿", { item: "💀" }]
  • D: ["👻", "🎃", "👿", "[object Object]"]
Ответ

Правильный ответ: B

Деструктурируя объекты, мы распаковываем значения правого объекта и присваиваем их одноименному свойству левого объекта. В данном случае мы присваиваем значение 💀 spookyItems[3]. Это означает, что мы модифицируем массив spookyItems, добавляя в него 💀. Поэтому получаем ["👻", "🎃", "👿", "💀"].

Вопрос № 109

const name = 'John Smith'
const age = 30

console.log(Number.isNaN(name))
console.log(Number.isNaN(age))

console.log(isNaN(name))
console.log(isNaN(age))
  • A: true false true false
  • B: true false false false
  • C: false false true false
  • D: false true false true
Ответ

Правильный ответ: C

С помощью Number.isNaN() мы проверяем, является ли переданное значение числом и равняется ли оно NaN. name не является числом, поэтому Number.isNaN(name) возвращает false. age является числом, но не равняется NaN, поэтому Number.isNaN(age) также возвращает false. С помощью метода isNaN мы проверяем, что переданное значение не является числом. name не является числом, поэтому isNaN(name) возвращает true. age является числом, поэтому isNaN(age) возвращает false.

Вопрос № 110

const randomValue = 30

function getInfo() {
console.log(typeof randomValue)
const randomValue = 'John Smith'
}

getInfo()
  • A: number
  • B: string
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: D

Переменные, объявленные с помощью ключевых слов const и let недоступны до инициализации (присваивания им значения; это называется "временной мертвой зоной"). В getInfo() областью видимости переменной randomValue является функция. Когда мы пытаемся вывести значение randomValue в консоль, выбрасывается исключение ReferenceError. Движок JavaScript не поднимается по цепочке областей видимости, поскольку мы объявили переменную randomValue в функции getInfo. Если бы мы этого не сделали, в консоль бы вывелся тип внешней (глобальной) переменной randomValue, т.е. number.

Вопрос № 111

const myPromise = Promise.resolve('Woah some cool data')

;(async () => {
try {
console.log(await myPromise)
} catch {
throw new Error(`Oops didn't work`)
} finally {
console.log('Oh finally')
}
})()
  • A: Woah some cool data
  • B: Oh finally
  • C: Woah some cool data и Oh finally
  • D: Oops didn't work и Oh finally
Ответ

Правильный ответ: C

В блоке try мы выводим в консоль ожидаемое (разрешенное) значение переменной myPromise - Woah some cool data. Поскольку в блоке try не возникло ошибки, код в блоке catch не выполняется. Код в блоке finally выполняется всегда, поэтому в консоль выводится Oh finally.

Вопрос № 112

const emojis = ['💫', ['✨', '✨', ['🍕', '🍕']]]

console.log(emojis.flat(1))
  • A: ['💫', ['✨', '✨', ['🍕', '🍕']]]
  • B: ['💫', '✨', '✨', ['🍕', '🍕']]
  • C: ['💫', ['✨', '✨', '🍕', '🍕']]
  • D: ['💫', '✨', '✨', '🍕', '🍕']
Ответ

Правильный ответ: B

С помощью метода flat мы создаем новый "плоский" массив. Глубина этого массива зависит от передаваемого значения. В данном случае мы передаем значение 1 (чего мы могли бы не делать, поскольку оно является значением по умолчанию), значит, будут объединены только массивы первого уровня вложенности, т.е. ['💫'] и ['✨', '✨', ['🍕', '🍕']]. Результатом объединения этих массивов является ['💫', '✨', '✨', ['🍕', '🍕']].

Вопрос № 113

class Counter {
constructor() {
this.count = 0
}

increment() {
this.count++
}
}

const counterOne = new Counter()
counterOne.increment()
counterOne.increment()

const counterTwo = counterOne
counterTwo.increment()

console.log(counterOne.count)
  • A: 0
  • B: 1
  • C: 2
  • D: 3
Ответ

Правильный ответ: D

Переменная counterOne является экземпляром класса Counter. Класс Counter содержит свойство count в конструкторе и метод increment, увеличивающий значение данного свойства на 1. Сначала мы дважды вызываем increment(). Значением counterOne.count становится равным 2. Затем мы создаем новую переменную counterTwo и присваиваем ей значение переменной counterOne. Поскольку объекты взаимодействуют между собой через ссылки, мы просто создали новую ссылку на то же самое место в памяти, на которое указывает counterOne. Поскольку обе переменные ссылаются на одну и ту же область памяти, любые изменения объекта, на который ссылается counterTwo также влияют на counterOne. Таким образом, значением counterTwo является 2. Мы вызываем counterTwo.increment(), который увеличивает значение свойства count до 3. Наконец, мы выводим в консоль counterOne.count и получаем 3.

Вопрос № 114

const myPromise = Promise.resolve(
Promise.resolve('Promise!')
)

function funcOne() {
myPromise.then(res => res).then(res => console.log(res))
setTimeout(() => console.log('Timeout!', 0))
console.log('Last line!')
}

async function funcTwo() {
const res = await myPromise
console.log(await res)
setTimeout(() => console.log('Timeout!', 0))
console.log('Last line!')
}

funcOne()
funcTwo()
  • A: Promise! Last line! Promise! Last line! Last line! Promise!
  • B: Last line! Timeout! Promise! Last line! Timeout! Promise!
  • C: Promise! Last line! Last line! Promise! Timeout! Timeout!
  • D: Last line! Promise! Promise! Last line! Timeout! Timeout!
Ответ

Правильный ответ: D

Сначала мы вызываем функцию funcOne. На первой строке этой функции мы вызываем промис myPromise, который является асинхронной операцией. Пока движок JavaScript занят разрешением промиса, выполнение myFunc() продолжается. На следующей строке у нас имеется асинхронная функция setTimeout, которая отправляется в WebAPI. Промис и setTimeout() являются асинхронными, поэтому движок продолжает выполнять код функции, не ожидая разрешения промиса и обработки setTimeout(). Сказанное означает, что сначала в консоль выводится Last line!, поскольку console.log() - синхронная операция. Это последняя строка кода в myFunc(), промис разрешается и в консоль выводится Promise!. В момент вызова функции funcTwo стек вызовов (call stack) не является пустым, поэтому колбек setTimeout() не может туда попасть. В funcTwo() мы сначала ожидаем разрешение промиса myPromise. С помощью ключевого слова await мы приостанавливаем выполнение функции до разрешения (выполнения или отклонения) промиса. Затем мы выводим в консоль ожидаемое значение переменной res (поскольку промис возвращает промис). В консоль выводится Promise!. На следующей строке у нас снова встречается асинхронная функция setTimeout, которая отправляется в WebAPI. Мы достигаем последней строки кода в funcTwo(), в консоль выводится Last line!. После того, как funcTwo() удаляется из стека вызовов, стек оказывается пустым. Ожидающие этого в очереди задач колбеки (console.log("Timeout!") из funcOne() и console.log("Timeout!") из funcTwo()) помещаются туда одна за другой. Первый колбек выводит в консоль Timeout! и удаляется из стека, затем то же самое происходит со вторым колбеком. Таким образом, мы получаем Last line! Promise! Promise! Last line! Timeout! Timeout!.

Вопрос № 115

// sum.js
export default function sum(x) {
return x + x
}

// index.js
import * as sum from './sum'
/* вызов функции "sum" */
  • A: sum()
  • B: sum.sum()
  • C: sum.default()
  • D: символ * может использоваться только при именованном экспорте
Ответ

Правильный ответ: C

С помощью символа * мы импортируем все экспортируемые из файла сущности, как дефолтные, так и именованные. Если у нас есть такие файлы:

// info.js
export const name = 'John'
export const age = 30
export default 'I love JavaScript!'

// index.js
import * as info from './info'
console.log(info)

В консоль будет выведено:

{ default: "I love JavaScript!", name: "John", age: 30 }

В данном случае импортированное значение функции sum выглядит примерно так:

{ default: function sum(x) { return x + x } }

Мы можем вызвать эту функцию посредством sum.default().

Вопрос № 116

const handler = {
set: () => console.log('Added a new property!'),
get: () => console.log('Accessed a property!'),
}

const person = new Proxy({}, handler)

person.name = 'John'
person.name
  • A: Added a new property!
  • B: Accessed a property!
  • C: Added a new property! Accessed a property!
  • D: ошибка
Ответ

Правильный ответ: C

С помощью прокси (Proxy) мы можем добавить объекту, передаваемому в качестве второго аргумента, определенное поведение. В данном случае мы передаем объект handler, который имеет два свойства: set и get. set вызывается при установке значений, а get - при их получении. Первый аргумент прокси - пустой объект ({}), который является значением переменной person. Поведение этого объекта определено в объекте handler. При добавлении свойства объекту person вызывается метод set. При получении доступа к свойству person вызывается get(). Сначала мы добавляем прокси новое свойство name. Вызывается метод set и в консоль выводится Added a new property!. Затем мы получаем значение свойства name. Вызывается get() и в консоль выводится Accessed a property!.

Вопрос № 117

const person = {
name: 'John Smith',
address: {
street: '100 Some Street',
}
}

Object.freeze(person)
person.address.street = "101 Main Street"
console.log(person.address.street)
  • A: false
  • B: 100 Some Street
  • C: 101 Main Street
  • D: ошибка
Ответ

Правильный ответ: C

Object.freeze() "замораживает" объект. В такой объект нельзя добавлять новые свойства, а существующие свойства не могут изменяться или удаляться. Тем не менее, объект замораживается поверхностно. Это означает, что свойства первого уровня вложенности иммутабельны (неизменяемы/неизменны). Однако в случае, когда таким свойством является объект (address), его свойства можно изменять.

Вопрос № 118

const add = x => x + x

function myFunc(num = 2, value = add(num)) {
console.log(num, value)
}

myFunc()
myFunc(3)
  • A: 2 4 и 3 6
  • B: 2 NaN и 3 NaN
  • C: 2 undefined и 3 6
  • D: 2 4 и 3 undefined
Ответ

Правильный ответ: A

Сначала мы вызываем функцию myFunc без аргументов. Поэтому аргументам присваиваются значения по умолчанию: num - 2, а value - значение, возвращаемое функцией add. Мы передаем add() значение num в качестве аргумента, которое равняется 2. add() возвращает 4, что является значением value. Затем мы вызываем myFunc() с аргументом 3, которое присваивается num. Поскольку мы не присваиваем значения value, его значением вновь становится значение, возвращаемое add(). Мы передаем add() значение 3, она возвращает 6, что становится значением value.

Вопрос № 119

class Counter {
#number = 10

increment() {
this.#number++
}

getNum() {
return this.#number
}
}

const counter = new Counter()
counter.increment()

console.log(counter.#number)
  • A: 10
  • B: 11
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: D

В ECMAScript 2020 мы можем добавлять классам приватные (частные/закрытые) переменные с помощью символа #. Мы не можем получить доступ к таким переменным за пределами класса. Поэтому, когда мы пытается вывести в консоль значение counter.#number, выбрасывается исключение SyntaxError.

Вопрос № 120

const teams = [
{ name: 'Team 1', members: ['John', 'Jane'] },
{ name: 'Team 2', members: ['Alice', 'Bob'] },
]

function* getMembers(members) {
for (let i = 0; i < members.length; i++) {
yield members[i]
}
}

function* getTeams(teams) {
for (let i = 0; i < teams.length; i++) {
/* ? */
}
}

const obj = getTeams(teams)
obj.next() // { value: "John", done: false }
obj.next() // { value: "Jane", done: false }
  • A: yield getMembers(teams[i].members)
  • B: yield* getMembers(teams[i].members)
  • C: return getMembers(teams[i].members)
  • D: return yield getMembers(teams[i].members)
Ответ

Правильный ответ: B

Для того, чтобы перебрать members в каждом элементе массива items, нам необходимо передать teams[i].members в функцию-генератор getMembers. Генератор возвращает объект. Для того, чтобы перебрать элементы этого объекта следует использовать yield*. Если мы не укажем yield, return yield или return, внутренняя функция-генератор не будет возвращена при первом вызове метода next.

Вопрос № 121

const person = {
name: 'John Smith',
hobbies: ['coding'],
}

function addHobby(hobby, hobbies = person.hobbies) {
hobbies.push(hobby)
return hobbies
}

addHobby('running', [])
addHobby('dancing')
addHobby('baking', person.hobbies)

console.log(person.hobbies)
  • A: ["coding"]
  • B: ["coding", "dancing"]
  • C: ["coding", "dancing", "baking"]
  • D: ["coding", "running", "dancing", "baking"]
Ответ

Правильный ответ: C

Функция addHobby принимает два аргумента: hobby и hobbies с дефолтным значением, равным свойству hobbies объекта person. Сначала мы вызываем addHobby() и передаем ей running в качестве значения для hobby и пустой массив в качестве значения для hobbies. Поскольку мы передали пустой массив в качестве значения для hobbies, в него добавляется running. Затем мы вызываем addHobby() и передаем ей dancing в качестве значения для hobby. При этом, мы не передаем значения для hobbies, поэтому он получает значение по умолчанию, т.е. значение свойства hobbies объекта person. В этот массив добавляется dancing. Наконец, мы вызываем addHobby() и передаем ей baking в качестве значения для hobby и массив person.hobbies в качестве значения для hobbies. Мы добавляем baking в массив person.hobbies. После добавления dancing и baking значением person.hoobies является ["coding", "dancing", "baking"].

Вопрос № 122

class Bird {
constructor() {
console.log("I'm a bird. 🐤")
}
}

class Flamingo extends Bird {
constructor() {
console.log("I'm pink. 🌸")
super()
}
}

const pet = new Flamingo()
  • A: I'm pink. 🌸
  • B: I'm pink. 🌸 и I'm a bird. 🐤
  • C: I'm a bird. 🐤 и I'm pink. 🌸
  • D: undefined
Ответ

Правильный ответ: B

Мы создаем переменную pet, которая является экземпляром класса Flamingo. При создании экземпляра вызывается constructor(). В консоль выводится I'm pink. 🌸, после чего вызывается super(). super() вызывает конструктор родительского класса. В консоль выводится I'm a bird. 🐤.

Вопрос № 123

const person = {
name: "John Smith",
age: 30
}

[...person] // ["John Smith", 30]
  • A: объекты являются итерируемыми по умолчанию
  • B: *[Symbol.iterator]() { for (let x in this) yield* this[x] }
  • C: *[Symbol.iterator]() { yield* Object.values(this) }
  • D: *[Symbol.iterator]() { for (let x in this) yield this }
Ответ

Правильный ответ: C

Объекты не являются итерируемыми (перебираемыми) по умолчанию. В итерируемых сущностях имеется протокол итератора. Мы можем реализовать такой протокол вручную, добавив в объект символ итератора ([Symbol.iterator]), который будет возвращать объект-генератор. Мы, например, можем преобразовать исходный объект в функцию-генератор с помощью [Symbol.iterator]() {}. Эта функция-генератор будет перебирать значения объекта person. Если мы хотим вернуть массив ['John Smith', 30], то объект должен выглядеть так: yield* Object.values(this).

Вопрос № 124

let count = 0
const nums = [0, 1, 2, 3]

nums.forEach(num => {
if (num) count += 1
})

console.log(count)
  • A: 1
  • B: 2
  • C: 3
  • D: 4
Ответ

Правильный ответ: C

Условие в цикле forEach проверяет, является ли значение переменной num истинным. Поскольку первым значением num является 0 (ложное значение), код в блоке if не выполняется. Остальные значения num (1, 2, 3) являются истинными, поэтому значение count увеличивается на 1 три раза. В результате значением count становится 3.

Вопрос № 125

function getFruit(fruits) {
console.log(fruits?.[1]?.[1])
}

getFruit([['🍊', '🍌'], ['🍍']])
getFruit()
getFruit([['🍍'], ['🍊', '🍌']])
  • A: null undefined 🍌
  • B: [] null 🍌
  • C: [] [] 🍌
  • D: undefined undefined 🍌
Ответ

Правильный ответ: D

Оператор ?. (опциональная последовательность) позволяет нам безопасно получать доступ к глубоко вложенным и потенциально несуществующим свойствам объектов. Мы пытаемся вывести в консоль элемент с индексом 1 подмассива с индексом 1 массива fruits. Если подмассива с индексом 1 в массиве fruits не существует, возвращается undefined. Если подмассив с индексом 1 в массиве fruits существует, но не имеет элемента с индексом 1, также возвращается undefined. Сначала мы пытаемся вывести в консоль второй элемент подмассива ['🍍'] массива [['🍊', '🍌'], ['🍍']]]. Этот подмассив состоит из одного элемента, т.е. элемента с индексом 1 в данном массиве не существует, поэтому возвращается undefined. Затем мы вызываем функцию getFruits без аргументов, поэтому массив fruits имеет значение undefined. Наконец, мы пытаемся вывести в консоль второй элемент подмассива ['🍊', '🍌'] массива ['🍍'], ['🍊', '🍌']. Элементом с индексом 1 этого подмассива является 🍌, что и выводится в консоль.

Вопрос № 126

class Calc {
constructor() {
this.count = 0
}

increase() {
this.count++
}
}

const calc = new Calc()
new Calc().increase()

console.log(calc.count)
  • A: 0
  • B: 1
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: A

Мы присваиваем переменной calc значение нового экземпляра класса Calc. Затем мы инициализируем новый экземпляр класса Calc и вызываем его метод increase. Поскольку свойство count находится в конструкторе класса Calc, данное свойство не является общим для экземпляров класса Calc. Это означает, что свойство count не обновляется для calc, оно по-прежнему равняется 0.

Вопрос № 127

const user = {
email: "e@mail.com",
password: "12345"
}

const updateUser = ({ email, password }) => {
if (email) {
Object.assign(user, { email })
}

if (password) {
user.password = password
}

return user
}

const updatedUser = updateUser({ email: "new@email.com" })

console.log(updatedUser === user)
  • A: false
  • B: true
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

Функция updateUser обновляет свойства email и password объекта user, если их значения переданы в качестве аргументов, после чего функция возвращает объект user. Значением, которое вернула updateUser(), является объект user. Таким образом, переменная updatedUser ссылается на то же место в памяти, что и сам user. Поэтому выражение updatedUser === user возвращает true.

Вопрос № 128

const fruits = ['🍌', '🍊', '🍎']

fruits.slice(0, 1)
fruits.splice(0, 1)
fruits.unshift('🍇')

console.log(fruits)
  • A: ['🍌', '🍊', '🍎']
  • B: ['🍊', '🍎']
  • C: ['🍇', '🍊', '🍎']
  • D: ['🍇', '🍌', '🍊', '🍎']
Ответ

Правильный ответ: C

Сначала мы вызываем метод slice для массива fruits. Данный метод не модифицирует исходный массив и возвращает извлеченное значение: 🍌. Затем мы вызываем метод splice. Данный метод модифицирует исходный массив, fruits теперь выглядит так: ['🍊', '🍎']. Наконец, мы вызываем метод unshift, который также модифицирует исходный массив, добавляя к нему 🍇 в качестве первого элемента. Массив fruits теперь выглядит так: ['🍇', '🍊', '🍎'].

Вопрос № 129

const animals = {}
let dog = { emoji: '🐶' }
let cat = { emoji: '🐈' }

animals[dog] = { ...dog, name: "Rex" }
animals[cat] = { ...cat, name: "Niko" }

console.log(animals[dog])
  • A: { emoji: "🐶", name: "Rex" }
  • B: { emoji: "🐈", name: "Niko" }
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: B

Ключи объекта конвертируются (преобразуются) в строки. Поскольку значением переменной dog является объект, animals[dog] означает, что мы создаем новое свойство с именем object Object, значением которого является новый объект. animals["object Object"] равняется { emoji: "🐶", name: "Rex"}. Значением переменной cat также является объект. Это означает, что мы перезаписываем свойство animals["object Object"] новым значением. Поэтому, когда мы выводим в консоль animals[dog], мы на самом деле обращаемся к animals["object Object"], поэтому получаем { emoji: "🐈", name: "Niko" }.

Вопрос № 130

const user = {
email: "my@email.com",
updateEmail: email => {
this.email = email
}
}

user.updateEmail("new@email.com")
console.log(user.email)
Ответ

Правильный ответ: A

Функция updateEmail является стрелочной, поэтому она не привязана (bind) к объекту user. Это означает, что ключевое слово this не ссылается на объект user. В данном случае this указывает на глобальную область видимости (window в браузере, global в Node.js). Значение свойства email объекта user не обновляется. Поэтому, когда мы обращаемся к user.email, в консоль выводится my@email.com.

Вопрос № 131

const promise1 = Promise.resolve('First')
const promise2 = Promise.resolve('Second')
const promise3 = Promise.reject('Third')
const promise4 = Promise.resolve('Fourth')

const runPromises = async () => {
const res1 = await Promise.all([promise1, promise2])
const res2 = await Promise.all([promise3, promise4])
return [res1, res2]
}

runPromises()
.then(res => console.log(res))
.catch(er => console.log(er))
  • A: [['First', 'Second'] и ['Fourth']]
  • B: [['First', 'Second'] и ['Third', 'Fourth']]
  • C: [['First', 'Second']]
  • D: 'Third'
Ответ

Правильный ответ: D

Promise.all() выполняет переданные ему промисы одновременно (параллельно). Если один из промисов отклоняется, Promise.all() также отклоняется со значением отклоненного промиса. В данном случае promise3 отклоняется со значением Third. Мы обрабатываем отклоненное значение в блоке catch функции runPromises. Поэтому в консоль выводится только Third.

Вопрос № 132

const keys = ["name", "age"]
const values = ["John", 30]

const method = /* ? */

Object[method](keys.map((_, i) => {
return [keys[i], values[i]]
})) // { name: "John", age: 30 }
  • A: entries
  • B: values
  • C: fromEntries
  • D: forEach
Ответ

Правильный ответ: C

Метод fromEntries преобразует двумерный массив в объект. Первый элемент каждого подмассива становится ключом, а второй - значением. В данном случае мы перебираем элементы массива keys, возвращая массив, первым элементом которого является элемент массива keys с текущим индексом, вторым элементом - элемент массива values с текущим индексом. Это создает массив массивов с правильными ключами и значениями, которые преобразуются в { name: 'John', age: 30 }.

Вопрос № 133

const createMember = ({ email, address = {}}) => {
const validEmail = /.+@.+..+/.test(email)
if (!validEmail) throw new Error("Valid email please")

return {
email,
address: address ? address : null
}
}

const member = createMember({ email: "my@email.com" })
console.log(member)
  • A: { email: "my@email.com", address: null }
  • B: { email: "my@email.com" }
  • C: { email: "my@email.com", address: {} }
  • D: { email: "my@email.com", address: undefined }
Ответ

Правильный ответ: C

Значением address по умолчанию является пустой объект ({}). Когда мы присваиваем переменной member значение, возвращаемое функцией createMember, мы не передаем значение для address, поэтому ее значением становится {}. Пустой объект - это истинное значение, поэтому условие address ? address : null возвращает address. Значением address является {}.

Вопрос № 134

let randomValue = { name: "John" }
randomValue = 30

if (!typeof randomValue === "string") {
console.log("Это не строка!")
} else {
console.log("Это строка!")
}
  • A: Это не строка!
  • B: Это строка!
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

Условие if проверяет, является ли !typeof randomValue строкой. Оператор ! преобразует значение в логический тип данных и инвертирует его. Если значение истинно, возвращается false, если ложно - true. В данном случае значением typeof randomValue является number, что есть истина, поэтому возвращается false. Выражение !typeof randomValue === 'string' возвращает false, поскольку на самом деле мы проверяем false === 'string'. Условие возвращает false, поэтому выполняется код в блоке else и в консоль выводится Это строка!.

Вопрос № 135

var car = new Vehicle("Honda", "white", "2010", "UK")
console.log(car)

function Vehicle(model, color, year, country) {
this.model = model
this.color = color
this.year = year
this.country = country
}
  • A: undefined
  • B: ошибка
  • C: null
  • D: { model: "Honda", color: "white", year: "2010", country: "UK" }
Ответ

Правильный ответ: D

Объявление функции поднимается в начало области видимости подобно объявлению переменной. Это называется поднятием или подъемом (hoisting). Поэтому место объявления функции Venicle в данном случае значения не имеет.

Вопрос № 136

function foo() {
let x = y = 0
x++
y++
return x
}

console.log(foo(), typeof x, typeof y)
  • A: 1 undefined undefined
  • B: ошибка
  • C: 1 undefined number
  • D: 1 number number
Ответ

Правильный ответ: C

Функция foo возвращает 1 из-за оператора ++. Выражение let x = y = 0 определяет локальную переменную x. Однако y определяется как глобальная переменная. Данное выражение эквивалентно следующему:

let x
window.y = 0
x = window.y

Поскольку переменная x за пределами функции имеет значение undefined, т.е. не определена, ее типом также является undefined. Однако y за пределами функции доступна и имеет значение 0 с типом number.

Вопрос № 137

function main() {
console.log('A')
setTimeout(function print() {
console.log('B')
}, 0)
console.log('C')
}

main()
  • A: A B C
  • B: B A C
  • C: A C
  • D: A C B
Ответ

Правильный ответ: D

Порядок выполнения функций зависит от стека вызовов (call stack). В данном случае он будет таким:

  1. Сначала в стек помещается функция main.
  2. Затем в стек помещается console.log('A'), выполняется и удаляется из стека.
  3. Далее setTimeot() отправляется в WebAPI, а оставшийся код продолжает выполняться.
  4. В стек помещается console.log('C'), выполняется и удаляется из стека.
  5. Колбек setTimeout() помещается в очередь задач (task queue, второе слово читается как "кью").
  6. Функция main удаляется из стека.
  7. После того, как стек вызовов опустел, в него помещается колбек из очереди задач.
  8. В стек помещается console.log('B'), выполняется и удаляется из стека.

Вопрос № 138

console.log(0.1 + 0.2 === 0.3)
  • A: false
  • B: true
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: A

Здесь мы имеем дело с распространенной проблемой чисел с плавающей точкой (или запятой, или чисел двойной точности, см. IEEE 754). Поскольку такие числа преобразуются в двоичные данные, имеет место некоторая неточность округления. Поэтому математические операции с названными числами порой приводят к неожиданным результатам. В частности, значением выражения 0.1 + 0.2 будет 0.30000000000000004, что чуть больше, чем 0.3. Поэтому сравнение 0.1 + 0.2 === 0.3 возвращает false.

Вопрос № 139

var y = 1
if (function f(){}) {
y += typeof f
}
console.log(y)
  • A: 1function
  • B: 1object
  • C: ошибка
  • D: 1undefined
Ответ

Правильный ответ: D

Условие if (function f(){}) возвращает true (функция - это объект). Поскольку переменная f нигде не определяется, она имеет значение undefined по умолчанию с типом undefined. Получаем 1 + undefined или 1undefined (оба операнда приводятся к строке).

Вопрос № 140

function foo() {
return
{
message: "Hello World"
}
}
console.log(foo())
  • A: Hello World
  • B: Object { message: "Hello World" }
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: C

Здесь мы имеем дело с автоматической расстановкой точек с запятой движком JavaScript. В данном случае точка с запятой автоматически вставляется после оператора return. Поэтому функция возвращает undefined. Если поставить { перед return, то функция будет работать, как ожидается:

function foo() { return { message: 'Hello World' } }
console.log(foo()) // { message: 'Hello World' }

Вопрос № 141

var myChars = ['a', 'b', 'c', 'd']
delete myChars[0]
console.log(myChars)
console.log(myChars[0])
console.log(myChars.length)
  • A: [empty, 'b', 'c', 'd'] empty 3
  • B: [null, 'b', 'c', 'd'] empty 3
  • C: [empty, 'b', 'c', 'd'] undefined 4
  • D: [null, 'b', 'c', 'd'] undefined 4
Ответ

Правильный ответ: C

Оператор delete удаляет свойства объекта, но не индексы массива. Точнее, удаляется только значение массива по указанному индексу, сам индекс остается, его значением становится undefined. При этом, количество элементов в массиве и его длина сохраняются.

Вопрос № 142

const obj = {
prop1: function() { return 0 },
prop2() { return 1 },
['prop' + 3]() { return 2 }
}

console.log(obj.prop1())
console.log(obj.prop2())
console.log(obj.prop3())
  • A: 0 1 2
  • B: 0 { return 1 } 2
  • C: 0 { return 1 } { return 2 }
  • D: 0 1 undefined
Ответ

Правильный ответ: A

ES6, среди прочего, представил новые способы определения методов и сокращения свойств объекта. Поэтому prop2 и prop3 обрабатываются как обычные функции.

Вопрос № 143

console.log(1 < 2 < 3)
console.log(3 > 2 > 1)
  • A: true true
  • B: true false
  • C: ошибка
  • D: false false
Ответ

Правильный ответ: B

Если в блоке if содержатся одинаковые операторы, то выражение оценивается слева направо. Для первого выражения порядок будет следующим:

console.log(1 < 2 < 3)
console.log(true < 3)
console.log(1 < 3) // true

А для второго таким:

console.log(3 > 2 > 1)
console.log(true > 1)
console.log(1 > 1) // false

Вопрос № 144

// обратите внимание: код выполняется в нестрогом режиме
function printNumbers (first, second, first) {
console.log(first, second, first)
}
printNumbers(1, 2, 3)
  • A: 1 2 3
  • B: 3 2 3
  • C: ошибка
  • D: 1 2 1
Ответ

Правильный ответ: B

В нестрогом режиме дублирующиеся параметры в обычных функциях разрешены. В приведенном примере дублирующимися являются параметры 1 и 3 (first). Первый параметр указывает на третий аргумент, передаваемый функции. Поэтому третий аргумент перезаписывает первый параметр. Обратите внимание, что в строгом режиме будет выброшено исключение.

Вопрос № 145

// обратите внимание: код выполняется в нестрогом режиме
const printNumbersArrow = (first, second, first) => {
console.log(first, second, first)
}
printNumbersArrow(1, 2, 3)
  • A: 1 2 3
  • B: 3 2 3
  • C: ошибка
  • D: 1 2 1
Ответ

Правильный ответ: C

В отличие от обычных, в стрелочных функциях дублирующиеся параметры запрещены, независимо от режима выполнения кода. Поэтому в данном случае будет выброшено исключение SyntaxError: Duplicate parameter name not allowed in this context (дублирующиеся названия параметров в данном контексте запрещены).

Вопрос № 146

const f = () => arguments.length
console.log(f(1, 2, 3))
  • A: ошибка
  • B: 3
  • C: undefined
  • D: null
Ответ

Правильный ответ: A

Стрелочные функции не имеют arguments, this, super и new.target. Поэтому любое обращение к arguments приводит к поиску переменной с таким названием в лексическом (внешнем) окружении функции. В данном случае переменной arguments в коде не существует. Поэтому возникает ошибка. В обычных функциях arguments - это массивоподобный объект, содержащий переданные функции аргументы:

const f = function () { return arguments.length }
console.log(f(1, 2, 3)) // 3

В стрелочных функциях альтернативой arguments является rest-оператор ... (прочие параметры):

const f = (...args) => args.length
console.log(f(1, 2, 3)) // 3

Вопрос № 147

console.log( String.prototype.trimLeft.name === 'trimLeft' )
console.log( String.prototype.trimLeft.name === 'trimStart' )
  • A: true false
  • B: false true
  • C: undefined
  • D: null
Ответ

Правильный ответ: B

По аналогии с String.prototype.padStart встроенный метод для удаления пробелов в начале строки был назван trimStart. Однако для обеспечения обратной совместимости название trimLeft было сохранено в качестве синонима (alias) для trimStart. При этом, прототипом trimLeft является trimStart.

Вопрос № 148

console.log(Math.max())
  • A: undefined
  • B: Infinity
  • C: 0
  • D: -Infinity
Ответ

Правильный ответ: D

-Infinity - это наименьшее из сравниваемых значений, поскольку почти любое другое значение в JavaScript больше него. Поэтому, когда Math.max() вызывается без аргументов, возвращается -Infinity.

Вопрос № 149

console.log(10 == [10])
console.log(10 == [[[[[[[10]]]]]]])
  • A: true true
  • B: true false
  • C: false false
  • D: false true
Ответ

Правильный ответ: A

Согласно спецификации ECMAScript приведенные выражения будут преобразованы следующим образом:

10 == Number([10].valueOf().toString()) // 10

Поэтому количество скобок значения не имеет.

Вопрос № 150

console.log(10 + '10')
console.log(10 - '10')
  • A: 20 0
  • B: 1010 0
  • C: 1010 10-10
  • D: NaN NaN
Ответ

Правильный ответ: B

Оператор + применяется как к числам, так и к строкам. Если одним из операндов является строка, второй операнд также приводится к строке, и операнды объединяются. Это называется конкатенацией. Оператор - пытается преобразовать операнд в число. При невозможности это сделать возвращается NaN.

Вопрос № 151

console.log([1, 2] + [3, 4])
  • A: [1, 2, 3, 4]
  • B: '[1, 2][3, 4]'
  • C: ошибка
  • D: '1,23,4'
Ответ

Правильный ответ: D

Оператор + не предназначен для сложения массивов. Поэтому массивы преобразуются в строки и объединяются.

Вопрос № 152

const numbers = new Set([1, 1, 2, 3, 4])
console.log(numbers)

const browser = new Set('Firefox')
console.log(browser)
  • A: 4 и x
  • B: 4 и x
  • C: [1, 2, 3, 4] и ["F", "i", "r", "e", "o", "x"]
  • D: 4 и x
Ответ

Правильный ответ: A

Set - это объект, представляющий собой коллекцию уникальных значений, поэтому повторяющиеся значения в него не включаются. В то же время, данный объект является чувствительным к регистру, поэтому в коллекцию записываются как F, так и f.

Вопрос № 153

console.log(NaN === NaN)
  • A: true
  • B: false
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

NaN согласно стандарту IEEE 754 не равен никакому другому значению, включая NaN. Еще одной интересной особенностью NaN является то, что данное значение представляет собой неправильное, но все-таки число, несмотря на то, что NaN расшифровывается как Not a Number (не число). Для того, чтобы убедиться в том, что NaN - это число, выполните console.log(typeof NaN).

Вопрос № 154

const numbers = [1, 2, 3, 4, NaN]
console.log(numbers.indexOf(NaN))
  • A: 4
  • B: NaN
  • C: ошибка
  • D: -1
Ответ

Правильный ответ: D

indexOf() использует оператор строгого равенства или проверки на идентичность (===), а поскольку NaN не равен никакому другому значению, включая NaN, выражение NaN === NaN возвращает false. indexOf() не может найти NaN в массиве - возвращается -1. Для поиска индекса NaN можно использовать метод findIndex. Также для проверки наличия NaN в массиве можно использовать метод includes:

const numbers = [1, 2, 3, 4, NaN]
console.log(numbers.findIndex(Number.isNaN)) // 4
console.log(numbers.includes(Number.isNaN)) // true

Вопрос № 155

const [a, ...b,] = [1, 2, 3, 4, 5]
console.log(a, b)
  • A: 1 [2, 3, 4, 5]
  • B: 1 5
  • C: ошибка
  • D: 1 [2, 3, 4]
Ответ

Правильный ответ: C

При использовании rest-оператора ... (прочие параметры), он передается в качестве последнего аргумента. В данном случае использование замыкающей запятой (trailing comma) приводит к возникновению ошибки. Если убрать запятую, то все будет в порядке:

const [a, ...b] = [1, 2, 3, 4, 5]
console.log(a, b) // 1 [2, 3, 4, 5]

Вопрос № 156

async function func() {
return 10
}
console.log(func())
  • A: Promise {:10}
  • B: 10
  • C: ошибка
  • D: Promise {:undefined}
Ответ

Правильный ответ: A

Асинхронная функция всегда возвращает промис. Даже если возвращаемое такой функцией значение само по себе не является промисом, оно будет "завернуто" в промис. Приведенный пример эквивалентен следующему:

function func() { return Promise.resolve(10) }

Вопрос № 157

async function func() {
await 10
}
console.log(func())
  • A: Promise {:10}
  • B: 10
  • C: ошибка
  • D: Promise {:undefined}
Ответ

Правильный ответ: D

await возвращает Promise {:10}, который может быть обработан с помощью then. В данном случае функция не содержит оператора return, т.е. не возвращает никакого значение в явном виде. Поэтому возвращается undefined. Приведенный код эквивалентен следующему:

function func () { return Promise.resolve(10).then(() => undefined) }

Вопрос № 158

function delay() {
return new Promise(resolve => setTimeout(resolve, 2000))
}

async function delayedLog(item) {
await delay()
console.log(item)
}

async function processArray(array) {
array.forEach(item => {
await delayedLog(item)
})
}

processArray([1, 2, 3, 4])
  • A: ошибка
  • B: 1, 2, 3, 4
  • C: 4, 4, 4, 4
  • D: 4, 3, 2, 1
Ответ

Правильный ответ: A

Несмотря на то, что processArray - это асинхронная функция, анонимная функция, которую мы используем в forEach(), является синхронной. Использование ключевого слова await в синхронных функциях приводит к тому, что выбрасывается исключение SyntaxError: await is only valid in async function (ключевое слово await валидно только в асинхронных функциях).

Вопрос № 159

function delay() {
return new Promise(resolve => setTimeout(resolve, 2000))
}

async function delayedLog(item) {
await delay()
console.log(item)
}

async function process(array) {
array.forEach(async (item) => {
await delayedLog(i)
})
console.log('Process completed!')
}

process([1, 2, 3, 5])
  • A: 1 2 3 5 и Process completed!
  • B: 5 5 5 5 и Process completed!
  • C: Process completed! и 5 5 5 5
  • D: Process completed! и 1 2 3 5
Ответ

Правильный ответ: D

Метод forEach не ожидает завершения операции, он лишь запускает ее выполнение и двигается дальше. Поэтому console.log('Process finished!') выполняется первым согласно последовательности разрешения промисов. Определить нужную последовательность можно с помощью оператора for-of и ключевого слова await:

async function processArray(array) {
for (const item of array) {
await delayedLog(item)
}
console.log('Process completed!')
}

Вопрос № 160

var set = new Set()
set.add("+0")
.add("-0")
.add(NaN)
.add(undefined)
.add(NaN)

console.log(set)
  • A: Set(4)
  • B: Set(3)
  • C: Set(5) NaN
  • D: Set(4) NaN
Ответ

Правильный ответ: A

В отличии от операторов равенства (== и ===), для Set все NaN являются одинаковыми значениями, а +0 и -0 - разными.

Вопрос № 161

const sym1 = Symbol('one')
const sym2 = Symbol('one')

const sym3 = Symbol.for('two')
const sym4 = Symbol.for('two')

console.log(sym1 === sym2, sym3 === sym4)
  • A: true true
  • B: true false
  • C: false true
  • D: false false
Ответ

Правильный ответ: C

Для символом характерно следующее:

  1. Каждый символ, возвращаемый Symbol(), это уникальное значение. Строка, передаваемая Symbol(), это всего лишь опциональная метка или описание символа, которая обычно используется для отладки кода.
  2. Метод Symbol.for создает символ в глобальном реестре символов. При каждом вызове данного метода проверяется, имеется ли символ с указанным ключом в реестре. После этого либо возвращается найденный символ, либо создается новый.

Вопрос № 162

const sym1 = new Symbol('one')
console.log(sym1)
  • A: ошибка
  • B: one
  • C: Symbol('one')
  • D: Symbol
Ответ

Правильный ответ: A

Symbol - это обычная функция, а не конструктор, в отличие, например, от Number или String. Поэтому при попытке использования его с ключевым словом new выбрасывается исключение TypeError: Symbol is not a constructor (Symbol не является конструктором).

Вопрос № 163

let myNumber = 100
let myString = "100"

if (!typeof myNumber === "string") {
console.log("It is not a string!")
} else {
console.log("It is a string!")
}

if (!typeof myString === "number"){
console.log("It is not a number!")
} else {
console.log("It is a number!")
}
  • A: ошибка
  • B: It is not a string! и It is not a number!
  • C: It is not a string! и It is a number!
  • D: It is a string! и It is a number!
Ответ

Правильный ответ: D

Оператор ! приводит значение к логическому типу и инвертирует его. Поскольку выражения typeof myNumber и typeof myString истинные, в обоих случаях возвращается false. Далее выполняются блоки else.

Вопрос № 164

console.log(JSON.stringify({ myArray: ['one', undefined, function() {}, Symbol('')] }))
console.log(JSON.stringify({ [Symbol.for('one')]: 'one' }, [Symbol.for('one')]))
  • A: { "myArray":['one', undefined, {}, Symbol] } и {}
  • B: { "myArray":['one', null, null, null] } и {}
  • C: { "myArray":['one', null, null, null] } и "{ [Symbol.for('one')]: 'one' }, [Symbol.for('one')]"
  • D: { "myArray":['one', undefined, function(){}, Symbol('')] } и {}
Ответ

Правильный ответ: B

undefined, функции и символы не являются валидными JSON-значениями. Такие значения не включаются в объект и конвертируются (преобразуются) в null. Поэтому возвращается null, null, null. Глобальные символы игнорируются, поэтому возвращается пустой объект ({}).

Вопрос № 165

class A {
constructor() {
console.log(new.target.name)
}
}

class B extends A { constructor() { super() } }

new A()
new B()
  • A: A A
  • B: A B
  • C: B B
  • D: ошибка
Ответ

Правильный ответ: B

new.target ссылается на конструктор (указывает на класс), который вызывается с помощью ключевого слова new. Это также справедливо для конструктора родительского класса, вызываемого из подкласса.

Вопрос № 166

const { a: x = 10, b: y = 20 } = { a: 30 }

console.log(x)
console.log(y)
  • A: 30 20
  • B: 10 20
  • C: 10 undefined
  • D: 30 undefined
Ответ

Правильный ответ: A

Для свойств объекта характерно следующее:

  1. Значение свойства (30) может быть извлечено и присвоено переменной (x).
  2. Свойству присваивается значение по умолчанию (20), когда извлекаемым значением является undefined (y).

Вопрос № 167

function area({ length = 10, width = 20 }) {
console.log(length * width)
}

area()
  • A: 200
  • B: ошибка
  • C: undefined
  • D: 0
Ответ

Правильный ответ: B

Здесь мы имеем дело с деструктуризацией объекта. Если опустить правую часть выражения, функция при вызове попытается найти хотя бы один аргумент. Если ей не удастся этого сделать, будет выброшено исключение TypeError: Cannot read property 'length' of undefined (невозможно прочитать свойство length неопределенного значения). Решить данную проблему можно следующими способами:

  1. Передать функции пустой объект ({}) в качестве аргумента:
function area ({ length = 10, width = 20 }) { console.log(length * width) }
area({}) // 200
  1. Присвоить пустой объект в качестве значения аргумента по умолчанию:
function area ({ length = 10, width = 20 } = {}) { console.log(length * width) }
area() // 200

Вопрос № 168

const props = [
{ id: 1, name: 'John'},
{ id: 2, name: 'Jane'},
{ id: 3, name: 'Bob'}
]

const [, , { name }] = props
console.log(name)
  • A: Bob
  • B: ошибка
  • C: undefined
  • D: John
Ответ

Правильный ответ: A

Деструктуризацию массива и объекта можно комбинировать. В данном случае переменной name присваивается значение соответствующего свойства третьего элемента массива props.

Вопрос № 169

function checkType(num = 1) {
console.log(typeof num)
}

checkType()
checkType(undefined)
checkType('')
checkType(null)
  • A: number undefined string object
  • B: undefined undefined string object
  • C: number number string object
  • D: number number number number
Ответ

Правильный ответ: C

Если функции не передается значение или передается undefined, аргумент принимает значение по умолчанию (1). Другие ложные значения ("" и null) присваиваются аргументу. Первые два вызова функции checkType возвращают number, поскольку значением аргумента является 1. Типом пустой строки ("") является string, а типом null - object.

Вопрос № 170

function add(item, items = []) {
items.push(item)
return items
}

console.log(add('Orange'))
console.log(add('Apple'))
  • A: ['Orange'] и ['Orange', 'Apple']
  • B: ['Orange'] и ['Apple']
  • C: []
  • D: undefined
Ответ

Правильный ответ: B

Аргументу items при каждом вызове функции add присваивается пустой массив (значение по умолчанию), который возвращается с помещенным в него значением аргумента item.

Вопрос № 171

function greet(greeting, name, message = greeting + ' ' + name) {
console.log([greeting, name, message])
}

greet('Hello', 'John')
greet('Hello', 'John', 'Good morning!')
  • A: ошибка
  • B: ['Hello', 'John', 'Hello John'] и ['Hello', 'John', 'Good morning!']
  • C: ['Hello', 'John', 'Hello John'] и ['Hello', 'John', 'Hello John']
  • D: undefined
Ответ

Правильный ответ: B

При первом вызове функции greet аргументу message присваивается значение по умолчанию (greeting + ' ' + name). При втором вызове данному аргументу присваивается переданное значение (Good morning!).

Вопрос № 172

function outer(f = inner()) {
function inner() { return 'Inner' }
}
console.log(outer())
  • A: ошибка
  • B: Inner
  • C: Inner Inner
  • D: undefined
Ответ

Правильный ответ: A

Функции и переменные, объявленные в теле функции, не могут использоваться в качестве значений по умолчанию, поэтому выбрасывается исключение ReferenceError: inner is not defined (переменная inner не определена). Для того, чтобы сделать функцию работоспособной, ее можно переписать так:

function outer (f) { function inner () { return 'Inner' }; const fun = f || inner(); return fun }
console.log(outer()) // Inner
console.log(outer('Outer')) // Outer
Или так:
const outer = (msg = 'Inner') => msg
console.log(outer()) // Inner
console.log(outer('Outer')) // Outer

Вопрос № 173

function myFun(x, y, ...args) {
console.log(args)
}

myFun(1, 2, 3, 4, 5)
myFun(1, 2)
  • A: [3, 4, 5] и undefined
  • B: ошибка
  • C: [3, 4, 5] и []
  • D: [3, 4, 5] и [undefined]
Ответ

Правильный ответ: C

Оператор rest (прочие параметры, ...) возвращает массив с переданными функции неименованными аргументами или пустой массив в случае, когда такие аргументы отсутствуют.

Вопрос № 174

const obj = {'key': 'value'}
const array = [...obj]
console.log(array)
  • A: ['key', 'value']
  • B: ошибка
  • C: []
  • D: ['key']
Ответ

Правильный ответ: B

Оператор spread (распространения или распаковки, ...) применяется только к итерируемым (перебираемым) сущностям. Объекты таковыми не являются. Поэтому выбрасывается исключение TypeError: object is not iterable (объекты не являются итерируемыми сущностями).

Вопрос № 175

function* myGenFunc() {
yield 1
yield 2
yield 3
}
var myGenObj = new myGenFunc
console.log(myGenObj.next().value)
  • A: 1
  • B: undefined
  • C: 2
  • D: ошибка
Ответ

Правильный ответ: D

Генераторы (функции со специальным символом * после названия) не могут использоваться в качестве конструкторов, т.е. с ключевым словом new, поэтому выбрасывается исключение TypeError: myGenFunc is not a constructor (myGenFunc не является конструктором).

Вопрос № 176

function* yieldAndReturn() {
yield 1
return 2
yield 3
}

var myGenObj = yieldAndReturn()
console.log(myGenObj.next())
console.log(myGenObj.next())
console.log(myGenObj.next())
  • A: { value: 1, done: false } { value: 2, done: true } { value: undefined, done: true }
  • B: { value: 1, done: false } { value: 2, done: false } { value: undefined, done: true }
  • C: { value: 1, done: false } { value: 2, done: true } { value: 3, done: true }
  • D: { value: 1, done: false } { value: 2, done: false } { value: 3, done: true }
Ответ

Правильный ответ: A

Инструкция return в генераторе (функция со специальным символом * после названия) останавливает его выполнение. Возвращаемое значение 2 присваивается свойству value, а значением свойства done становится true. После завершения работы генератора вызов метода next возвращает { value: undefined, done: true }.

Вопрос № 177

const myGenerator = (function *(){
yield 1
yield 2
yield 3
})()

for (const value of myGenerator) {
console.log(value)
break
}

for (const value of myGenerator) {
console.log(value)
}
  • A: 1 2 3 и 1 2 3
  • B: 1 2 3 и 4 5 6
  • C: 1 1
  • D: 1
Ответ

Правильный ответ: D

Генератор (функция со специальным символом * после названия) не может использоваться после закрытия итератора. В первом цикле мы с помощью оператора break останавливаем выполнение генератора со значением 1. Повторный перебор генератора невозможен, поэтому второй console.log() ничего не выводит в консоль.

Вопрос № 178

const squareObj = new Square(10)
console.log(squareObj.area)

class Square {
constructor(length) {
this.length = length
}

get area() {
return this.length * this.length
}

set area(value) {
this.area = value
}
}
  • A: 100
  • B: ошибка
  • C: 10
  • D: undefined
Ответ

Правильный ответ: B

В отличие от объявлений функций (но не функциональных выражений), объявления классов не поднимаются в начало области видимости. Это также справедливо для выражений класса. Поэтому использовать класс можно только после его объявления, в противном случае, выбрасывается исключение ReferenceError: Square is not defined (переменная Square не определена).

Вопрос № 179

function Person() { }

Person.prototype.walk = function() {
return this
}

Person.run = function() {
return this
}

let user = new Person()
let walk = user.walk
console.log(walk())

let run = Person.run
console.log(run())
  • A: undefined undefined
  • B: Person Person
  • C: ошибка
  • D: Window Window
Ответ

Правильный ответ: D

Когда обычный метод или метод прототипа вызывается без передачи ему значения this, метод возвращает значение this по умолчанию. В данном случае таким значением является глобальный объект (window в браузере, global в Node.js).

Вопрос № 180

class Vehicle {
constructor(name) {
this.name = name
}

start() {
console.log(`${this.name} vehicle started`)
}
}

class Car extends Vehicle {
start() {
console.log(`${this.name} car started`)
super.start()
}
}

const car = new Car('BMW')
console.log(car.start())
  • A: ошибка
  • B: BMW vehicle started и BMW car started
  • C: BMW car started и BMW vehicle started
  • D: BMW car started и BMW car started
Ответ

Правильный ответ: C

Ключевое слово super используется, в том числе, для вызова методов родительского класса. В отличие от других языков программирования, в JavaScript вызов super() не обязательно должен быть первой инструкцией.

Вопрос № 181

const user = {'age': 30}
user.age = 25
console.log(user.age)
  • A: 30
  • B: 25
  • C: ошибка
  • D: undefined
Ответ

Правильный ответ: B

Мы используем ключевое слово const для объявления переменной user, т.е. делаем ее константой (неизменяемой или неизменной). Однако иммутабельность переменной-объекта, не распространяется на ее свойства. Другими словами, свойства такого объекта можно изменять. Но если мы попытаемся присвоить переменной user новое значение (user = {'age': 25}), будет выброшено исключение TypeError: Assignment to constant variable. Для обеспечения иммутабельности свойств объекта можно использовать метод freeze. Мы используем ключевое слово const для объявления переменной user, т.е. делаем ее константой (неизменяемой или неизменной). Однако иммутабельность переменной-объекта, не распространяется на ее свойства. Другими словами, свойства такого объекта можно изменять. Но если мы попытаемся присвоить переменной user новое значение (user = {'age': 25}), будет выброшено исключение TypeError: Assignment to constant variable (попытка присвоения значения константной переменной). Для обеспечения иммутабельности свойств объекта можно использовать Object.freeze().

Вопрос № 182

function a(x) {
x++
return function () {
console.log(++x)
}
}

a(1)()
a(1)()
a(1)()

let x = a(1)
x()
x()
x()
  • A: 1 2 3 и 1 2 3
  • B: 3 3 3 и 3 4 5
  • C: 3 3 3 и 1 2 3
  • D: 1 2 3 и 3 3 3
Ответ

Правильный ответ: B

Здесь мы имеем дело с замыканием. Замыкания позволяют нам создавать статические функции, которым доступны переменные из внешнего окружения. Другими словами, замыкание имеет доступ к глобальной области видимости, области видимости родительской функции и собственной области видимости. Мы получаем 3 3 3 и 3 4 5, поскольку сначала просто вызываем функцию a. Она работает как обычная функция. Затем мы объявляем переменную x и присваиваем ей значение функции a(1), вот почему мы получаем 3 4 5 вместо 3 3 3.

Вопрос № 183

function Name(a, b) {
this.a = a
this.b = b
}

const me = Name('John', 'Smith')

console.log(!(a.length - window.a.length))
  • A: undefined
  • B: NaN
  • C: true
  • D: false
Ответ

Правильный ответ: C

Мы получаем true. Обратите внимание, что при создании объекта с помощью функции-конструктора Name мы не использовали ключевое слово new. Из-за этого переменная a стала глобальной и получила значение John. В действительности, глобальные переменные - это свойства глобального объекта (window в браузере или global в Node.js). Поэтому выражение a.length - window.a.length возвращает 0, а !0 возвращает true.

Вопрос № 184

const x = function (...x) {
let k = (typeof x).length
let y = () => "freetut".length
let z = { y: y }

return k - z.y()
}

console.log(Boolean(x()))
  • A: true
  • B: 1
  • C: -1
  • D: false
Ответ

Правильный ответ: A

Spread-оператор ...x позволяет получить параметры функции в виде массива. Выражение typeof array возвращает object. Длина строки object равняется 6. z.y() возвращает длину строки freetut, т.е. 7. Функциональное выражение x возвращает -1, которое после преобразования в логический тип становится true. Обратите внимание, что Boolean(0) вернет false.

Вопрос № 185

(function js(x) {
const y = (j) => j * x

console.log(y(s()))

function s() {
return j()
}

function j() {
return x ** x
}
})(3)
  • A: undefined
  • B: 18
  • C: 81
  • D: 12
Ответ

Правильный ответ: C

Функция js выполняется автоматически, поскольку является IIFE (Immediately Invoked Function Expression - немедленно вызываемым функциональным выражением). Аргумент x передается js() со значением 3. Значение, возвращаемое функцией y(s()), означает вызов трех функций: y, s и j, поскольку s() возвращает j(). j() возвращает 3 ^ 3, или 27, поэтому s() возвращает 27. y(s()) означает y(27), что возвращает 27 * 3, или 81. Обратите внимание, что мы можем вызывать функции до их объявления, но это не работает с функциональными выражениями.

Вопрос № 186

var tip = 100

(function () {
console.log("I have $" + husband())

function wife() {
return tip * 2
}

function husband() {
return wife() / 2
}

var tip = 10
})()
  • A: I have $10
  • B: I have $100
  • C: I have $50
  • D: I have $NaN
Ответ

Правильный ответ: D

Здесь мы имеем дело с IIFE (Immediately Invoked Function Expression - немедленно вызываемым функциональным выражением). IIFE выполняются автоматически. Последовательность здесь следующая: husband() возвращает wife(), а wife() возвращает tip * 2. Можно подумать, что tip равняется 100, поскольку мы объявили ее с помощью ключевого слова var и она стала глобальной. Однако на самом деле ее значением является undefined, поскольку мы объявляем переменную tip со значением 10 внутри функции. Поскольку переменная tip поднимается в начало области видимости со значением undefined, правильным ответом является D. undefined возвращает NaN, когда мы пытаемся разделить его на 2 или умножить на 2. Если убрать var tip = 10 в конце функции, правильным ответом будет B.

Вопрос № 187

const js = { language: "loosely type", label: "difficult" }

const edu = { ...js, level: "PhD" }

const newbie = edu

delete edu.language

console.log(Object.keys(newbie).length)
  • A: 2
  • B: 3
  • C: 4
  • D: 5
Ответ

Правильный ответ: A

Данная задача посвящена spread-оператору (...). Этот оператор позволяет получать параметры функции, копировать или объединять объекты и массивы. В переменной edu мы используем оператор ... для копирования объекта js и добавления к нему свойства level. Это также работает с массивами. Затем мы объявляем другую переменную с именем newbie. Важное замечание: обе переменных указывают на одно и то же место в памяти. Это называется передачей значения по ссылке. После удаления свойства language посредством delete edu.language, длина массива ключей обоих объектов становится равной 2.

Вопрос № 188

var candidate = {
name: "John",
age: 30
}

var job = {
frontend: "Vue or React",
backend: "Nodejs and Express",
city: "Ekaterinburg"
}

class Combine {
static get() {
return Object.assign(candidate, job)
}

static count() {
return Object.keys(this.get()).length
}
}

console.log(Combine.count())
  • A: 5
  • B: 6
  • C: 7
  • D: 8
Ответ

Правильный ответ: A

Object.assign(candidate, job) объединяет candidate и job в один объект. Затем Object.keys() возвращает массив ключей объекта. Обратите внимание, что методы get и count определены как статические, поэтому их можно вызывать с помощью Class.staticMethodName(). Результирующий объект содержит 5 ключей.

Вопрос № 189

var x = 1

;(() => {
x += 1
++x
})()

;((y) => {
x += y
x = x % y
})(2)

;(() => (x += x))()

;(() => (x *= x))()

console.log(x)
  • A: 4
  • B: 50
  • C: 2
  • D: 10
Ответ

Правильный ответ: A

Начальное значение переменной x равняется 1. В первом IIFE (Immediately Invoked Function Expression - немедленно вызываемом функциональном выражении) значение x увеличивается до 3. Во втором IIFE выражение x + y (3 + 2) возвращает 5, а выражение x % y (5 % 2) возвращает 1. В третьем и четвертом IIFE мы получаем 2 (1 + 1) и 4 (2 * 2), соответственно.

Вопрос № 190

let x = {}
let y = {}
let z = x

console.log(x == y)
console.log(x === y)
console.log(x == z)
console.log(x === z)
  • A: true true true true
  • B: false false false false
  • C: true true false false
  • D: false false true true
Ответ

Правильный ответ: D

Технически x и y имеют одинаковые значения. Обе переменные являются пустыми объектами. Однако объекты сравниваются не по значениям. z и x являются объектами, ссылающимися на одно и то же место в памяти. В JavaScript объекты передаются по ссылкам. Поэтому при сравнении x и z возвращается true.

Вопрос № 191

console.log("hello")

setTimeout(() => console.log("hey"), 1)
setTimeout(() => console.log("yo"), 2)
setTimeout(() => console.log("world"), 0)

console.log("hi")
  • A: hello hey yo world hi
  • B: hello hi hey yo world
  • C: hello hi world hey yo
  • D: hello hi hey world yo
Ответ

Правильный ответ: D

Три функции setTimeout помещаются в очередь задач (task queue) перед попаданием в стек вызовов (call stack), поэтому сначала в консоль выводятся hello и hi. Можно подумать, что три колбека setTimeout() будут выполнены в следующем порядке: world -> hey -> yo согласно временной задержке в 0 мс -> 1 мс -> 2 мс, соответственно. Однако, между 0 мс и 1 мс для браузера разницы не существует. Поэтому следующим в консоль выводится hey, затем world и в конце yo.

Вопрос № 192

String.prototype.lengthy = () => {
console.log("hello")
}

let x = { name: "John" }

delete x

x.name.lengthy()
  • A: John
  • B: hello
  • C: undefined
  • D: ошибка
Ответ

Правильный ответ: B

С помощью String.prototype.someThing = function() {} можно определить новый встроенный метод объекта String. Мы можем сделать то же самое с Array, Object или FunctionName, где FunctionName - это пользовательская функция. Несложно понять, что string".lengthy возвращает hello. Оператор delete удаляет свойство объекта, а не сам объект. Поэтому мы получаем hello, а не ReferenceError. Обратите внимание, что если мы объявим объект без ключевых слов let, const или var, то получим свойство глобальный объект (window в браузере, global в Node.js). В этом случае выражение delete objectName вернет true.

Вопрос № 193

let x = {}

x.__proto__.hi = 10

Object.prototype.hi = ++x.hi

console.log(x.hi + Object.keys(x).length)
  • A: 10
  • B: 11
  • C: 12
  • D: NaN
Ответ

Правильный ответ: C

Начальным значением переменной x является пустой объект ({}). Затем мы добавляем к нему свойство hi со значением 10 с помощью x.__proto__.hi. Обратите внимание, что это эквивалентно Object.prototype.hi = 10, поэтому мы добавляем свойство hi к прототипу пустого объекта - Object. Это означает, что в дальнейшем любой объект будет наследовать данное свойство. Свойство hi становится распределенным (совместным, shared). Если мы объявим новый объект, скажем, let y = {}, переменная y унаследует свойство hi от Object. Сравнение x.__proto__ === Object.prototype вернет true. После этого, мы перезаписываем значение свойства hi новым значением 11. Получаем 1 (x имеет одно свойство) + 11 (значение свойства hi), что равняется 12.

Вопрос № 194

const array = (a) => {
let length = a.length
delete a[length - 1]
return a.length
}

console.log(array([1, 2, 3, 4]))

const object = (obj) => {
let key = Object.keys(obj)
let length = key.length
delete obj[key[length - 1]]

return Object.keys(obj).length
}

console.log(object({ 1: 2, 2: 3, 3: 4, 4: 5 }))

const setPropNull = (obj) => {
let key = Object.keys(obj)
let length = key.length
obj[key[length - 1]] = null

return Object.keys(obj).length
}

console.log(setPropNull({ 1: 2, 2: 3, 3: 4, 4: 5 }))
  • A: 3 3 3
  • B: 4 4 4
  • C: 4 3 4
  • D: 3 4 3
Ответ

Правильный ответ: C

Данная задача показывает, как работает оператор delete. Выражения delete someObject и delete someArray возвращают false (ничего не делают). Выражение delete someObject.someProperty удаляет указанное свойство объекта. В случае с массивом, выражение delete someArray[keyNumber] удаляет только значение указанного индекса, сам индекс остается и его новым значением становится undefined. По этой причине первый console.log() выводит 4 (массив содержит 4 элемента, последний имеет значение undefined), а второй - 3 (количество оставшихся свойств объекта). Последний console.log() выводит 4, поскольку присвоение свойству объекта значения null или undefined не удаляет это свойство, ключ остается. Поэтому длина массива ключей объекта сохраняется.

Вопрос № 195

var a = [1, 2, 3]
var b = [1, 2, 3]

var c = [1, 2, 3]
var d = c

var e = [1, 2, 3]
var f = e.slice()

console.log(a === b)
console.log(c === d)
console.log(e === f)
  • A: true true true
  • B: false false true
  • C: true true false
  • D: false true false
Ответ

Правильный ответ: D

Сравнение a и b возвращает false, поскольку эти переменные ссылаются на разные места в памяти, несмотря на то, что их значения являются одинаковыми. В JavaScript, в случае с объектами, значения передаются по ссылке. Во втором случае d является копией c, поэтому они ссылаются на одну и ту же область памяти. Любые изменения в c отражаются на d (и наоборот). Третий пример демонстирует способ копирования массива с помощью метода slice. f является копией e, но они ссылаются на разные места в памяти. Поэтому их сравнение возвращает false.

Вопрос № 196

var languages = {
name: ["javascript", "java", "python", "php", { name: "feature" }],
feature: "awesome"
}

let flag = languages.hasOwnProperty(
Object.values(languages)[0][4].name
)

;(() => {
if (flag !== false) {
console.log(
Object.getOwnPropertyNames(languages)[0].length <<
Object.keys(languages)[0].length
)
} else {
console.log(
Object.getOwnPropertyNames(languages)[1].length <<
Object.keys(languages)[1].length
)
}
})()
  • A: 8
  • B: NaN
  • C: 64
  • D: 12
Ответ

Правильный ответ: C

Данная задача является довольно сложной, поскольку в ней встречается несколько встроенных методов для работы с объектами. Например, методы keys и getOwnPropertyNames возвращают массивы ключей (названий свойств) объекта: первый - только перечисляемые, второй - также не перечисляемые. Object.values() и Object.keys() возвращают значения и ключи объекта, соответственно. Object.hasOwnProperty('propertyName') возвращает логическое значение в зависимости от того, существует указанное свойство в объекте или нет. Переменная language имеет значение true, поскольку Object.values(languages)[0][4].name возвращает feature, которое является свойством объекта. Наконец, мы получаем 4 << 4, что возвращает побитовое значение, эквивалентное 4 * 2 ^ 4 или 4 * 16, или 64.

Вопрос № 197

var person = {}

Object.defineProperties(person, {
name: {
value: "John",
enumerable: true,
},
job: {
value: "developer",
enumerable: true,
},
studying: {
value: "PhD",
enumerable: true,
},
money: {
value: "USD",
enumerable: false,
}
})

class Evaluate {
static checkFlag(obj) {
return Object.getOwnPropertyNames(obj) > Object.keys(obj)
? Object.getOwnPropertyNames(obj)
: Object.keys(obj)
}
}

const flag = Evaluate.checkFlag(person)

console.log(flag.length)
  • A: 1
  • B: 2
  • C: 3
  • D: 4
Ответ

Правильный ответ: D

Object.keys(obj) почти идентичен Object.getOwnPropertyNames(obj), за исключением того, что последний, кроме перечисляемых, возвращает также неперечисляемые ключи объекта. По умолчанию все свойства создаваемого объекта являются перечисляемыми. Мы можем сделать их неперечисляемыми с помощью Object.defineProperty() или Object.defineProperties() (настройка enumerable: false). Поэтому Object.keys(person) возвращает 3, а Object.getOwnPropertyNames(person) - 4. Тернарный оператор возвращает 4.

Вопрос № 198

const id = 10

const getID = (...id) => {
id(id)

function id(id) {
console.log(typeof id)
}
}

getID(id)
  • A: ошибка
  • B: 10
  • C: undefined
  • D: function
Ответ

Правильный ответ: D

Когда мы определяем одну функцию внутри другой, то получаем замыкание (closure). Обратите внимание, если функция обычная (а не функциональное выражение), она поднимается в начало области видимости. Мы видим несколько id в коде, но некоторые из них ничего не делают. Результатом выполнения кода является typeof id, т.е. function. Таким образом, id в рассматриваемом примере является функцией.

Вопрос № 199

var book1 = {
name: "Name of the Rose",
getName: function () {
console.log(this.name)
}
}

var book2 = {
name: { value: "Harry Potter" }
}

var bookCollection = Object.create(book1, book2)

bookCollection.getName()
  • A: Harry Potter
  • B: Name of the rose
  • C: ошибка
  • D: Object object
Ответ

Правильный ответ: A

Object.create() позволяет создавать одни объекты на основе других. Если мы не передадим второй параметр - book2, в данном случае - свойство name объекта bookCollection будет иметь значение Name of the Rose, унаследованное от book1. Это означает, что мы можем добавлять новые свойства создаваемому с помощью Object.create() объекту. bookCollection имеет собственное свойство name и одноименное свойство, унаследованное от book1. Собственные свойства объекта имеют приоритет над унаследованными. Поэтому мы получаем Harry Potter.

Вопрос № 200

(() => {
const a = Object.create({})

const b = Object.create(null)

let f1 = a.hasOwnProperty("toString")

let f2 = "toString" in b

let result =
f1 === false && f2 === false
? console.log((typeof a.toString()).length)
: console.log(b.toString())
})()
  • A: ошибка
  • B: undefined
  • C: 0
  • D: 6
Ответ

Правильный ответ: D

Объекты a и b создаются с помощью Object.create(). Разница между ними состоит в том, что a наследует прототип Object, а b является совершенно пустым, поскольку мы передали аргумент null методу create. hasOwnProperty('toString') в обоих случаях возвращает false, поскольку в объектах метод toString не определен. Однако данный метод существует в объекте a как унаследованный от Object. f1 и f2 возвращают false. Обратите внимание, что для проверки наличия свойства в объекте мы используем Object.hasOwnProperty('key') и ('key' in object). Они отличаются тем, что первый возвращает только собственные свойства объекта, а второй - также унаследованные. typeof a.toString() возвращает string, длина которой равняется 6.

Вопрос № 201

let promise = new Promise((rs, rj) => {
setTimeout(() => rs(4), 0)

Promise.resolve(console.log(3))

console.log(2)
})

promise
.then((rs) => {
console.log(rs ? rs ** rs : rs)
return rs
})
.then((rs) => console.log(rs === 256 ? rs : rs * rs))
  • A: 3 2 256 256
  • B: 3 2 256 16
  • C: 256 16 3 2
  • D: 16 256 3 2
Ответ

Правильный ответ: B

Мы определяем промис с помощью ключевого слова let и вызываем его. setTimeout - это асинхронная функция, которая выполняется последней, даже при нулевой задержке: setTimeout(() => rs(4), 0). Хотя выражение Promise.resolve(console.log(3)) также возвращает промис, он относится к микрозадачам (microtasks), которые имеет приоритет над макрозадачами (macrotasks), такими как setTimeout(). В первом then() мы получаем 4 ^ 4, или 256, во втором - 4 * 4, или 16. Обратите внимание, что return rs возвращает первоначальное значение.

Вопрос № 202

async function f() {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done"), 0)
})

setTimeout(() => console.log("world"), 0)

console.log(await promise)

console.log("hello")
}

f(setTimeout(() => console.log("timer"), 0))
  • A: ошибка
  • B: done hello world
  • C: hello done world
  • D: timer done hello world
Ответ

Правильный ответ: D

Хотя мы не определяем параметров в функции f, мы передаем ей setTimeout(() => console.log("timer"), 0) при вызове. Поэтому сначала в консоль выводится timer. Переменная promise, возвращающая разрешенный промис, вызывается с помощью ключевого слова await. JavaScript приостанавливает выполнение кода на строке console.log(await promise) до разрешения промиса. Вот почему следующим мы получаем done. Почему вторым значением, выведенным в консоль, является done, а не world или hello? Поскольку JavaScript ставит выполнение кода на паузу, когда встречает ключевое слово await, мы не можем получить hello до разрешения промиса (обратите внимание, что setTimeout() всегда выполняется последней, поскольку является асинхронной (макро)задачей, поэтому setTimeout(() => console.log("world"), 0)) выполняется в самом конце). Здесь мы наблюдаем разницу в работе ключевого слова await перед асинхронным оператором (в данном случае мы использовали setTimeout() для примера) и вызовом функции/оператора без него.

Вопрос № 203

class MySort {
constructor(object) {
this.object = object
}

getSort() {
return Object.entries(this.object)[0][1].sort()[
Object.values(this.object).length
]
}
}

const object = {
month: ["August", "September", "January", "December"],
}

const sortMe = new MySort(object)

console.log(sortMe.getSort())
  • A: August
  • B: September
  • C: January
  • D: December
Ответ

Правильный ответ: D

Object.entries() возвращает массив, состоящий из ключей и значений объекта в виде массивов (подмассивов), Object.values() - массив значений объекта, а Object.keys() - массив ключей. Таким образом, Object.entries(object) в рассматриваемом примере возвращает вложенный массив с одним элементом, значения которого вложены в другой массив - [["month", ["August", "September", "January", "December"]]]. По этой причине Object.entries(this.object)[0][1].sort() на самом деле сортирует значения массива и возвращает их в новом порядке: August -> December -> January -> September. Следовательно, когда мы пытаемся получить элемент с индексом [Object.values(this.object).length], то получаем December, поскольку [Object.values(this.object).length] возвращает 1 (длина массива, возвращенного Object.values()).

Вопрос № 204

const flag = [] !== !!!!![]

let f = () => {}

console.log((typeof f()).length + flag.toString().length)
  • A: NaN
  • B: 12
  • C: 13
  • D: 14
Ответ

Правильный ответ: C

Сравнение двух массивов или объектов в JavaScript всегда возвращает false, поскольку объекты передаются по ссылке, в отличие от примитивов, таких как строка, число или логическое значение. Вот почему сравнение [] и [] с помощью == или === возвращает false. Сложная часть рассматриваемого примера - это !==!!!!!, что эквивалентно !==, так что на самом деле здесь нет ничего сложного. Таким образом, значением переменной flag является true. В функциональном выражении f мы используем стрелочную функцию, но {} - это часть функции, а не объект. Для того, чтобы вернуть объект, выражение следует переписать так: let f = () => ({}) или использовать обычную функцию. С помощью ключевого слова return мы легко можем перехватить содержимое функции, когда используем обычный способ ее определения. Поэтому typeof f() возвращает undefined, а не object. Затем мы получаем 9 (длина undefined) + 4 (длина строки true), что равняется 13.

Вопрос № 205

(function (a, b, c) {
arguments[2] = (typeof arguments).length
c > 10 ? console.log(c) : console.log(++c)
})(1, 2, 3)
  • A: 4
  • B: 5
  • C: 6
  • D: 7
Ответ

Правильный ответ: D

Здесь мы имеем дело с самовызываемой функцией (IIFE) с тремя параметрами. Обратите внимание, что arguments внутри функции возвращает массивоподобный объект, состоящий из аргументов, переданных функции при вызове. Когда мы присваиваем значение этому объекту (или любому его элементу), функция будет использовать это значение, а не значение переданного при ее вызове аргумента. Поэтому значением (typeof arguments).length будет 6, а не 3. 6 меньше 10, поэтому мы получаем console.log(++c) или 7. Обратите внимание, что arguments недоступна в стрелочных функциях. ES6 рекомендует использовать rest-оператор (...) в качестве альтернативы arguments в стрелочных функциях, который возвращает настойщий массив. Таким массивом можно манипулировать с помощью методов map, filter, reduce и др.

Вопрос № 206

class Calculator {
constructor(a, b) {
this.a = a
this.b = b
}
static getFlag() {
return new Array(this.a).length == new Array(this.b)
.toString().length
}

getValue() {
return Calculator.getFlag() ? typeof this.a : typeof new Number(this.b)
}
}

const me = new Calculator(5, 5)

console.log(me.getValue())
  • A: NaN
  • B: string
  • C: object
  • D: number
Ответ

Правильный ответ: C

У нас имеется класс Calculator. При создании нового экземпляра, мы передаем ему два аргумента: a и b. Эти аргументы имеют одинаковые значения, но new Array(this.a).length сильно отличается от new Array(this.b).toString().length, поскольку последний возвращает длину строки ,,,,, или 4, а первый - длину массива, или 5. По этой причине getFlags() возвращает false. В getValue() мы получаем выражение typeof new Number(this.b), что возвращает object. Это немного отличается от выражения typeof b, которое возвращает number.

Вопрос № 207

var name = "John"

const obj = {
name: "Jane",

callMe: function () {
return this.name
}
}

let me = obj.callMe

let she = obj.callMe.bind(obj)

let result = me() === obj.callMe() ? she() : `${me()} ${she()}`

console.log(result)
  • A: undefined
  • B: John
  • C: Jane
  • D: John Jane
Ответ

Правильный ответ: D

Данный вопрос посвящен ключевому слову this. У нас есть простой объект, содержащий один метод и одно свойство. Во-первых, важно понимать, что let me = obj.callMe и последующий вызов me() существенно отличаются от прямого вызова obj.callMe(). Если мы присваиваем переменной метод, объявленный внутри объекта, this в этом объекте будет вести себя по-разному (когда мы вызываем переменную как метод и когда мы вызываем сам метод). В частности, в первом случае, this - это глобальный объект (window в браузере, global в Node.js), в то время как во втором случае this внутри функции по-прежнему ссылается на свойство name объекта obj. Это означает, что me() возвращает John, а obj.callMe - Jane. Затем result возвращает false, и мы получаем ${me()} ${she()}. Почему she() отличается от me()? Потому что she() привязана к объекту obj, а me() нет.

Вопрос № 208

((...a) => {
const b = ["JavaScript", "Russia"]

const c = [...a, typeof a, ...b, "apple"]

console.log(c.length + c[0].length)
})(new Array(10))
  • A: 5
  • B: 10
  • C: 15
  • D: 20
Ответ

Правильный ответ: C

... используется двумя способами: как оператор распространения (spread) и как прочие параметры (rest). В рассматриваемом примере мы видим оба способа. Первый оператор в самовызываемой функции (IIFE) - это, разумеется, rest, а в константе c мы видим spread. В первом случае мы можем передать функции любое количество аргументов. Обратите внимание, что typeof a - это object, несмотря на то, что фактически - это массив (в отличие от массивоподобного объекта arguments). spread позволяет объединять массивы. Таким образом, ...a - это оператор rest при использовании в качестве параметра функции, но в константе - это оператор spread. Мы получаем массив c с пятью элементами (...a - это вложенный массив, поэтому его длина равняется 1), но первый элемент данного массива сам имеет 10 элементов (new Array(10)). Сумма длин обоих массивов равняется 15.

Вопрос № 209

function F(name, ...career) {
this.name = name

return Array.isArray(career) === true && typeof career === "object" ? {} : ""
}

var student = new F("John")

console.log(student.name)
  • A: John
  • B: undefined
  • C: ошибка
  • D: false
Ответ

Правильный ответ: B

У нас имеется функция-конструктор F (название написано с заглавной буквы, это не обязательно, но таково соглашение), которая может использоваться для создания объекта, такого как объект student в рассматриваемом примере. В функции имеется два параметра, хотя второй параметр - это на самом деле rest-оператор (...). Его типом является object, но выражение Array.isArray(career) возвращает true. Оператор return возвращает пустой объект ({}). Вы можете быть немного удивлены, когда console.log(student.name) выведет в консоль undefined. Все дело в том, что у пустого объекта отсутствует свойство name.

Вопрос № 210

class Filter {
constructor(element) {
this.element = element
}
filter() {
return this.type() === "object" ? this.element[0].name : "hello"
}

type() {
return typeof this.element
}
}

let countries = [
{ name: "Russia", isdeveloped: true },
{ name: "Vietnam", isdeveloped: false },
]

let x = new Filter(countries)

const filter = countries.filter((item) => {
return !item.isDeveloped
})

console.log(x.filter().length + filter[0].name.length)
  • A: 11
  • B: 12
  • C: 13
  • D: 14
Ответ

Правильный ответ: C

Пример получился немного длинным. На самом деле, он не слишком сложный. Вы легко найдете правильный ответ, если потратите немного времени на размышления. Сначала мы определяем класс с двумя методами. Метод filter возвращает первый элемент массива (свойства element), или hello, в зависимости от метода type. Выражение typeof array возвращает object, так что filter() возвращает this.elements[0].name. Затем мы вызываем встроенный метод filter. Этот метод возвращает новый массив в зависимости от условия, переданного колбеку. Обратите внимание, что !item.isDeveloped означает false. Значит, мы получаем Vietnam. Наконец, мы получаем Russia.length и Vietnam.length, что в сумме дает 13.

Вопрос № 211

async function abc() {
console.log(8)

await Promise.resolve(2).then(console.log)

console.log(3)
}

setTimeout(() => {
console.log(1)
}, 0)

abc()

queueMicrotask(() => {
console.log(0)
})

Promise.resolve(4).then(console.log)

console.log(6)
  • A: 6 8 3 0 4 2 1
  • B: 8 2 3 0 4 6 1
  • C: 6 8 2 0 4 3 1
  • D: 8 6 2 0 4 3 1
Ответ

Правильный ответ: D

Порядок выполнения асинхронного кода зависит от микро- и макрозадач. Микрозадачи имеют приоритет. Запомните, что синхронный код всегда выполняется перед асинхронным. Поэтому мы имеем следующий порядок:

  1. Синхронный код.
  2. Микрозадачи (промисы, async/await).
  3. Макрозадачи (setTimeout, setInterval). Обратите внимание, что в Node.js у нас также имеется process.nextTick(), который имеет наивысший приоритет, но в рассматриваемой задаче его нет. Итак, колбек setTimeout() будет выполнен последним, поскольку является макрозадачей. Поэтому мы получаем 1 последним. Следующей вызывается функция abc. Сначала в консоль выводится 8. Затем на ключевом слове await выполнение функции приостанавливается, выполняется console.log(6), поскольку Promise.resolve(4).then(console.log) - это асинхронный код. Вот почему следующим мы получаем 6. Теперь настало время для Promise.resolve(2), поэтому мы получаем 2. Что произойдет, если убрать ключевое слово await? Поскольку у нас имеется ключевое слово await, выполнение кода как бы ставится на паузу. Мы получаем 0 и 4, а не 3. Промисы и async/await - микрозадачи, которые выполняются перед console.log(3). На следующем этапе мы получаем 3 и, последним, 1. Так что же произойдет, если убрать ключевое слово await? Тогда порядок будет следующим: 8 3 6 2 0 4 1.

Вопрос № 212

const username = {
x: "youtube.com/username".length,
getMe() {
const inner = function () {
console.log(++this.x)
}
inner.bind(this)()
},
}

username.getMe()
  • A: 20
  • B: 21
  • C: 22
  • D: 23
Ответ

Правильный ответ: B

Мы получаем 21. Сначала youtube.com/username возвращает 20, поскольку мы используем свойство length строки. Затем значение x увеличивается на 1 посредством ++this.x. Вопрос выглядит тривиальным, но это не так. Нужно помнить о том, что console.log(++this.x) не будет работать, если значением x будет undefined при вызове за пределами объекта. Мы можем решить эту проблему с this с помощью стрелочной функции: const inner = () => {}, поскольку стрелочные функции берут this из внешнего (лексического) окружения. Вторым решением является использование трюка с that/this. Нам нужно лишь объявить новую переменную const that = this внутри insideMe() и перед объявлением функции inner. Это довольно распространенный прием. Третьим решением является использование apply, call или bind, нативных методов функций (функция - это объект). В данном случае, мы реализовали bind(this) для связывания функции и объекта, чтобы this указывал на объект при выполнении функции. Обратите внимание, что bind() не выполняется сразу, поэтому мы добавили () после него. Если заменить bind() на call(), то дополнительные круглые скобки не понадобятся. inner.bind(this)() станет inner.call(this). На практике, мы, как правило, создаем переменную для хранения результата связывания функции и объекта.

Вопрос № 213

function* userName() {
yield "js.pro.ru"
yield "youtube.com/username"
yield "John Smith"
}

let data = userName()

console.log((typeof data).length + data.next().value.length)
  • A: NaN
  • B: 10
  • C: ошибка
  • D: 15
Ответ

Правильный ответ: D

Присмотритесь к функции. После ключевого слова function имеется символ *. В функции отсутствует ключевое слово return. Что здесь происходит? Если вы знакомы с генераторами, вам не составит труда решить рассматриваемую задачу. Мы не часто используем генераторы, но они являются основой async/await, позволяющей удобно работать с асинхронным кодом. Выражение typeof data возвращает object, а не function. typeof userName возвращает function, поскольку userName - обычная функция. Выражение (typeof data).length возвращает 6. data.next() вызывает встроенный метод next, который возвращает значение первого yield, определенного в функции. Получаем 9 - длину строки js.pro.ru. В итоге получаем 15. Понимание работы генераторов имеет важное значение для понимания работы ключевых слов async/await.

Вопрос № 214

const a = [1, 2, "one", 3, 1, "one", "two", 3]

const b = [...new Set(a)]

b.length = "one".length

console.log(b)
  • A: 4
  • B: [1, 2, "one", 3, "two"]
  • C: [1, 2, "one", "two"]
  • D: [1, 2, "one"]
Ответ

Правильный ответ: D

... в массиве - это spread-оператор (оператор распространения/распаковки), который похож на rest-оператор (прочие параметры). Данный оператор позволяет объединять (изменять) и копировать массивы. В рассматриваемом примере b - это копия a. Тем не менее, когда мы передаем a в Set, возвращаются только уникальные значения. Это означает, что b содержит [1, 2, "one", 3, "two"]. Затем мы устанавливаем значение длины b равным 3 ("one".length). Таким образом, мы уменьшили длину массива. Вот почему в консоль выводится только [1, 2, "one"].

Вопрос № 215

const one = function (p) {
return arguments[0]
}

const two = function (...p) {
return arguments[arguments[0]]
}

const a = [one(123), two(1, 2, 3)]

console.log(typeof a !== "object" ? a[0] : a[1])
  • A: 1
  • B: 2
  • C: 3
  • D: 123
Ответ

Правильный ответ: B

Прежде всего, следует отметить, что мы не можем использовать arguments в стрелочных функциях. arguments - это массивоподобный объект, который содержит аргументы, переданные функции при ее вызове. Обратите внимание, что ... в массиве - это spread-оператор (оператор распространения/распаковки), который ведет себя иначе, чем rest-оператор (прочие параметры). При использовании ... в функции, мы можем передавать ей любое количество аргументов. Также обратите внимание, что в функции two мы возвращаем arguments[arguments[0]] или 2, а не 1, поскольку arguments[0] возвращает 1, а arguments[1] - 2. Выражение typeof a возвращает object. В итоге мы получаем 2 из a[1] или two(1, 2, 3).

Вопрос № 216

class Component {
constructor(age) {
this.age = age + `${typeof Coder}`.length
}

getAge() {
return ++this.age
}
}

class Coder extends Component {
constructor(age) {
super(age)
this.age = age - `${typeof Coder}`.length
}
}

const a = new Coder(16)

console.log(a.getAge())
  • A: 7
  • B: 8
  • C: 9
  • D: 10
Ответ

Правильный ответ: C

У нас есть два простых класса, Coder расширяет Component. Ничего особенного. Поскольку typeof ClassName возвращает function, а не class, мы получаем 8 из 'function'.length. Поскольку мы используем super(age) в классе Coder, то перезаписываем конструктор родительского класса Component. Поэтому при инициализации объекта a автоматически выполняется "this.age = age - ${typeof Coder}.length". Разница между дочерним и родительским конструкторами заключается в арифметической операции. Таким образом, мы получаем 16 - 8, а не 16 + 8, т.е. 8. Функция getAge возвращает 9. Помните, что JavaScript - это не настоящий объектно-ориентированный язык программирования, несмотря на то, что мы можем использовать в нем классы и объекты.

Вопрос № 217

class RemoveFalse {
constructor(element) {
this.element = element

this.length = this.removeFalse().length
}

removeFalse() {
this.element = this.element.filter(Boolean)

return this.element
}
}

const theArray = [true, false, 1, 0, NaN, undefined, "", null, "string"]

const a = new RemoveFalse(theArray)

console.log(a.length)
  • A: false
  • B: true
  • C: 2
  • D: 3
Ответ

Правильный ответ: D

Основной вывод, который можно сделать из приведенного примера - filter(Boolean) может быть использован для удаления из массива ложных значений. Для этого мы также можем использовать filter(callback). Обратите внимание, что мы должны передать методу filter функцию обратного вызова, а Boolean как раз является такой функцией. Вы можете убедиться в этом с помощью typeof Boolean. Как и map или reduce, filter возвращает новый массив на основе существующего. [true, false, 1, 0, NaN, undefined, '', null, 'string'].filter(Boolean) возвращает [true, 1, 'string'], поэтому a.length возвращает 3.

Вопрос № 218

const coderfarm = [1, [], {}, [], 2, 3]

const converted = Number(coderfarm instanceof Array)

const result = coderfarm.indexOf(converted + true)

console.log(result)
  • A: []
  • B:
  • C: 2
  • D: 4
Ответ

Правильный ответ: D

У нас имеется массив, состоящий из нескольких чисел, двух массивов и объекта. Посредством встроенной функции Number мы можем конвертировать (преобразовать) любое переданное функции значение в число. codefarm instanceof Array возвращает true, которое преобразуется в 1. Для проверки того, является ли значение массивом, также можно использовать Array.isArray(arrayToBeChecked), возвращающий логическое значение. Выражение typeof [] возвращает object, а не array. Встроенная функция indexOf возвращает индекс искомого элемента. Поскольку converted + true возвращает 2, мы ищем индекс элемента 2 в массиве codefarm. Данный элемент находится на 4 позиции.

Вопрос № 219

const converter = (arrayInput) => {
return { ...arrayInput }
}

const content = ["function", "object", "decorator"]

const checking = content[Number(false)]

const result = typeof converter(content) === content[1]

console.log(checking ? (result ? (typeof converter).length : false) : false)
  • A: 6
  • B: NaN
  • C: true
  • D: 8
Ответ

Правильный ответ: D

Оператор ... является очень полезным. В функции converted нет ничего необычного, она использует преимущества ... (оператор rest || оператор spread) для преобразования массива в объект. Константа checking имеет значение function из Number(false), что дает 0, т.е. значением checking является элемент массива content с индексом 0. Константа result имеет значение true, поскольку typeof converter(content) возвращает object, как и content[1]. Таким образом, мы имеем checking = true и result = true, поэтому получаем (typeof converter).length или 'function'.length, или 8. Главный вывод здесь такой: мы можем использовать оператор распространения (spread-оператор) для преобразования массива в объект. Например: const a = ['hello', 2]; const b = { ...a }, получаем b = { 0: 'hello', 1: 2 }. Ключами объекта в данном случае являются индексы элементов в массиве.

Вопрос № 220

function* js(length) {
for (let i = length.length; i > 0; --i) {
yield i
}
}

let getJS = js(typeof js)

let result = getJS.next().value

console.log(result + getJS.next().value)
  • A: 10
  • B: 14
  • C: 15
  • D: 16
Ответ

Правильный ответ: C

Здесь мы имеем дело с функцией-генератором, которая определяется с помощью специального символа * после названия. Благодаря ключевому слову yield мы можем хранить в функции любое количество значений. Поскольку typeof js возвращает function, длина этой строки равняется 8. Поэтому при вызове getJS.next().value мы получаем 8. При следующем вызове мы получаем 7, затем 6. Генератор может хранить и возвращать любое количество значений. В итоге мы получаем 8 + 7, или 15.

Вопрос № 221

var ages = [10, 15, 20, 25]

let response = []

ages.some(function (currentValue, index, ages) {
if (currentValue > ages[ages.length - index])
response.push(currentValue + ages.length)
})

console.log(response)
  • A: [20]
  • B: [20, 25]
  • C: [25, 29]
  • D: [29]
Ответ

Правильный ответ: D

Array.prototype.some() - это встроенная функция, позволяющая обрабатывать элементы массива с помощью колбека. Колбек в рассматриваемом примере имеет три параметра: currentValue (значение текущего элемента массива), index (индекс текущего элемента) и ages (сам массив). Метод some возвращает логическое значение. Выражение currentValue > ages[ages.length - index] возвращает true лишь один раз, поскольку речь идет о последнем элементе. Давайте рассмотрим код последовательно:

  1. 10 > ages[4 - 0]: поскольку ages[4] возвращает undefined, и 10 > undefined возвращает false, выполнение кода останавливается.
  2. 15 > ages[4 - 1]: поскольку ages[3] возвращает 25, условие является ложным.
  3. 20 > ages[4 - 2]: поскольку ages[2] возвращает 20, условие также не удовлетворяется.
  4. 25 > ages[4 - 3]: поскольку ages[1] возвращает 10, выражение возвращает true. Только это значение помещается в массив response. В массиве response содержится response.push(currentValue + ages.length) или 25 + ages.length, или 25 + 4, т.е. 29.

Вопрос № 222

const getString = (string, method = false) => {
if (method === true) {
return string.slice(1, 4).length
}

return string.substr(1, 4).length
}

console.log(getString("hello", true) + getString("hello"))
  • A: 6
  • B: 7
  • C: 8
  • D: 9
Ответ

Правильный ответ: B

getString - это стрелочная функция с двумя параметрами. Как видите, параметр method имеет значение по умолчанию, равное false. Если не передать другое значение при вызове функции или передать undefined, будет использовано значение по умолчанию. Основной вывод: разница между slice(1, 4), возвращающим 3, и substr(1, 4), возвращающим 4. console.log(getString('hello', true) + getString('hello')) или console.log(string.substr(1, 4).length + string.slice(1, 4).length), или console.log(4 + 3) выводит в консоль 7.

Вопрос № 223

class UserName {
name = "hello world"

getSlice(slice) {
return this.getName(slice).slice(true, this.name.length)
}

getName(space) {
return this.name.split(space)
}
}

UserName.prototype.split = function (argument) {
return this.getSlice(argument)
}

const a = new UserName()

console.log(a.split("").length)
  • A: NaN
  • B: true
  • C: 10
  • D: 11
Ответ

Правильный ответ: C

В рассматриваемом примере нет ничего необычного. Он намеренно запутан. У нас есть класс UserName с двумя методами и одним свойством. Мы добавляем к нему еще один метод - split, используя традиционный способ (через prototype). Помните, что class в JavaScript - это лишь синтаксический сахар для функции-конструктора (выражение typeof ClassName возвращает function). При вызове split(), мы передаем ему пустую строку. Данный метод вызывает другие методы. Порядок следующий: split("") -> this.getSlice("") -> this.getName("") -> this.name.split(""). Здесь split - это функция, преобразующая строку в массив. Обратите внимание, что в getSlice() мы используем slice(true, this.name.length) для модификации массива с 1 по 11 индексы. Длина нового массива составляет 10. Этот код помогает понять, как работают прототипы в JavaScript, а также увидеть разницу между встроенными и пользовательскими методами.

Вопрос № 224

function javaScript(node) {
let one = node.includes("I") ? " love " : " you "

return function (deno = one) {
let two = node.replace(deno, " done ")

return function (done = two) {
return (node + deno + done).length
}
}
}

console.log(javaScript("I love you")()())
  • A: 20
  • B: 26
  • C: 23
  • D: 25
Ответ

Правильный ответ: B

Кроме изучения некоторых встроенных функций для работы со строками, таких как replace и includes, здесь мы имеем дело с каррированием (currying). Обратите внимание, что только внешняя (основная) функция имеет название, внутренние функции являются анонимными. У нас также имеется три оператора return. При вызове функции необходимо использовать 3 пары круглых скобок - javaScript('I love you')()(). Мы не передаем аргументы вложенным функциям, поэтому они используют значения по умолчанию. Результирующим выражением является return (node + deno + done).length, где node - I love you, deno - love (2 пробела) и done - I done you. Длина получившейся строки I love you love I done you равняется 26. Пробелы принимаются в расчет.

Вопрос № 225

(function (flag) {
let age = Boolean(NaN === NaN ? false : flag)

console.log(age.toString()[Number(flag)])
})([])
  • A: "f"
  • B: "t"
  • C: true
  • D: false
Ответ

Правильный ответ: B

У нас имеется самовызывающаяся функция (IIFE) с пустым массивом в качестве аргумента. Обратите внимание, что сравнение NaN === NaN возвращает false, поэтому переменная age получает значение flag, т.е. пустой массив. Boolean([]) возвращает true. Функция toString возвращает строку true, а Number([]) - 0. Поэтому в консоль выводится t. Обратите внимание, что Boolean([]) === true, но Number([]) === 0, а NaN === NaN возвращает false.

Вопрос № 226

console.log(Boolean([]))
console.log(Number([]))
console.log(Number(Boolean([])))
console.log(Boolean(Number([])))

console.log(Boolean({}))
console.log(Number({}))
console.log(Number(Boolean({})))
console.log(Boolean(Number({})))

console.log(Boolean(new Boolean(false)))
  • A: true 0 1 false true 1 1 false false
  • B: true 0 1 false false NaN 1 false true
  • C: true 0 1 false false false 1 false false
  • D: true 0 1 false true NaN 1 false true
Ответ

Правильный ответ: D

JavaScript - это язык со слабой и динамической типизацией. Тип переменной в JS может меняться в зависимости от ее значения. При изменении одного значения на другое поведение JS может быть весьма неожиданным. Например, Number([]) возвращает 0, Number({}) - NaN, а Boolean([]) и Boolean({}) - true. Boolean(new Boolean(false)) возвращает true, несмотря на то, что мы передаем функции-конструктору Boolean значение false. Однако, если мы уберем ключевое слово new, то получим false. Boolean(new Boolean(false)) - это валидная с точки зрения JS операция, поэтому возвращается true. С другой стороны, Boolean(Boolean(false)) без ключевого слова new, возвращает false, поскольку значение false вообще не является операцией.

Вопрос № 227

const myYoutube = {
name: "username",
address: "youtube.com/username",
getInfo() {
return this
},
content: () => (this === window ? myYoutube.getInfo() : this),
}

console.log(myYoutube.content().name)
  • A: username
  • B: window
  • C: NaN
  • D: undefined
Ответ

Правильный ответ: A

Для того, чтобы правильно ответить на данный вопрос, нужно понимать концепцию this в JavaScript (в расматриваемом примере речь идет только о браузере). По умолчанию this указывает на глобальный объект window. Обратите внимание, что Window (с заглавной буквы) - это функция-конструктор объекта window. Поэтому console.log(this === window) возвращает true, а console.log(this === Window) - false. getInfo - это стрелочная функция, this, объявленный внутри этой функции, указывает на window, поэтому myYoutube.content() возвращает myYoutube.getInfo(). Обратите внимание, что нам пришлось явно писать myYoutube.getInfo() для того, чтобы код работал корректно, поскольку this не указывает на текущий объект. В функции getInfo this указывает на текущий объект, поскольку getInfo - это обычная функция. В итоге мы получаем username как значение свойства name.

Вопрос № 228

const myArray = [1, 2, 3]

myArray.someProperty = this

Array.prototype.someOtherProperty = "hello"

let result = []

for (let key in myArray) {
result.push(key)
}

for (let key in myArray) {
if (myArray.hasOwnProperty(key)) {
result.push(key)
}
}

console.log(result.length)
  • A: 10
  • B: NaN
  • C: 9
  • D: 7
Ответ

Правильный ответ: C

У нас имеется простой массив с тремя элементами. При проверке типа массива с помощью оператора typeof мы получаем object (для определения того, что значение является массивом, можно использовать Array.isArray(array) или array instanceof Array). При объявлении myArray.someProperty мы добавляем новое свойство к данному массиву. При объявлении Array.prototype.someProperty = 'hello', мы добавляем новое свойство ко всем массивам. Цикл for-in перебирает массив и возвращает пары ключ/значение, включая унаследованные свойства. На второй итерации мы используем метод hasOwnProperty, который перебирает только собственные (не унаследованные) ключи/значения. Если коротко, на первой итерации мы получаем 5 (3 исходных элемента, 1 собственное свойство и еще 1 унаследованное свойство). На второй - только 4 (унаследованное свойство не учитывается). Для перебора массива обычно используется цикл for-of или классический цикл for. Использование for-in для этого считается плохой практикой. for-in обычно используется для перебора объектов.

Вопрос № 229

const coderfarm = [1, 2, 3, 4, 5]

const [top, ...bottom] = (function (a) {
let result = a

a.unshift(new Array(3))

return result
})(coderfarm)

console.log(top.length + bottom.length)
  • A: 8
  • B: 9
  • C: 10
  • D: 11
Ответ

Правильный ответ: A

Здесь мы используем деструктуризацию для извлечения значений массива (или объекта) и spread-оператор (оператор распространения/распаковки). Деструктурируемый массив возвращается из самовызывающейся функции (IIFE). Сначала мы передаем аргумент codefarm (параметр a функции). Затем мы обновляем этот массив, добавляя в начало (посредством метода unshift) массив из трех undefined (с помощью new Array(3)). После этого массив выглядит так: [[undefined, undefined, undefined], 1, 2, 3, 4, 5]. Переменная top - это первый элемент массива или [undefined, undefined, undefined], длина которого равняется 3. Переменная bottom - это прочие элементы массива, ее длина равняется 5. В итоге мы получаем 3 + 5 или 8.

Вопрос № 230

let age = { number: 10 }

const getAge = (flag) => {
flag ? delete age.number : delete age
return age.number++
}

console.log(getAge(false))

console.log(age.number)

console.log(getAge(true))

console.log(age.number)
  • A: 10 10 NaN NaN
  • B: 10 10 undefined undefined
  • C: 10 11 undefined undefined
  • D: 10 11 NaN NaN
Ответ

Правильный ответ: D

Оператор delete удаляет свойство объекта, но не сам объект. У нас есть простая функция getAge с параметром flag. Если значением flag является true, выполняется код delete age.number, в противном случае, мы пытаемся удалить объект. Поскольку delete не может удалить объект, можно сказать, что delete age ничего не делает. Выражение console.log(getAge(false)) возвращает 10 и затем увеличивает значение age.number на 1. Данное значение хранится в памяти, поэтому console.log(age.number) возвращает 11. Когда мы присваиваем flag значение true, console.log(getAge(true)) выполняет код delete age.number, что удаляет свойство number объекта age. Это означает, что age.number равняется undefined. Однако, поскольку мы пытаемся увеличить значение этого свойства на 1 с помощью оператора ++, возвращается NaN.

Вопрос № 231

const f = function() {
this.x = 5;
(function() {
this.x = 3;
})();
console.log(this.x);
};

const obj = {
x: 4,
m: function() {
console.log(this.x);
},
};

f();
new f();
obj.m();
new obj.m();
f.call(f);
obj.m.call(f);
  • A: 3 5 4 undefined 5 5
  • B: 5 5 4 undefined 5 undefined
  • C: 3 3 undefined 4 undefined 4
  • D: 5 5 4 undefined 3 5
Ответ

Правильный ответ: A

При вызове функции f ее контекст (значение this) равняется window (в рассматриваемом примере речь идет только о браузере). Контекст самовызывающейся функции (IIFE) также равняется window, поэтому значением window.x становится 3. Когда функцию вызывают с ключевым словом new - создается новый объект, который становится контекстом функции (конструктора), но самовызывающаяся функция этот контекст не получает, поэтому второй раз в консоль выводится 5. Далее мы имеем дело с методом m объекта obj. Контекстом метода является объект, которому данный метод принадлежит. Значением свойства obj.x является 4, что и выводится в консоль. Однако, если вызвать тот же метод с помощью new, то для m будет создан новый контекст, в этом новом контексте x будет иметь значение undefined. Вызывая функцию f с помощью call(f), мы определяем, что контекст данной функции равен самой функции, т.е. this === f. Функция - это специальный вид объекта, которому, как и любому другому объекту, можно добавлять свойства. f.x равняется 5, что и выводится в консоль. Наконец, мы вызываем метод m с помощью call(f), т.е. this === f. После предыдущего вызова свойство f.x равняется 5, поэтому вместо undefined в консоль снова выводится 5.