update
This commit is contained in:
parent
962caebbb7
commit
87bf53d076
1825 changed files with 94929 additions and 0 deletions
90
1-js/5-functions-closures/3-scope-new-function/article.md
Normal file
90
1-js/5-functions-closures/3-scope-new-function/article.md
Normal file
|
@ -0,0 +1,90 @@
|
|||
# [[Scope]] для new Function
|
||||
|
||||
|
||||
## Присвоение [[Scope]] для new Function [#scope-Function]
|
||||
|
||||
Есть одно исключение из общего правила присвоения `[[Scope]]`, которое мы рассматривали в предыдущей главе.
|
||||
|
||||
**При создании функции с использованием `new Function`, её свойство `[[Scope]]` ссылается не на текущий `LexicalEnvironment`, а на `window`.**
|
||||
|
||||
## Пример
|
||||
|
||||
Следующий пример демонстрирует как функция, созданная `new Function`, игнорирует внешнюю переменную `a` и выводит глобальную вместо нее.
|
||||
|
||||
Сначала обычное поведение:
|
||||
|
||||
```js
|
||||
//+ run untrusted refresh
|
||||
var a = 1;
|
||||
function getFunc() {
|
||||
var a = 2;
|
||||
|
||||
*!*
|
||||
var func = function() { alert(a); };
|
||||
*/!*
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
getFunc()(); // *!*2*/!*, из LexicalEnvironment функции getFunc
|
||||
```
|
||||
|
||||
А теперь -- для функции, созданной через `new Function`:
|
||||
|
||||
```js
|
||||
//+ run untrusted refresh
|
||||
var a = 1;
|
||||
function getFunc() {
|
||||
var a = 2;
|
||||
|
||||
*!*
|
||||
var func = new Function('', 'alert(a)');
|
||||
*/!*
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
getFunc()(); // *!*1*/!*, из window
|
||||
```
|
||||
|
||||
## Почему так сделано?
|
||||
|
||||
[warn header="Продвинутые знания"]
|
||||
Содержимое этой секции содержит информацию теоретического характера, которая прямо сейчас не обязательна для дальнейшего изучения JavaScript.
|
||||
[/warn]
|
||||
|
||||
**Эта особенность `new Function`, хоть и выглядит странно, на самом деле весьма полезна.**
|
||||
|
||||
Представьте себе, что нам действительно нужно создать функцию из строки кода. Наверняка код этой функции неизвестен на момент написания скрипта (иначе зачем `new Function`), но станет известен позже, например получен с сервера или из других источников данных.
|
||||
|
||||
При выполнении кода на боевом сервере он наверняка сжат минификатором -- специальной программой, которая уменьшает размер кода, убирая из него лишние комментарии, пробелы, что очень важно -- переименовывает локальные переменные на более короткие.
|
||||
|
||||
То есть, обычно если внутри функции есть `var userName`, то минификатор заменит её на `var u` (или другую букву, чтобы не было конфликта), предполагая, что так как переменная видна только внутри функции, то этого всё равно никто не заметит, а код станет короче. И обычно проблем нет.
|
||||
|
||||
...Но если бы `new Function` могла обращаться к внешним переменным, то при попытке доступа к `userName` в сжатом коде была бы ошибка, так как минификатор переименовал её.
|
||||
|
||||
**Получается, что даже если бы мы захотели использовать локальные переменные в `new Function`, то после сжатия были бы проблемы, так как минификатор переименовывает локальные переменные.**
|
||||
|
||||
Описанная особенность `new Function` просто-таки спасает нас от ошибок.
|
||||
|
||||
Если внутри функции, создаваемой через `new Function`, всё же нужно использовать локальные переменные -- нужно всего лишь предусмотреть соответствующие параметры и передавать их явным образом, например так:
|
||||
|
||||
```js
|
||||
//+ run untrusted refresh
|
||||
*!*
|
||||
var sum = new Function('a, b', ' return a + b; ');
|
||||
*/!*
|
||||
|
||||
var a = 1, b = 2;
|
||||
|
||||
*!*
|
||||
alert( sum(a, b) ); // 3
|
||||
*/!*
|
||||
```
|
||||
|
||||
## Итого
|
||||
|
||||
<ul>
|
||||
<li>Функции, создаваемые через `new Function`, имеют значением `[[Scope]]` не внешний объект переменных, а `window`.</li>
|
||||
<li>Следствие -- такие функции не могут использовать замыкание. Но это хорошо, так как бережёт от ошибок проектирования, да и при сжатии JavaScript проблем не будет. Если же внешние переменные реально нужны -- их можно передать в качестве параметров.</li>
|
||||
</ul>
|
Loading…
Add table
Add a link
Reference in a new issue