Возможные вопросы на собеседованиях по JS (часть 1)

Часть 1

26

Возможные вопросы по JS

Типы данных в JS. Приведение типов.

6 примитивных и объект
* Boolean
* Null
* Undefined
* Number
* String
* Symbol
* Object

Приведение типов в js делится на:
* Строковое — при предоставлении чего либо в виде строки 😃
* Численное — в математических выражениях
* Логическое — приведение к true, false.

3 типа преобразований
1. String() — приведение к строке в строковом контексте
2. Number() — приведение к примитиву в численном контекстеб включая унарный плюс. Происходитпри сравнении разных типов
3. Boolean() — приведение к логическому типу в логическом контексте

Случай #1
Сравнение числа со строчкой

При сравнении строки с числом, всегда строка преобразуется в число. Если строка не может преобразоваться в число, то получаем NaN

99 == "hello"
99 == NaN // false

Случай #2
Сравнение булевского значения с любым другим типом

В этом случае булевское значение преобразуется в число. true преобразуется в 1, а false в 0.

1 == true
1 == 1 //true
//---
"1" == true
"1" == 1
1 == 1 //true

Случай №3
Сравнение null с undefined

Сравнение этих значений дает true.

undefined == null

Строгое Сравнение

Два значения считаются строго равными только в том случае, если они относятся к одному типу и содержат одно значение.

Пустые значения: 0, undefined, null, NaN, пустая строка.

undefined и null равны только друг другу, но не равны всему остальному.

Но при этом при строгом сравнении, они друг другу не равны

null == null //true
undefined == undefined //true
undefined == null //true
undefined === null //false

Еще забава с null

null > 0 //false
null < 0 //false
null == 0 //false
null >= 0 //true
null > 0 || null == 0 //false

Пример

const bool = new Boolean(false);
if (bool) console.log(bool); //true
if (bool == false) console.log(bool); //true

В первом случае, потому что возвращает объект. А во втором случае, потому что в контексте сравнения вызвалось через valueof и вернуло примитив.

Объекты приводятся к примитивам с помощью методов valueOf и toString

Преобразование объекта

Отличие null и undefined

  • null чаще всего используется там, где объект еще не создан или не найден. Используется для представления несуществующих объектов.
  • undefined — для неинициализированных переменных, отсутствующих свойств объектов или отсутствующих значений в массивах.

isNaN — polyfill

if(!Number.isNaN) {
  Number.isNaN = function(n) {
    return n !== n;
  }
}

Копирование объектов

1й способ

var newObject = JSON.parse(JSON.stringify(oldObject));

2й способ

var clone = {}; 
for (var key in user) {
  clone[key] = user[key];
}

Let vs var vs const

Главные отличия:

  1. Let и const не поднимаются к началу блока
  2. Ограничены скоупом блока в котором объявлены
  3. Повторное объявление let и const недопустимо (не считая когда let объявляется в другом блоке). При этом не важно как была переменная объявлена до этого через var, let или const
  4. const невозможно изменить после инициализации
  5. Объявление const не позволяет изменить привязку, но не значение. Т.е. спокойно можно изменять содержимое объекта или массива
  6. Временная мертвая зона не позволит проверить переменную, даже через typeof если проверка происходит до объявления. Однако если мы проверим переменную вне блока где она объявлена, то typeof отработает нормально
if(condition) {
  console.log(typeof value); //reference error
  let value = "blue";
}

// А так сработает

console.log(typeof value); //"undefined"
if(condition) {
  let value = "blue";
}
  1. Блочные привязки полезны в циклах, так как переменные существуют только внутри циклов
  2. Теперь не надо вызывать IIFE для того чтобы передать каждой функции новое значение в цикле, так как при каждой итерации переменные объявляются заново.
  3. Вышесказанное верно и для for-in и for-of
  4. Константа объявленная через cons вызовет ошибку при попытке использовать её в цикле for уже после первой итерации, однако отработает при for-in или for-of если не пытаться её изменить
  5. Объявления переменных в глобальной области видимости через var создавало свойство в объекте window что могло затереть существуещее свойство, а объявление через let или const создают новые привязки в глобальной области видимости, но не добавляют свойства в глобальный объект. Т.е. последние не затрут глобальную переменную, а замаскируют её.

**//============== Как было **


var func = []; for(var i = 0; i < 10; i++) { funcs.push((function(value){ return function() { console.log(value); } })(i)); } funcs.forEach(function(func) { func(); //Выведет 0,1,2,3 ...,9 })

**///============== Как стало **

var funcs = [];
for(let i = 0; i < 10; i++) {
  func.push(function(){
    console.log(i);
  });
}

func.forEach(function(func){
  func(); // 0,1,2,3 ...,9
});

Передача данных по ссылке и по значению. Примеры.

Обычные значения: строки, числа, булевы значения, null/undefined при присваивании переменных копируются целиком (по значению)

А вот объеты передается ссылка, т.к. в переменной, которой присвоен объект, хранится не сам объект, а его адрес в памяти, ссылка на него.

Какие JS движки вы знаете?

  • Google V8
  • Rhino
  • SpiderMonkey

Что такое this?

this определяет контекст выполнения.

Контекст выполнения — можно представить это как: обертка, коробка, контейнер, который сохраняет переменные и в котором кусочки нашего кода оцениваются и выполняются.

По умолчанию контекстом выполнения является — глобальный контекст:
* Код который вне всякой функции
* Мы можем ассоциировать контекст с объектом
* В браузерах (объект window).

При выполнении в функциях, контекст выполнения перемещается в эти функции
execution context

Контекст выполнения можно ассоциировать с объектом, которые содержит некоторые основные переменные:
* Variable Object(VO) — который содержит аргументы функции, объявленные переменные, а также функции объявленные через function declaration.
* Scope chain — который содержит текущие доступные объекты, такие как переменные объекты всех его родителей.
* И переменная this

Когда функция вызывается, новый контекст выполнения попадает на верх стэка выполнения (execution stack). И это делится на две фазы:
1. Фаза создания
* Создается объект переменных
* Создается цепочка областей видимости
* Определяется значение перменной this
2. Фаза выполнения
* Код функции, которая сгенерировала текущий контекст выполнения выполняется строчка за строчкой.

execution context details

Variable Object
* Создается объект аргументов, который содержит все аргументы, которые были переданные в функцию
* Код сканируется на наличие function declaration: для каждой функции создается свойство в VO, указывающее на эту функцию. Это означает, что все такие функции будут сохранены внутри VO
* Код сканируется на наличие variable declaration: для каждой переменной, создается свойство в VO, и устанавливается значение undefined

Последние два пункта можно определить как hoisting, когда функции и переменные поднимаются в начало кода.

Переменная this это такая переменная, которую получает каждый контекст выполнения. И сохраняется в объекте контекста выполнения (который также хранит: variable object (VO), Scope chain)

В глобальном контексте выполнения, за пределами каких либо фукнций, this ссылается на глобальный объект вне зависимости от использования в строгом или нестрогом режиме

Итак, куда же ведет переменная this?

  • При обычном вызове функции: this указывает на глобальный объект (в браузере — window)
  • При вызове метода: this указывает на объект, который вызвал этот метода

Переменной this не присваевается значение до тех пор, пока функция, в которой она определена, фактически вызвана

Правила привязки this
Правила для определения this по точке вызова функции можно определить в порядки их приоритета.
1. Привязка new: Функция вызвана с newthis — новый сконструированный объект

var bar = new foo();
  1. Явная привязка: Функция вызывана с call или apply, даже скрыто внутри жесткой привязки bind. В этом случае this — явно указанный объект
var bar = foo.call(obj2);
  1. Неявная привязка — функция вызвана с контекстом, иначе называемым как владеющий или содержащий объект. В этом случае this — является этим объектом контекста
var bar = obj1.foo();
  1. Привязка по умолчанию: в ином случае будет this по умолчанию. В режиме strict mode это будет undefined, иначе будет объект global
var bar = foo();

Вместо 4х стандартных правил привязки, стрелочные функции ES6 используют лексическую область видимости для привязки this, что означает что они заимствуют привязку this от вызова своей окружающей функции. Они являются заменой self = this

console.log(this.document === document); //true
console.log(this === window); //true
this.a = 37;
console.log(window.a); //37

В контексте функций, значение this зависит от того, каким образом вызвана функция.

Что происходит при вызове new

Когда функция вызывается с указанной перед ней new, также известный как вызов конструктора, автоматически выполняются следующие вещи:
1. Создается новый объект (конструируется) прямо из воздуха
2. Только что *сконструированный объект связывается с [[Прототипом]]
3. Только что сконструированный объект устанавливается как привязка this для этого вызова функции
4. За исключением тех случаев, когда функция возвращает свой собственный альтернативный объект, вызов функции с new автоматически вернет только что сконструированный объект

new polyfill

function nouveau (Constructor, ...args) {
    const instance = Object.create(Constructor.prototype);
    const result = Constructor.apply(instance, args);
    return result === Object(result) ? result : instance;
  }

Object.create() polyfill

  function object (o) {
    function F () {}
    F.prototype = o;
    return new F();
}

Реализовать функцию sum(2)(39)(2)(5)()

  function sum(a) {

  var currentSum = a;

  function f(b) {
    currentSum += b;
    return f;
  }

  f.toString = function() {
    return currentSum;
  };

  return f;
}

alert( sum(1)(2) ); // 3
alert( sum(5)(-1)(2) ); // 6
alert( sum(6)(-1)(-2)(-3) ); // 0
alert( sum(0)(1)(2)(3)(4)(5) ); // 15

Стили программирования в JS

  • динамический
  • ООП
  • императивный
  • функциональный

Function.prototype.bind polyfill

Можно считать простым декоратором

function bind(func, context) {
  return function() {
    return func.apply(context, arguments);
  };
}

Вызов bind(func, context) возвращает обёртку, которая ставит this и передает основную работу функции func.

You might also like More from author

Leave A Reply

Your email address will not be published.