LINUX.ORG.RU

Истиный смысл var.

 


1

1

Начал тут разбираться с js, и обнаружил на разных бложеках уйму холливаров по поводу использования var.

Как известно, в js считается плохим тоном не использовать var везде, в том числе и в глобальной области. Только вот почему ее там (в глобальной) надо использовать, похоже мало кто знает, мож скрывают, хз.

То, что переменная объявленная без var не имеет (скрытого) св-тва DontDelete, и (похоже) переменная c var (конкретно в ноде) не копируется в глобальный объект - это ситуацию до конца не проясняет, потому что остается вопрос, если это все не имеет значения для конкретного кода, почему бы не забить.

Я поковырялся с этим вопросом, и вот что выяснил.

Оказывается, в ноде можно подключать модули не только стандартным require, но и простым eval-read. Вот тут, как раз-таки, и проявляется настоящая причина. Если мы «подключим» наш «модуль» внутри ф-ции, то пер-нные из «модуля» без вар сразу бухаются в глобальный скоп.

Допустим, у нас два файла: основной и модуль.

модуль(пусть будет tst):

a=1
var b=2;
основной:
read=function(file){return require("fs").readFileSync(file, "ascii")}

tst=function(){eval(read("./tst")); console.log(a, b)};
tst()// 1 2
console.log(global.a, global.b)// 1 undefined
Вот так усе просто. Выдавливаем по каплям матрицу.:)



Последнее исправление: anonimous (всего исправлений: 1)

нода - нодой. Это же не эталлонное реализация языка.

visual ★★★
()

Везде одни вопросы «как же работает js», у вас формальной спецификации, человеческим языком написанной нету, или это отраслевая особенность у веб-программистов?

arturpub ★★
()
Ответ на: комментарий от arturpub

ТС познает мир.

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

Kalashnikov ★★★
()
Ответ на: комментарий от Kalashnikov

Ну это в любом языке

много хитрых или уникальных штук как те же whatever

Насколько я понимаю из оп-поста, var это способ локализации переменной в скопе, а окружений в js либо нет, либо при require их не трудится создавать (если этого нет в мане по реквайру, то должно быть во введении в скопинг и модули).

Непонятно только что за повод эти внезапные откровения изливать в свой личный бложек^W^W^W^W на ЛОР :)

arturpub ★★
()
Ответ на: комментарий от arturpub

require - это исключительно костыль нода, в языке этого нет. Притом этот костыль нормально разруливает глобальные области видимости насколько я понял. ТС же берёт эвал и удивляется что тот работает по стандарту.

Kalashnikov ★★★
()
Ответ на: комментарий от Kalashnikov

Ничего он не разруливает, на тестах нелокальные сеты проваливаются до глобального скопа, независимо от места require, как и ожидалось. eval судя по всему патчит скоп в рантайме, отсюда и видимость после него. Уж если чему и удивляться, то этому.

http://stackoverflow.com/questions/9781285/specify-scope-for-eval-in-javascript

arturpub ★★
()

Без var нод разработчики обычно делают труЪ глобальные вещи, которые не хотят реквайрить, например config. Но следят за тем чтобы оно было инстанциировано в первых строках app.js

vertexua ★★★★★
()
Ответ на: комментарий от Kalashnikov

Так и не понял о чём ты.

Я о том, что var вообще в глобальной области нах не нужен, если не нужно магии с DontDelite/delete и нодовским глобал. Просто часто читая статьи по JS, замечал такую фигню, что авторы делают из var какой-то культ из var, часто встречается фраза «хорошим тоном является ставить var везде при объявлении...» Я показал случай, где это действительно может иметь реальное значение. Видимо отсюда и растут корни этого требования. Для меня это было неочевидно раньше, вот и все. Может кому-то еще из новичков будет интересно.

Точка с запятой тоже не имеет значения, забивай и на неё.

тащемта, я и так забиваю, но не всегда:


tst=function(x){return x}
a=tst
;(function(){return 1})()
console.log(a)
//-->[Function]

tst=function(x){return x}
a=tst
(function(){return 1})()
console.log(a)
//-->1

anonimous
() автор топика
Ответ на: комментарий от Kalashnikov

хитрых или уникальных штук как те же var

Прототипы для меня, пока, действительно, хитры пока. Но в свете того, что я написал, с var для меня все абсолютно ясно. И не было никакого смысла вводить в strict mode это нелепое ограничение на запрет объявления переменной без var, это глупость просто. Если знать, как var паботает, никаких проблем с этим никогда не возникнет. А эти мудаки поставили телегу впереди лошади, как всегда. Только вносят лишнюю путаницу.

anonimous
() автор топика
Ответ на: комментарий от blan4

Спасибо, но я вроде с этим разобрался уже. Щас к прототипам подбираюсь.

anonimous
() автор топика
Ответ на: комментарий от blan4

Про области видимости и var

Кста, по вашей ссылке, по-мойму, бред, например:

Также JavaScript не различает пространств имён

И тут же:

Каждый раз, когда JavaScript обнаруживает ссылку на переменную, он будет искать её всё выше и выше по областям видимости

То ли автор, не владеет русским, то ли это неудачная паста. Ща по ходу чтения дальше буду критиковать

anonimous
() автор топика
Ответ на: комментарий от blan4

Скрипт A определяет переменную по имени foo в глобальной области видимости, а скрипт B определяет foo в текущей области видимости.

Тут же, опять, то ли корявый язык, то ли тотальное непонимание. Они оба определяют в глобальной. Разница в другом. См. топик.

anonimous
() автор топика
Ответ на: комментарий от blan4

Повторимся, это совсем не тот же самый эффект. Если вы не используете var — то вы в большой опасности.

var foo = 42;
function test() {
    // локальная область видимости
    foo = 21;
}
test();
foo; // 21

Опять ахинея, здесь смысл в том, что он переопределяет пер-нную (присваивает) в глобальной области, а не определяет локальную переменную.

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

anonimous
() автор топика
Ответ на: комментарий от Vit

Вообще-то require это какбэ часть CommonJS

А вы не подскажете, зачем он вообще нужен этот костыль? Ведь он делает практически то же самое, что eval/read, только оборачивает все в объект, насколько я понял. Это и так легко сделать. Нахрена они плодят левые, нах ненужные сущности, нахера засирать и без того уже напрочь засранный язык?

anonimous
() автор топика

Вот так усе просто.

Ватсон, всё еще проще. Нормальные люди пишут в начале кода 'use strict'. А еще пользуются линтовщиком (jshint для ноды).

Начните что-нибудь реальное писать, а то больно смотреть на очередной вопрос из серии «почему не стоит стрелять в ногу, если их всё равно две».

Vit ★★★★★
()

а NodeJs понимает «use strict»?

если да, то какой смысл не использовать «use strict»?

если нет, то печалька :-(

user_id_68054 ★★★★★
()
Ответ на: комментарий от Vit

Нормальные люди пишут в начале кода 'use strict'

Они кастрируют муттабельные замыкания?

А как-же они пишут код типа:


mkCounter=function(start){return function(){return start=start+1}}

counter1=mkCounter(1)
counter2=mkCounter(10)

console.log(counter1())
console.log(counter1())
console.log(counter1())
console.log(counter2())
2
3
4
11

anonimous
() автор топика
Ответ на: комментарий от anonimous

Ну в жизни встречаются люди, которые не насилуют яваскрипт, а пишут на нем что-то реальное, сложнее хелловорда. Этим людям нужна система модулей. Чтобы использовать чужой код.

Vit ★★★★★
()
Ответ на: комментарий от anonimous

Они кастрируют муттабельные замыкания?

Почему бы не поставить 'use strict' в начало своего кода и не проверить?

Vit ★★★★★
()
Ответ на: комментарий от Vit

Вы имеете в виду интерпрайз? Я не программист, поэтому не имею возможности. Но для себя скрипты пишу иногда, в целях обучения, и с некоторой пользой. И не вижу, кстати, причин превращать мощнейший язык в очередной си плас плас. Он уже есть.

anonimous
() автор топика
Ответ на: комментарий от Vit

Почему бы не поставить 'use strict' в начало своего кода и не проверить?

Работает. А как же это сочетается с запрещением переменных без var? Получается, use strict распространяется только на ту область, где объявляется, в данном случае, на глобальную, так чтоле?

anonimous
() автор топика
Ответ на: комментарий от anonimous

У меня опенсорсные проекты. Лично для себя вы можете писать вообще как угодно, даже махровый говнокод никому кроме вас не доставит проблем.

Vit ★★★★★
()
Ответ на: комментарий от anonimous
var foo;

fooo = 5;

console.log(foo);



В имени переменной опечатка. При обязательном использовании var это ловится автоматически. Линтом вообще ловится больше половины ошибок.

Если выдрючиваться только потому, что JS позволяет, вы просто потратите на разработку заметно больше времени. А времени всегда мало.

Vit ★★★★★
()
Последнее исправление: Vit (всего исправлений: 2)
Ответ на: комментарий от Vit

А, я понял, извиняюсь, я просто думал, что при use strict вообще запрещены присваивания, а на самом деле она запрещает только присваивание для ранее необъявленных переменных:


"use strict"

var a=false
var tst=function(){a=1}
tst()
console.log(a)

Ну тогда еще ниче, но все равно, не всегда удобно.

anonimous
() автор топика
Ответ на: комментарий от Vit

Ясно. А ведь насколько я понимаю, в ноде переменные с вар не копируются в глобальный объект? Если так, как же проверить, например, существует ли та или иная переменная, вроде


a=1
b=2
var c=3

for(var i in global){console.log(i)}

a
b

anonimous
() автор топика
Ответ на: комментарий от anonimous
var a;
...
if (global.a === undefined) { ... }
...
if (a === undefined) { ... }
Vit ★★★★★
()
Последнее исправление: Vit (всего исправлений: 1)
Ответ на: комментарий от user_id_68054

Да, понимает. Но печали особо нет. Я им пока не пользуюсь, и особого профита не вижу.

anonimous
() автор топика
Ответ на: комментарий от Vit

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

tst={
a: 1,
b: function(){}
}

, а подключались вот так:

tst=eval(read("./tst"))
Все было бы то же самое, только все прозрачно. И донести до любого программиста, даже полного дебила, что модули надо заворачивать в объекты не составило бы никакого труда.

anonimous
() автор топика
Ответ на: комментарий от anonimous

Кроме того, что реквайр знает стандартные пути (это мелочь на самом деле), он еще кеширует загруженные модули, и при следующем реквайре вернется уже готовый объект. Чем это отличается от каждоразового eval-read, кроме скорости, это тебе задачка на подумать.

anonymous
()
Ответ на: комментарий от arturpub

а окружений в js либо нет

С чего Вы взяли?

либо при require их не трудится создавать

Это очень легко cделать, вы ищите проблемы там где их нет.

tst=function(){var fs=require("fs"); return fs.readFile}

console.log(tst) // --> [Function]
console.log(fs) // --> err
console.log(readFile)// --> err

изливать в свой личный бложек

Потому что я нуб и в ходе обсуждения многие вещи легче усваиваются:)

anonimous
() автор топика
Ответ на: комментарий от anonymous

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

anonimous
() автор топика
Ответ на: комментарий от anonimous

Ты вообще про скопинг выше по треду читал? Модуль это функция, которая при загрузке выполняется и само выполнение замыкает var'ы на функции, а глобальные просто сетит. Никогда ничего никуда не копируется, ни в ноде, ни где еще. После загрузки модуля ты видишь результат его исполнения, и все. Ты мог в модуле экспортировать функцию, которая делает d = 4, как думаешь, когда d «скопируется» в глобальный объект?

anonymous
()
Ответ на: комментарий от anonimous

Вопрос в отличии кроме скорости :)

anonymous
()
Ответ на: комментарий от anonimous

Я не ищу проблемы, я не вижу упоминания окружений в документации. Если модуль fs из таоего примера сетит глобалы, то он их посетит и в первый раз, и в другие разы при eval read. Покажи реальную изоляцию и я поверю в окружения в js ;)

anonymous
()
Ответ на: комментарий от anonimous

Увы, какая-то сволочь уже успела до вас, и донесла, что за eval надо сразу нахер посылать.

Вы определитесь, что вам нужнее - узнать как пишут или своими фантазиями на тему яваскрипта пофонтанировать. Если пофонтанировать - дык мы вас все дружно похвалим, и еще таких же советов дадим.

Vit ★★★★★
()
Ответ на: комментарий от anonymous

Никогда ничего никуда не копируется, ни в ноде, ни где еще.

В браузерах, насколько я знаю, все глобальные переменные копируются в глобальный объект.

anonimous
() автор топика
Ответ на: комментарий от Vit

Внезапно, eval это единственное, что бывает под капотом реквайра, суть дискуссии лежит на уровне eval'а, и его отсюда не выкинуть.

anonymous
()
Ответ на: комментарий от anonymous

Если модуль fs из таоего примера сетит глобалы

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

anonimous
() автор топика
Ответ на: комментарий от Vit

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

anonimous
() автор топика
Ответ на: комментарий от anonimous

В этом корень непонимания твоего. Давай еще раз, по пунктам. Есть текст модуля в файле. Вот он «загружается». Что это вообще значит? Допустим в тексте было a = 1; var b = 2. Текст парсится и превращается в байт-код. Байт-код это функция, то есть мы получили из текста функцию, но еще ее не вызывали. Пока во всех конеткстах, в т.ч. глобальном все по-прежнему. Но давай сначала посмотрим что это за байт-код такой? Там три микрокоманды. Первая — установить символ А в 1. Вторая — создать локальный символ Б. Третья — установить символ Б в 2. Что произойдет, если эту функцию вызвать? Да как обычно все с функциями происходит: символ А нелокальный, поэтому сет провалится в глобальный объект (это твой момент «копирования», который просто А = 1, а никакое не копирование). Второй сет останется внутри, т.к. есть одноименная локальная переменная. Фишка в том, что евал эти два шага — парсинг в байт-код и вызов — схлопывает в один, но суть остается та же: ты просто вызвал функцию, которая модуль. Ты просто function () { ... } вокруг не писал, это евал за тебя сделал (не совсем так, но для понимания сойдет).

anonymous
()
Ответ на: комментарий от anonymous

То что под капотом рекваера можно почитать в CommonJS. Это интерфейс системы модулей, который можно реализовать разными способами. Например, если собирать код под браузер через browserify, то ни каких eval-ов там не будет.

Vit ★★★★★
()
Ответ на: комментарий от anonimous

То ли я чо-то не понимаю, то ли ты не тестишь свои высказывания.

// fs.js
a=1
var b=2

А теперь запусти свой код чуть выше и проверь есть ли a в глобалах.

anonymous
()
Ответ на: комментарий от anonymous

Если модуль fs из таоего примера сетит глобалы

tst=function(){var fs=require("fs"); return fs.readFile}

console.log(tst()) // --> [Function]
console.log(fs) // --> err
console.log(readFile)// --> err

Пардон, я вызвать ф-цию забыл во второй строке. Суть этого примера в том, что при вызове ф-ции tst она ищет имена из модуля в своем скопе. Последние 2 строки показывают, что в глобальном окружении эти имена отсутствуют. При их вызове интерпретатор валится, что обозначено «err».

anonimous
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.