Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Обработка двойных () (https://javascript.ru/forum/misc/61442-obrabotka-dvojjnykh.html)

kaban4ig 18.02.2016 15:28

Обработка двойных ()
 
var global = (function () {
				return this || (1, eval)('this');
			}());

Подскажите как обрабатывается код такого вида.

(1, eval)('this')

Octane 19.02.2016 00:05

Сначала посмотрим на такой пример:
var x = 0;

(function () {
    var x = 1;

    eval('alert(x)'); // 1
    (1, eval)('alert(x)'); // 0

}());
∙ Для кода, выполненного через просто eval(…), доступен скоп текущей функции, поэтому берется значение локальной переменной x.
∙ Для кода, выполненного через (1, eval)(…), доступен только глобальный скоп, поэтому берется значение глобальной переменной x.

Чтобы понять, почему так происходит, рассмотрим обычный метод объекта:
var obj = {
    method: function () {
        return this;
    }
};

var method = obj.method;

alert(obj.method() === obj) // true
alert(method() === window) // true
Как видим, когда вызываем метод через аксессор obj.method, то объектом активации функции становится сам obj и this является ссылкой на него.
А когда мы вызываем метод по прямой ссылке, то его объектом активации становится глобальный контекст, в случае браузерного JS – это window, и this в этом случае является ссылкой на window.

Вернемся к eval:
(1, eval)
Это обычное выражение, результатом которого является ссылка на функцию eval. Возвращается последнее значение после запятой. Но как можно заметить в обычном вызове eval(…) тоже нет объекта активации. Это особенность функции eval, объектом активации для нее является текущий скоп. Как оно там внутри реализовано мы не знаем, но можем представить происходящее следующим псевдокодом:
var x = 0;

function eval(code) {
    with (this) {
        return (function () {

            return // результат выполнения code

        }).call(this.context);
    }
}

globalScope → {
    x: 0,
    eval: eval,
    context: window
}

(function () {
    var x = 1;

    localScope → {
        x: 1,
        eval: eval,
        context: window
    }

    localScope.eval('alert(x)'); // 1
    
    globalScope.eval('alert(x)'); // 0

}());
Трюк (1, eval) отвязывает функцию eval от локального скопа. Не обязательно писать (1, eval), можно как во втором примере получить ссылку на функцию:
var x = 0;

(function () {
    var x = 1;

    eval('alert(x)'); // 1

    var globalEval = eval;
    globalEval('alert(x)'); // 0

}());
Эффект будет такой же.

Соответственно в твоем примере (1, eval)('this') используется для получения глобального контекста.
Такую запись можно заменить на new Function('return this')().


Часовой пояс GMT +3, время: 06:59.