581.11K
Category: programmingprogramming

Исполняемый код и контекст исполнения в JS

1.

Исполняемый код и контекст
исполнения в JS
Дмитрий Нефедов
Старший программист группы систем электронной коммерции
Спортмастер Россия
mailto: [email protected]

2.

В JS нет магии :)
var a = 5;
function foo() {
console.log(a);
}
function bar() {
foo();
console.log(a);
var a = 6;
}
bar();

3.

Область видимости
Статическая область видимости:
Динамическая область видимости:
var x = 10;
x = 10;
function foo() {
console.log(x);
}
procedure foo()
print(x)
end
foo(); // 10
function bar() {
var x = 20;
console.log(x); // 20
foo(); // 10
}
bar();
foo() // 10
procedure bar()
x = 20
foo() // 20
end
bar()

4.

Лексическая область видимости
Спецификация, используемая для определения связи идентификаторов с конкретными
значениями и функциями;
Связано с синтаксической структурой кода, такой как FunctionDeclaration, BlockStatement,
Catch и TryStatement;
Состоит из записи окружения и ссылки на внешнее лексическое окружение;

5.

Пример:
var x = 10;
function foo() {
var y = 20;
}
globalEnvironment = {
environmentRecord: {
Object: function,
// etc ...
x: 10
},
outer: null
};
fooEnvironment = {
environmentRecord: {
y: 20
},
outer: globalEnvironment
};

6.

Пример:
function foo() {
var x = 10;
function bar() {
var y = 20;
console.log(x + y); // 30
}
function baz() {
var z = 30;
console.log(x + y); // 40
}
}
fooEnvironment = {
environmentRecord: {x: 10},
outer: globalEnvironment
};
barEnvironment = {
environmentRecord: {y: 20},
outer: fooEnvironment
};
bazEnvironment = {
environmentRecord: {z: 30},
outer: fooEnvironment
};

7.

Типы записей окружения
Декларативные записи
Каждая декларативная запись среды связана с областью программы ECMAScript,
содержащей объявления переменных, констант, let, class, module, import и / или функций.
Декларативная запись среды связывает набор идентификаторов, определенных объявлениями,
содержащимися в его области.)
Объектные записи
Запись объектной среды используется для определения связи переменных и функций,
появившихся в глобальном контексте и внутри with-операторов.

8.

Вид декларативной записи окружения
function foo(a) {
var b = 10;
function c() {}
}
environment = {
// storage
environmentRecord: {
type: "declarative",
a: <...>,
b: <...>,
c: <...>
},
// reference to the parent environment
outer: <...>
};

9.

Пример объектной записи окружения
var a = 10;
var b = 20;
with ({a: 30}) {
console.log(a + b); // 50
}
console.log(a + b); // 30, restored
context.lexicalEnv = {
environmentRecord: {a: 10, b: 20},
outer: null
};
previousEnv = context.lexicalEnv;
withEnv = {
environmentRecord: {a: 30},
outer: context.lexicalEnv
};
context.lexicalEnv = withEnv;
context.lexicalEnv = previousEnv;

10.

Контекст исполнения
This
Переменные компоненты среды
Лексические компоненты среды
ExecutionContext = {
ThisBinding: <this value>,
VariableEnvironment: { ... },
LexicalEnvironment: { ... },
}

11.

This
В глобальном контексте this - глобальный объект
Внутри контекста функции this определяется формой вызова функции
var foo = {
bar: function () {
console.log(this);
};
};
foo.bar();// "this" === "foo"
var bar = foo.bar;
bar();// "this" === global
this.bar();// "this" === global
bar.prototype.constructor();// "this" === "bar.prototype"
// --- non-Reference cases --(foo.bar = foo.bar)();// "this" === "global" or "undefined"
(foo.bar || foo.bar)();// "this" === "global" or "undefined"
(function () {this;})();//"this" === "global" || "undefined"

12.

Переменные компоненты среды
function foo(a) {
var b = 20;
}
foo(10);
fooContext.VariableEnvironment = {
environmentRecord: {
arguments: {0: 10, length: 1, callee: foo},
a: 10,
b: 20
},
outer: globalEnvironment
};

13.

Лексические компоненты среды
var a = 10;
foo.[[Scope]] = globalContext.[[VariableEnvironment]];
function foo() {console.log(a);}
// "with"
previousEnvironment =
globalContext.[[LexicalEnvironment]];
with ({a: 20}) {
var bar = function () {
console.log(a);
};
foo(); // 10, from VariableEnv
bar(); // 20, from LexicalEnv
}
foo(); // 10
bar(); // still 20
globalContext.[[LexicalEnvironment]] = {
environmentRecord: {a: 20},
outer: previousEnvironment
};
// "bar" is created
bar.[[Scope]] = globalContext.[[LexicalEnvironment]];
// "with" is completed, restore the environment
globalContext.[[LexicalEnvironment]] =
previousEnvironment;

14.

Инициализация идентификаторов
Процесс определения значения идентификатора, появившегося в контексте, с
использованием лексического компонента в текущем контексте выполнения
function resolveIdentifier(lexicalEnvironment, identifier) {
// если метод вызван из конечного окружения, переменной нет
if (lexicalEnvironment == null) {
throw ReferenceError(identifier + " is not defined");
}
// если значение найдено, возвращаем его Reference
if (lexicalEnvironment.hasBinding(identifier)) {
return new Reference(lexicalEnvironment, identifier);
}
return resolveIdentifier(lexicalEnvironment.outer, identifier);
}

15.

Пример
var a = 10;
(function foo() {
var b = 20;
(function bar() {
var c = 30;
console.log(a + b + c); // 60
})();
})();
resolveIdentifier(bar.[[LexicalEnvironment]], "a") ->
-- bar.[[LexicalEnvironment]] - not found,
-- bar.[[LexicalEnvironment]].outer ->
foo.[[LexicalEnvironment]]) -> not found
-- bar.[[LexicalEnvironment]].outer.outer ->
found reference, value 10

16.

Спасибо за внимание!
English     Русский Rules