Как стать автором
Обновить

Комментарии 38

Очень неплохая статья, так держать!

Можно было бы еще добавить определение хойстинга/hoisting, т.к. оно также играет важную роль. Так, например, что будет выведено в консоль в след.ситуации:

var func = function() { console.log('1'); };
function func() { console.log('2'); }
func();


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

Также можно было бы упямонуть про ES6 let, которая напрямую затрагивает тему данной статьи.
Перевод же…
Хорошая статья для начинающих, но странно, что в конце 2013 года автор совсем не затронул let и его влияние на области видимости.

UPD: Черт, выше уже написали про let.
Рано его еще использовать. В частности v8 еще не умеет оптимизировать функции с let (возможно ситуация изменится с запуском TurboFan). Что влечет в свою очередь примерно x20 кратную потерю производительности, что порой критично. Да и вообще меня не покидает ощущение, что классы и let — это эдакий популизм. В отличии от реально нужных генераторов и ES7 async/await, argument pattern'ов и destructuring assignment (который, к сожалению, в v8 еще не родили, хотя использовать его с генераторами самое оно).
Понравилось, спасибо. Вроде и ничего нового, но зато всё по делу.
Хотя у меня на практике обычно по простому
var Module= {
    mothod1 : function() {
	
    },
    mothod2 : function() {
		
    },
    mothod3 : function() {
		
    }
}
Отличная статья, но есть неточность: в первом примере — это не всегда так.

В ноде это будет объявлено в глобальной области, однако в браузере — не в глобальной, а внутри области window.
Глобальная область в браузере доступна примерно так: name = 'Todo';
var name = 'Todo'; // Локальная ОВ
globalName = 'Todo'; // Глобальная ОВ (покуда без var)

Не могу придумать пример, когда это важно, но раз уж статья об областях видимости…
Неверующим
console.log(this); // > Window
НЛО прилетело и опубликовало эту надпись здесь
В браузере? Будет text:

mySuperVar = 'text';
typeof(window.mySuperVar); //string
window.mySuperVar; //text
console.log(window.mySuperVar); //undefined
// actual result: text 
НЛО прилетело и опубликовало эту надпись здесь
Я думаю, имеется ввиду, что если это писать в консоли, то вывод будет примерно такой:
var myVar = "text";
console.log(window.myVar);
> undefined
> "text"

Покуда сам метод console.log() ничего не возвращает, то сначала печатается undefined, а потом уже переменная.
НЛО прилетело и опубликовало эту надпись здесь
переменная всегда попадает в тек.контекст, соотв. не важно с var или без, она будет доступна из window:

var x = 'xxx';
y = 'yyy';
console.log(window.x); // 'xxx'
console.log(window.y); // 'yyy'
НЛО прилетело и опубликовало эту надпись здесь
Как раз таки наоборот:

var myVar = "text";
console.log(window.myVar);
> text
> undefined
НЛО прилетело и опубликовало эту надпись здесь
Я сначала не понял, о чём вы. Я подумал, что console.log(window.mySuperVar) выводит undefined

на самом деле undefined — это не вывод, а возврат функции console.log
НЛО прилетело и опубликовало эту надпись здесь
function a() {
  console.log(1);
  return 2;
}
a();


Вывод:
1 2

здесь уже нет никакого undefined. Здесь 1 — вывод console.log(1), а 2 — возврат функции a
В обеих ситуациях это считается глобальной областью: this в браузере это window, в nodejs — переменная определяемая системой.
Этот загадочный js…

Тут подумал — если мы используем iframe, то до него можно достучаться через window.frames[0].variable; Следовательно, в iframe это все-таки будет локальный контекст по сравнению с родительским. Хотя даже без var он наружу не бросает. Хитрый js однако. К слову, в статье про области видимости как раз это можно было и раскрыть.

ОФФТОП. (Да, поведу себя как ребенок, но раньше об этом не задумывался)
Тут меня осенил гениальный план, как можно воровать личные данные: делаете на своем сайте iframe на чужой сайт, он там открывается, а мы имеем доступ к нему. Хм, я подумал — слишком простая и очевидная схема, и правда — vk так не открылся. Но не сложно догадаться, что виной этому хедер — X-iframe-options: deny. Полез лазить по интернету. Крупные сайты предусмотрели этот заголовок, но из более мелких (всякие интернет-магазины самописные, а так же всякие самописные бложики) спокойно открываются через iframe почти все. Браузер safari. Хм, печально, товарищи.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Хм. Это все хорошо. И это логично. Но попробовал у себя на локальном файле через file:// — и, к моему удивлению, сработало. У меня был полный доступ к открывшейся странице. Удивленный, полез воспроизводить это на jsfiddle. Но там не сработало. Странное поведение.
Хм. В Safari 8.0 этот файл отрабатывает без проблем, если его открывать как file://. На мой взгляд, это может быть достаточно большой дыркой.
Скрытый текст
<!DOCTYPE html>
<html>
<head>
</head>
<script>
var k = 3;
l = 5;
var load = function()
{
 window.frames[0].$('body').click(function() { alert('Алерт'); });
}
</script>

<body>
<iframe onload="load()" src="http://raal100.narod.ru" width='500' height='500'></iframe>
</body></html>

вот так надо:

window.frames[0].contentWindow.variable


просматривайте, какими свойствами обладает объект, в данном случае объект window.frames[0], и да пребудет с вами сила

И ещё: во фрейме должен быть загружен страница того же домена или поддомена.

если во фрейме загружен поддомен, то в нём должно быть запущена строчка document.domain = "<домен родительского окна>".
Каждая ОВ назначает своё значение переменной “this”

Это не совсем верно. this это свойство контекста выполнения (execution context), а не области видимости (scope).
например,
var b = 1;
function a() {
    console.log('scope b:', b);
    console.log('this b:', this.b);
    // здесь небольшая магия, в es6, если не указано явно, this будет null,
    // в es5 - глобальный объект
}
a();
a.call({b:2});
что обозначает ключевое слово this, и как оно относится с ОВ?


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

Помимо функций, есть ещё один способ манипуляции с ОВ. Вы его знаете, но вам говорили никогда им не пользоваться в продакшне (и в общем-то правильно). Это оператор with. Он использует существующий объект в качестве ОВ.

Рассмотрим такой код:

(function(){
  var that = 42;
  with({
    "that": "foo",
    "this": "bar"
  }){
    console.log(that);
    console.log(this);
  }
})();


Первый консоль-лог выведет «foo». Переменная that, конечно, объявлена и равна 42, но это во внешней ОВ. Во внутренней есть своя переменная that, и она затеняет («shadowing») переменную из внешней ОВ. Несмотря на экзотический оператор, поведение вполне привычное.

А вот второй консоль-лог выведет глобальный объект. Во внутренней ОВ есть переменная под именем «this», но она не затенила this. Единственное логичное объяснение — при разрешении значения this механизм ОВ не используется. А сам this — это ключевое слово, а не переменная, и ни в какой области видимости переменных не находится, точно так же, как и ключевые слова null, true или false.

Ещё раз уточню, это упрёк автору статьи, а не переводчику. Переводчику только похвала, за хороший перевод.
Поддерживаю. Согласен что this это не переменная. Это ссылка на саму локальную область видимости. Почему нельзя так сказать?
Это ссылка на саму локальную область видимости. Почему нельзя так сказать?

да потому что this только по умолчанию указывает на локальную область видимости, и this можно менять вызовами apply, call, bind
Да нет же, this вообще не указывает на локальную область видимости. Вот, товарищ m1el даже уже продемонстрировал это.

Видимо, вас сбила с толку фраза «Каждая ОВ назначает своё значение переменной “this”,..»
В оригинале она гласит: «Each scope binds a different value of this,..»
Т.е, «Каждая… своё значение» тут в смысле «каждый раз разное значение».
Статья неплохая для начинающих, но не полная, либо автор сам не знает, либо не удосужился написать про то, что значения переменных в функциях при ее выполнении инициализируются сразу же как undefined не зависимо есть ли эти переменные в глобальной области или родительской.
Ох уж эти переводы. Почему обязательно «переводить» название языка как яваскрипт, но при этом писать this, call, return, а не это, вызов, вернуть?
потому что this и call, return — зарезервированные слова. И как бы понимать, что что имелось в виду под словом «вызов» — call или apply трудновато.
(ворчу) Вот начитаются сейчас про scope, наизучают js, а потом начинают писать подобное:

[].forEach.call($$("*"),function(a){a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)})
Есть ощущение, что автор не программировал с применением ООП, и инкапсуляцию описывает как чудо света.

Интересный поворот в том, что внутри одной ОВ все функции имеют доступ к любым другим, поэтому из публичных методов мы можем вызывать приватные, которые в глобальной ОВ недоступны


Вот так поворот! Если приватные методы нельзя вызывать в публичных, их польза близка к нулю.

Но вообще достаточно неплохая статья, одна из лучших на тему.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации