2013-09-25 3 views
2

Недавно я обнаружил with в javascript для выполнения блока с объектом в качестве текущей области. Мне любопытно, есть ли какая-то маска javascript, чтобы сделать то же самое с функцией и назвать ее в другой области.Изменение области действия функции

Пример:

var scope = { foo: 'bar' }, 
    foo = 'baz'; 

function func(){ 
    return foo; 
} 

with(scope){ 
    foo; // foo is 'bar' 
    func(); // foo is still 'baz' 
} 

В примере, with изменяет объем переменной foo, но функция все еще использует сферу за пределами with, где она была определена. Любые предложения о том, как изменить или отменить область действия функции?

+3

Просто FYI: _ "Использование с утверждением не рекомендуется, так как это может быть источником запутанных ошибок и проблемы совместимости. [...] Использование с не рекомендуется и запрещено в строгом режиме ECMAScript 5. «_ - [MDN] (https://developer.mozilla.org/en-US/docs/Web/ JavaScript/Справка/Заявления/с). – elclanrs

ответ

0

Короче - ДА

С является особенным, он делает dynamic binding. Это создает запутывающие ошибки, поэтому операторы with не запускаются в strict mode.

Однако никто не сказал, что мы не можем немного повеселиться. Мы не можем изменить переменные замыкания, которые имеет функция, однако мы можем использовать динамическую природу JavaScript для чтения исходного кода функции и создания новой привязки. Это не основной язык или общий, но для случая, который вы попросили, это, безусловно, выполнимо.

Вот образец для самого базового дела, который вы задали (без вложенных замыканий, без параметров и т. Д.). Хотя вы не можете изменить закрытие, вы можете объявить новую функцию, которая выполняет тот же код другой.Позвольте мне сделать одно совершенно ясно - это грязный хак здесь;)

var scope = {foo: 'bar'}, 
      foo = 'baz'; 


var func = function func() { 
    return foo; 
} 
// here, `foo` is closed over by the outer foo and it is 'baz' 

document.body.innerHTML += " " + func(); // foo is still 'baz' 

// foo is bar, since it's a different function here: 
document.body.innerHTML += " " + withFunc({foo:"bar"},func); 

function withFunc(obj, func) { 
    //declare a new function 
    return new Function("obj", // with a parameter obj 
      "with(obj){\n " + // do `with` on that parameter 
      "return "+func+"()\n}")(obj); // invoke and return original function 
} 

http://jsfiddle.net/42YX4/

+0

Спасибо! Это именно то, что я искал. Я подумал, что на самом деле это плохая идея. Было любопытно, возможно ли это. Я полностью забыл о конструкторе функций, это отличное решение. – Huston

2

Короче - NO

С является особенным, он делает dynamic binding. Это создает путаные ошибки, поэтому операторы with не запускаются в strict mode.

Функция в вашем случае closes overfoo. Как только функция объявлена, нет способа изменить то, что foo ссылается на нее.


Если мы должны быть точными:

Раздел 10.4.3 спецификации языка описывает «Ввод кода функции», интересная вещь здесь:

Пусть localEnv быть результатом вызова NewDeclarativeEnvironment передаёт значение внутреннего свойства F [[Scope]] в качестве аргумента.

Это происходит после того, как мы нарисовали this и до того, как мы установили область действия localEnv, которую мы только что нашли. Теперь что это такое [[Scope]]?

[[Область применения]] - Лексическая среда - лексическая среда, определяющая среду, в которой выполняется объект Function. Из стандартных встроенных объектов ECMAScript реализуются только объекты функции [[Область]].

Это означает, что сфера применения функции определяется заранее, а не на основе динамического контекста :)

+0

Связанный и интересный, но устаревший и, конечно же, не являющийся частью языка - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/Parent –

+0

Интересно, что "это" устанавливается перед областью. Учитывая, что «это» легко модифицируется приложением/вызовом, я бы ожидал, что область будет установлена ​​первой, так как она статична. Спасибо за подробное объяснение! – Huston

Смежные вопросы