Skip to content

Instantly share code, notes, and snippets.

@YozhEzhi
Last active June 20, 2018 21:21
Show Gist options
  • Select an option

  • Save YozhEzhi/7b0b37804eb4089670dd6b4147eec347 to your computer and use it in GitHub Desktop.

Select an option

Save YozhEzhi/7b0b37804eb4089670dd6b4147eec347 to your computer and use it in GitHub Desktop.
JS частые вопросы.

Falsy и Truthy значения.

    truthy:
    if (true)
    if ({})
    if ([])
    if (42)
    if ("foo")
    if (new Date())

    falsy:
    if (false)
    if (null)
    if (undefined)
    if (0)
    if (NaN)
    if ('')
    if (document.all) [1]

Отличие примитивных типов данных от объектов.

Все типы данных в js выдут себя как объекты:

const greeting = 'hello';
greeting.length; => 5

In this case, behind the scenes, JS turns primitive data type into an object, runs the size method, and then transforms it back to the primitive data type.

Строгий режим выполнения кода.

По умолчанию новые фичи ES5 выключены, и код будет работать 'по-старому'. Для того, чтобы перевести код в режим полного соответствия современному стандарту, нужно указать "use strict". Эта директива не поддерживается IE9-.

Provides better security and stronger error checking. Strict mode helps out in a couple ways:

  • It catches some common coding bloopers, throwing exceptions.
  • It prevents, or throws errors, when relatively “unsafe” actions are taken (such as gaining access to the global object).
  • It disables features that are confusing or poorly thought out.

Замыкание (Closure).

Замыкание — это способность функции иметь доступ к внешним переменным, т.е. это связь. Closure is when a function 'remembers' its lexical scope even when the function is executing outside that lexical scope. Closures are useful in hiding the implementation of functionality while still revealing the interface.

Closures are frequently used in JavaScript for object data privacy, in event handlers and callback functions, and in partial applications, currying, and other functional programming patterns.

In JavaScript, closures are created every time a function is created, at function creation time.

При создании: любая функция получает скрытое свойство [[Scope]], которое ссылается на лексическое окружение, в котором она была создана. Благодаря наличию [[Scope]]: если переменная не найдена в функции – она будет искаться снаружи.

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

// EXAMPLE 1
function foo() {
  var bar = 'wassup!';

  function baz() {
    console.log(bar);
  }

  bam(baz);
}

function bam(baz) {
  // Prints `bar` - because `baz()` which is called inside `bam`'s lexical scope
  // has access to `bar` inside `foo()`.
  // Function `baz` pass as link to argument to `bam()`.
  baz(); // wassup!
}

foo();

// EXAMPLE 2
var dateUtil = {
  weekdayShort: (function () {
    var days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

    return function (x) {
      if ((x != parseInt(x)) || (x < 1) || (x > 7)) {
        throw new Error('Invalid weekday number');
      }

      return days[x - 1];
    };
  }())
};

console.log(dateUtil.weekdayShort(2)); // Tue

// EXAMPLE 3
// Classic way without memoizing:
var fibonacci = function (n) {
  return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
};

console.log(fibonacci(100)); // stack overflow!

// With memoizing:
var fibonacci = (function () {
  var memo = [0, 1]; // access via closure;

  var fib = function (n) {
    var result = memo[n];

    if (typeof result !== 'number') {
      result = fib(n - 1) + fib(n - 2);
      memo[n] = result;
    }

    return result;
  };

  return fib;
}());

console.log(fibonacci(100)); // 354224848179262000000

MDN

function declaration и function expression.

    // Function Declaration
    function sum(a, b) {
      return a + b;
    }

    // Function Expression
    var sum = function(a, b) {
      return a + b;
    }

Основное отличие между ними: функции, объявленные как Function Declaration, создаются интерпретатором до выполнения кода. Поэтому их можно вызвать до объявления.

Object.create() vs new operator.

    const instance = new FnClass();

Оператор new:

  • создаёт пустой объект.
  • устанавливает __proto__ ссылкой на prototype функции-класса, от которой был вызван оператор new: instance.__proto__ = FnClass.prototype;
  • применяет функцию-класс к нашему новосозданному объекту: constructorReturns = FnClass.apply(instance, arguments); т.е. исполняет функцию FnClass, передавая ей instance в качестве this и аргументы в виде псевдомассива arguments;
  • возвращает экземпляр функции-класса, но если FnClass нам вернул объект, тогда его: return constructorReturns instanceof Object ? constructorReturns : instance;

Метод Object.create() создаёт новый объект с указанными объектом прототипа и свойствами. Пример

Без него раньше пользовали:

    if (!Object.create) {
        Object.create = function(proto) {
            var Fn = function(){};
            Fn.prototype = proto;
            return new Fn;
        }
    }

this.

JS has 4 function invocation types: 1. function invocation: alert('Hello World!'); 2. method invocation: console.log('Hello World!'); 3. constructor invocation: new RegExp('\\d'); 4. indirect invocation: alert.call(undefined, 'Hello World!');

And each one defines its own context.

By default this is global object (Window) in a function invocation. But in strict mode - this equals undefined.

this in an inner function.

A common trap with the function invocation is thinking that this is the same in an inner function as in the outer function. To have the expected this, modify the inner function's context with indirect invocation (using .call() or .apply(), see 5.) or create a bound function (using .bind()).

When invoking a method on an object, this becomes the object itself.

Pitfall: separating method from its object A method from an object can be extracted into a separated variable. When calling the method using this variable, you might think that this is the object on which the method was defined. As was said we can use .bind() to deal with it.

this is the newly created object in a constructor invocation.

Don't forget to use new operator. Because without it - this will reffer to the Window.

this is the first argument of .bind() when invoking a bound function.

The role of .bind() is to create a new function, which invocation will have the context as the first argument passed to .bind(). It is a powerful technique that allows to create functions with a predefined this value. .bind() makes a permanent context link and will always keep it.

this in arrow function.

this is the enclosing context where the arrow function is defined. The arrow function doesn't create its own execution context, but takes this from the outer function where it is defined. An arrow function is bound with the lexical context once and forever. this cannot be modified even if using the context modification methods.

Цепочка прототипов (Prototype chain).

Объект — это коллекция свойств, имеющая также связанный с ней объект-прототип. Прототипом является либо также объект, или же значение null. Прототипом объекта является внутреннее свойство [[Prototype]].

var foo = {
    x: 10,
    y: 20
};

Для такого объекта мы имеем два явных свойства объекта и одно неявное (внутреннее) __proto__, которое является ссылкой на прототип объекта foo.

С помощью ссылки __proto__ образуется цепь прототипов. Цепь прерывается, если ссылка ссылается на null. Цепь прототипов - конечная цепь объектов, которая используется для организации наследования и разделяемых свойств.

Эти свойства объектов позволяют нам наследовать объекты и переиспользовать их повторно. В классовой системе это называется наследованием. В js наследование реализуется с помощью цепи прототипов (делегирующее наследование или прототипное наследование).

var a = {
  x: 10,
  calculate: function (z) {
    return this.x + this.y + z;
  }
};

var b = {
  y: 20,
  __proto__: a
};

var c = {
  y: 30,
  __proto__: a
};

// вызываем унаследованный метод
b.calculate(30); // 60
c.calculate(40); // 80

Если свойство или метод не найдены в самом объекте (т.е. объект не имеет такого родного свойства), то осуществляется попытка найти данное свойство или метод в цепи прототипов.

Значение this при использовании унаследованного метода установлено в оригинальный объект, но не в прототипный объект, в котором метод был найден.

Класс в js. Наследование класса.

Класс в общем — это разновидность абстрактного типа данных в ООП, характеризуемый способом своего построения. Суть отличия классов от других абстрактных типов данных состоит в том, что при задании типа данных класс определяет одновременно и интерфейс, и реализацию для всех своих экземпляров, а вызов метода-конструктора обязателен.

Под классами в JS подразумевают функции-конструкторы: функции, вызываемые при создании экземпляра с оператором new, со ссылкой на прототип — объект, содержащий свойства (данные) и методы (функции) класса. Пример 1, Пример 2

Если вы хотите унаследоваться от нескольких объектов, то это возможно сделать при помощи примесей. Функция примешивания должна копировать функции из прототипа суперкласса в прототип подкласса.

function MyClass() {
  SuperClass.call(this);
  OtherSuperClass.call(this);
}

MyClass.prototype = Object.create(SuperClass.prototype); // наследование
mixin(MyClass.prototype, OtherSuperClass.prototype); // примешивание

MyClass.prototype.myMethod = function() {
  // что-то делаем
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment