4 февраля 2011 в 18:01

Блокировка видимости с помощью Let в JavaScript

Let — это такое ключевое слово с помощью которые мы можем определить переменную с ограниченной областью видимости, и эту область видимости мы можем ограничить аж четырьмя способами. Люди знающие OCaml сразу найдут параллель между let… in в Ocaml и let в JavaScript.
На хватит слов, давайте рассмотрим каждый способ применения let.



Включаем поддержку Let


Возможно у вас не получится сразу воспользоваться Let, но не огорчайтесь возможно Let заработает когда вы укажите type=«application/javascript;version=1.7» или вызовите version(170).

Область видимости для одного блока


С помощью let мы можем определить переменную видимой только в определенном блоке кода.
Синтаксис такого определения выглядит так
let(define vars){
some expression
}

А чтобы было понятней давайте рассмотрим простой пример. Пусть Bob живет в России и хочет купить DreamPlug он знает что в СНГ эта штучка будет стоит 300$, он отправляется в Европу чтобы купить подешевле, покупает и возвращается в Россию, и хвастается друзьям что у него есть комп из розетки и когда его спрашивают про цену он отвечает 300$.
Посмотреть данный пример
//Bob в России
dreamplug = new Object();
dreamplug.price = 300;
let(dreamplug.price = 150){
//Bob приехал в Европу
Bob.buy(dreamplug); // Bob покупает dream plug за 150$
}
//Bob вернулся в Россию
Bob.onmessage = function(event){
if(event.data == "Сколько стоил?")Bob.postmessage(price + "$",event.origin) //Когда Bob-а спрашивают он отвечает
}
//Данный пример заработает только если вы определите обьект Bob с методом buy
//И да, я выражаю человеческие разговоры через JavaScript


Область видимости для одного выражения



Практически тоже самое что и для блока но применяется к одному выражению(кто бы мог подумать). И соответственно не надо ставить фигурных скобок.
Для понятности рассмотрим пример с Bob-ом. Итак, наш Bob впал в детство и вспомнил то как он отвечал по признакам делимости у доски. Он отвечал по признаку делимости на два, кроме одного примера в котором надо было ответить по признаку делимости на 3.
Посмотреть данный пример
//Признак делимости на два
pred = function(x)!(x%2) //Предикат признака делимости на два
pred(3)
//Здесь я пропустил еще пару ответов Bob-a у доски
pred(2)
let(pred = function(x)!(x%3))pred(4) //Предикат признака делимости на три


Некоторые хабровчане (а именно те кто не знают что такое функциональный ЯП) наверняка заметили что тут мы определяли с помощью let не переменную, а функцию, но не забывайте что JS — функциональный ЯП, и функция является полноценным типом.

Let внутри цикла for


Мы также можем определит переменные с помощью let для цикла, единственным отличием от определения с помощью var будет то что переменная не будет в области видимости цикла и ничего кроме него.
Итак, пусть Bob пошел в магазин за покупками.
Посмотреть данный пример
list = ["msp430","avr","pic","msp430 Launch pad"] //Bob не тупой и у него есть список поупок
var i = 100; //Прсто Bob-у понравилось это число
for(let i=0;i<list.length;i++){
  Bob.buy(list[i]); //Bob купил вещь из списка
}
Bob.say('Мне нравится число ' + i) //100!!!


Let внутри блока



Мы можем определить с помощью let переменную внутри определенного блока. Отличием от определения let для блока кода будет в том что здесь начав определять переменную она станет undefined и только когда мы присвоим ей значение он станет не undefined. То есть например. Если Bob-а спросят квадрат его любимого числа, делать так нельзя.
Посмотреть данный пример
let i=100
{
let i = i * i
Bob.say(i) //NaN так как когда мы написали let i - мы определили i внутри блока i пока что undefined и при умножении undedined на undedined мы получили NaN
}


Но тем не менее можно делать вот так:
Посмотреть данный пример
let i=100
{
let m = i * i
Bob.say(m) 
}


Буду рад услышать замечания относительно статьи и адекватности.
@ArtemSmirnov
карма
245,0
рейтинг 0,0
Самое читаемое Разработка

Комментарии (28)

  • 0
    Где ещё почитать про синтаксис javascript;version=1.7 и область его применимости в браузерах?

    В FF3.6 заработал, а где ещё такая странная запись будет работать и каковы перспективы для неё?

    Впрочем, там работает и

    , что тоже не обычно. С какой это версии JS пошло и почему так не пишут, а обычно f = function(x){return x*x;}?
    • 0
      [Съедены теги:]
      В FF3.6 заработал
      <script type="application/javascript;version=1.7">let(f = function(x)(x*x))alert(f(4));</script>
      , а где ещё такая странная запись будет работать и каковы перспективы для неё?

      Впрочем, там работает и
      <script>
      f = function(x)(x*x);
      alert(f(4))
      </script>
      , что тоже не обычно. С какой это версии JS пошло и почему так не пишут, а обычно f = function(x){return x*x;}?
      • 0
        Такая запись функций пошла с 1,7 версии.
        Не пишут так потому что 1)Не все знают 2)Internet Explorer
        Основные перспективы использования let — это node.js
        Почитать про JavaScript можно на MDC
        Где работает с уверенностью сказать не могу но насколько я знаю IE8+, Chrome,FireFox (версии не указал так как пользователи этих браузеров обычно обновляют его) поддерживают 1.7 версию.
        • +3
          Нет, кроме лисы ни один популярный браузер не поддерживает.
        • –1
          В node.js let, array comprehensions и closure expression у меня не заработали =( Есть способ запустить?
          • +2
            В V8 нет let и поэтому его нет в Node.js
            let is a Mozilla extension, not part of any standard
            Аналогично с E4X (хотя он в стандарте)
            There are currently no plans for implementing E4X in V8
            Comparison_of_layout_engines_(ECMAScript)
    • +8
      Javascript — это имплементация стандарта ECMAscript корпорацией Mozilla. Следовательно, в других браузерах (вообще ни в одном, базирующемся на Webkit, Presto, Trident) поддержки let нету. Я как-то заводил баг в багтрекере V8 — там мне сказали то же самое «извините, но новые фичи не включим, пока они не будут в ecmascript».
      Ответвление Javascript, поддерживаемое мозиллой добавляет еще такие фичи:
      — Короткие анонимные функции
      Было: function(x) {return x * x}
      Стало: function(x) x * x
      — Генераторы, итераторы (__iterator__, next()) и, следовательно, yield statement, как в пытоне
      function fib() { // js 1.7
        var i = 0, j = 1;
        while (true) {
          yield i;
          var t = i;
          i = j;
          j += t;
        }
      }
      
      handleResults( i for ( i in obj ) if ( i > 3 ) ); // js 1.8
      


      — Списочные выражения (тоже из пытона)
      var ten_squares = [i * i for each (i in range(0, 10))];
      var evens = [i for each (i in range(0, 21)) if (i % 2 == 0)];
      

      — Destructing assignment
      var a = 1;
      var b = 3;
      [a, b] = [b, a];
      function f() {
        return [1, 2];
      }
      
      var c, d = f();
      
      • 0
        Ну тогда я пожалуй напишу компилятор данного подмножества JS в JS для V8, Preso,…
        • 0
          Было бы здорово, но как будет выглядеть тогда разработка? Будет что-то типа Coffeescript — пишешь код, компилируешь, вставляешь в js-файл и смотришь?
          • +1
            Две версии.
            1) Как Coffescript
            2) JIT с подключением extend.js
      • 0
        Маленькая поправочка, Webkit, Presto, Trident — это движки, которые рендерят НТМЛ. За джаваскрипт отвечает JS движок.

        Еще я бы добавил к вашему списку такую вещь:
        Object.__noSuchMethod__ — вызывается, если метод не существует. Ну вот почему именно этой фичи нет в V8, когда она так мне нужна в node.js -_-

  • 0
    Ссылка на работающий пример в вашей статье смотрелась бы как нельзя кстати.
    • 0
      Спасибо за совет, работающие примеры добавил.
  • 0
    Последний пример, скорее всего, с ошибкой. В том же FF сравните:
    <script type="application/javascript;version=1.7">
    let f = 1
    	{alert(f);} //вывод 1
    	alert(f); //вывод 1
    </script>
    

    и
    <script type="application/javascript;version=1.7">
    let(f = 1)
    	{alert(f);} //вывод 1
    	alert(f); //ошибка "f is not defined"
    </script>
    
    • 0
      Поясните пожалуйста в чем ошибка. Так как пробовал все из веб консоли FF 4.0 Beta 10 и все работало как я расписал.
    • 0
      Ограничение видимости работает именно во 2-м моём примере, когда после let — скобки. В первом случае оператор let, скорее всего, просто игнорируется. Ещё пример:
      <script type="application/javascript;version=1.7">
      let(f = 1)
      	alert(window.f); //undefined - правильно
      	alert(f); //ошибка "f is not defined" - тоже правильно
      </script>

      Поэтому Ваш пример
      let i=100
      {

      не сработает по ограничению видимости.
      • 0
        Т.е работать, конечно, будет, но i==100 останется и после фигурных скобок после блока.
        • 0
          Оно так и задумано.
          • 0
            А какое тогда отличие от просто
            i=100
            {

            ? Даже область видимости переменной i в этом случае — windows.
            • 0
              Вот именно что отличий нет, в том примере внешняя область видимости для кода в блоке не важна. Важно то что когда мы определяем внутри let i = i *i то сначала i становится undefined во внутренней области.
              а в let m = i * i мы определяем m а затем присваиваем m значения в результате умножения i*i из внешней области видимости.
    • –1
      Потому что в JavaScript областью видимости управляет только функция.
      Последний пример должен выглядеть так:

      let i=100;
      (function(){
      let i = i * i;
      Bob.say(i);
      })();
  • 0
    так можно писать с тех пор как вышел FF 2.0.
    Подробнее
  • 0
    если правильно понял, то в первом примере вместо
    Bob.postmessage("300$",event.origin)

    должно быть
    Bob.postmessage(price+"$",event.origin)
    • +1
      Да вы правильно поняли, спасибо, ошибку исправил.
  • +1
    а поямните первый пример
    в эту функцию вы прайс не передаете?
    Bob.buy('dream plug');
    т.е. эта фунция работает с глобальным объектом прайс
    то есть получается что let на время переопределяет глобальную переменную?
    • 0
      К сожалению тесты показали что не переопределяет, следовательно у меня ошибка в примере, сейчас я её исправлю.
  • 0
    Устарело. Теперь es6

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.