8 posts tagged

javascript

# 92. Переменные в javascript

Переменные – это та вещь, которая упрощает работу программиста. Конечно, при большом желании можно обойтись и без переменных, вычисляя на лету нужные значения и передавая их в поток выполнения, но это особый способ писать код.

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

В javascript’е есть пара ключевых слов, чтобы объявить переменную: var и let. На собеседованиях очень любят спрашивать про var, потому что в нём больше подводных камней. Так, например, переменная объявленная через var “поднимается” (по англ. hoisting) по вашему блоку кода (функции в общем случае) к его началу. Посмотрим на следующий код:

function foo() {
    if (!hoisted) {
        console.log('defined undefined');
    }

    var hoisted = true;
}

foo();

Хотелось, чтобы в рантайме было выброшено исключение о том, что переменной hoisted не существует, но этого не произойдёт – переменная будет объявлена и ей присвоится значение undefined.

Если бы мы объявили hoisted с помощью let, то получили бы, как надо, reference error – hoisted is not defined.

Теперь немного усложним:

function foo() {
    if (!hoisted) {
        console.log('defined undefined');
    }

    hoisted = true;
}

foo();

Внезапно этот код много где может отработать, несмотря на то, что hoisted никогда не определяется. Всё потому, что при выполнении кода, такая запись будет рассматриваться интерпретатором как присвоение значения свойству (некоторого объекта). Чтобы определить какому, мы бежим по scope chain до самого корня, не находим это поле в нашей цепочке и создаём его в глобальном объекте, который равен window. Если бы нашли, то присвоили бы найденной переменной значение.

Кроме прочего, объявление переменной без var не позволит сборщику мусора удалить выделенную под неё память, ведь она будет полем объекта, а объект всё ещё нужен для работы.

Всё будет иначе (и, пожалуй, как надо), если сделать так:

'use strict';

function foo() {
    if (!hoisted) {
        console.log('defined undefined');
    }

   hoisted = true;
}

foo();

Замечаем небольшое изменение – ‘use strict’. Эта директива включает особый режим языка, в котором такие вольности не позволяются и будет выброшена ошибка ReferenceError.

А вот задачка:

function foo() {
    if (false) {
        var hoisted = true;
    }

    console.log(hoisted); // что случится в этом месте?
}

foo();

Предлагаю подумать, каким будет вывод и только потом читать следующий параграф.

Если бы мы использовали let, то вывод, как мы обсуждали раньше, привёл бы к ошибке ReferenceError. Здесь же получится, что мы объявили переменную, она всплыла до вершины блока (в данном случае к началу функции foo) и была инициализирована значением undefined.

И под конец, задачка на понимание. Лучше не забивать код сразу в консоль, а попробовать устно проговорить каждый из выводов, исправить при необходимости код и продолжать. Задачка с реального собеседования в одной из очень хороших российских компаний.

'use strict';

x = 5;

console.log(++x);
console.log(x++);

function test() {
    console.log(x);

    x += 10;

    console.log(x);
    console.log(typeof x);

    var x = 15;
    console.log(x);
}

test();
console.log(x);

Интересные ссылки:

  1. https://www.ecma-international.org/ecma-262/8.0/index.html#sec-variable-statement
  2. stackoverflow
 No comments   2018   javascript

#65. Angularjs и тоска

Нормальные пацаны начинают изучение с примерчика. Внимательно читая, можно найти следующие строки и, конечно, ими воспользоваться, ты ж новичок:

Most of the files in your working directory come from the angular-seed project which is typically used to bootstrap new Angular projects.

Используется для новых проектов? Отлично, мне подходит. Разворачиваю свой проект. Дальше читаю доки и вижу:

Мы не дураки, кликаем «View Source» чуть выше на всякий, ищем нужную нам функцию и видим:

this.otherwise = function(params) {
    if (typeof params === 'string') {
      params = {redirectTo: params};
    }
    this.when(null, params);
    return this;
};

Всё очевидно, кидаем строчку с адресом страницы, на которую будет редирект и хвала! Но не тут-то было! Ничего не работает. В консоли ошибка с кучей барахла. Что делать, всё же по-науке было решено!
Оказывается, жопа кроется в деталях:

"dependencies": {
    "angular": "1.2.x",
    "angular-route": "1.2.x",
    "angular-loader": "1.2.x",
    "angular-mocks": "~1.2.x",
    "html5-boilerplate": "~4.3.0"
  }

Это код подгрузки зависимостей в пустом проекте. А код, на который ссылается документация, уже новый (и про особенность нигде не указано).

Идём смотреть пулреквесты в этом angular-seed:

Зависимости, оказывается, старые и уже с октября никто не спешит мержить в основную ветку эти исправления. А стоило бы, потому что на начальном этапе хочется, чтобы загрузил всё рекомендуемое, “копи-паст из документации” и работает.

 No comments   2015   javascript

#44. Как не надо...

Сегодня рассказ о том, как не надо делать. Вот так, совершенно точно, не надо:

if ($('#tabBtns').attr('class').indexOf('forBiz') > -1)

#42. Progress Events

Нашёл в стандартах такую интересную штуку. В редакторах, кстати, до 2010 года был Яндекс. Суть заключается в контролировании загрузки, например, какого-нибудь файла или чего-нибудь ещё при помощи XMLHttpRequest.
Эта штука позволяет без особых ухищрений, стандартными средствами, делать дорожки загрузок или просто бегущие процентики с использованием пары строк кода. При этом отражать эти элементы будут реальную ситуацию с загрузкой, а не вымышленные прогресс, который образуется с помощью readystate.
Вот пример кода из документации:

var progressBar = document.getElementById("p");
var client = new XMLHttpRequest();
client.open("GET", "magical-unicorns");
client.onprogress = function(pe) {
	if(pe.lengthComputable) {
		progressBar.max = pe.total;
		progressBar.value = pe.loaded;
	}
}
client.onloadend = function(pe) {
	progressBar.value = pe.loaded;
}
client.send();

Посмотреть как это работает можно здесь

А вот здесь можно несколько подробнее про это почитать (собственно, стандарт):
Progress Event

 No comments   2014   javascript

#14

Никак не удаётся провести итоговое тестирование календарика. Как только оттестирую, так сразу напишу что-нибудь о нём. А пока уже другая задача стоит – запилить график. Не просто график, а крутой график. Нашёл пару интересных, думаю возьму за основу, разберусь, а там либо допилю, либо сделаю свой. Вот, к примеру, как хочется, чтоб он выглядел

Этот график рисует Chart.js

 No comments   2013   javascript   график

#13

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

 No comments   2013   javascript   jquery   календарь

#11

Хотим получить разницу между датами в полных годах в javascript? Делаем так

var now = new Date(); // дата до которой считаем
var bdate = new Date('1991-11-19'); // дата от
var d = now - bdate; 
var r = new Date(0); 
r.setMilliseconds(d); 
var old = r.getFullYear() - 1970; // вычитаем 1970 лет 
// (количество лет, создаваемых по умолчанию 
// в new Date(0))

С помощью denisx

 No comments   2013   javascript   памятки

#9

Интересная штука получается. Раньше, чтобы повесить событие на ещё не существующий элемент, надо было написать

$('.selector').live(function () {});

Теперь такая простая и удобная штука не работает. Теперь нужно использовать метод .on, который, как оказалось, сложнее в понимании.
Даже если использовать документацию и написать так

$('.selector').on('mouseenter', function() {})

функция не выполнится, когда вы от неё этого будете ожидать. Задница кроется в том, что теперь .selector – это обёртка. Вы можете вешать на неё, но только если она уже есть в dom’e.
Если у вас на странице пока не существует элемента, на который вы хотите повесить функцию, то придётся писать так

$('.selector').on('mouseenter', '.element', function () {})

Как вам такой синтаксис? Мне, например, не очень.
На досуге надо будет покапаться в фреймворке, разобраться почему так получается и для чего так сделали.

P.S. В документации это объясняется тем, что события всплывают от низа к верху, поэтому когда мы кликаем на элементе, который появился после инициализации, событие всплывает до элемента, к которому было привязано событие через .on и на нём срабатывает. Это помогает избежать чересчур частых биндов/анбиндов событий на элементах, которые появляются динамически.

 No comments   2013   javascript   jquery