Закрытие и это — два довольно часто встречающихся тестовых сайта, но задумывались ли вы когда-нибудь, что они на самом деле связаны с одним и тем же пунктом знаний?
Пожалуйста, наш главный герой этой статьи, контекст исполнения
контекст выполнения
каков контекст выполнения
Нетрудно понять, что контекст выполнения — это среда, в которой выполняется js-код, его состав следующий
executionContextObj = {
this: 对的就是你关注的那个this,
VO:变量对象,
scopeChain: 作用域链,跟闭包相关
}
Поскольку JS является однопоточным, одновременно может происходить только одно действие, остальные будут поставлены в очередь в указанном стеке контекста. Когда интерпретатор js инициализирует исполняемый код, он создает в стеке глобальный контекст выполнения, а затем при каждом вызове функции создает и помещает в стек новый контекст выполнения. После выполнения функции контекст выполнения извлекается.
Пять ключевых моментов:
- один поток
- Синхронное выполнение
- глобальный контекст
- Неограниченный контекст функции
- Создает новый контекст для каждого вызова функции, включая сам вызов
Скорость установления контекста выполнения
создать сцену
- Инициализировать цепочку областей видимости
- Создать переменный объект
- создавать аргументы
- Декларация функции сканирования
- Сканировать объявления переменных
- спроси это
этап выполнения
- Инициализировать ссылки на переменные и функции
- выполнить код
this
Когда функция выполняется, это всегда относится к объекту, вызвавшему функцию. Чтобы определить смысл этого, на самом деле нужно определить, кому принадлежит эта функция.
указать на вызывающий объект
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
указывает на глобальный объект
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
Уведомление
//接上
var bar = foo
a = 3
bar() // 3不是2
На этом примере вы можете лучше понять, что это определяется только при вызове функции
пройтись еще немного
function foo() {
console.log( this.a );
}
function doFoo(fn) {
this.a = 4
fn();
}
var obj = {
a: 2,
foo: foo
};
var a =3
doFoo( obj.foo ); // 4
а также
function foo() {
this.a = 1
console.log( this.a );
}
function doFoo(fn) {
this.a = 4
fn();
}
var obj = {
a: 2,
foo: foo
};
var a =3
doFoo( obj.foo ); // 1
Почему это? Это потому, что набор a в foo читается первым, подобно принципу области действия?
Напечатав this для foo и doFoo, вы можете узнать, что их this указывает на окно, и их операции изменят значение a в окне. Дело не в том, что набор a в foo читается первым
Итак, если вы измените код на
function foo() {
setTimeout(() => this.a = 1,0)
console.log( this.a );
}
function doFoo(fn) {
this.a = 4
fn();
}
var obj = {
a: 2,
foo: foo
};
var a =3
doFoo( obj.foo ); // 4
setTimeout(obj.foo,0) // 1
Приведенные выше результаты кода могут подтвердить наше предположение.
Построение с новыми точками к новому объекту
a = 4
function A() {
this.a = 3
this.callA = function() {
console.log(this.a)
}
}
A() // 返回undefined, A().callA会报错。callA被保存在window上
var a = new A()
a.callA() // 3,callA在new A返回的对象里
apply/call/bind
function foo() {
console.log( this.a );
}
var obj = {
a: 2
};
foo.call( obj ); // 2
//bind返回一个新的函数
function foo(something) {
console.log( this.a, something );
return this.a + something;
}
var obj =
a: 2
};
var bar = foo.bind( obj );
var b = bar( 3 ); // 2 3
console.log( b ); // 5
стрелочная функция
Стрелочные функции особенные, у них нет своего this, они используют this значение включающего контекста выполнения (функции или глобального).
var x=11;
var obj={
x:22,
say:()=>{
console.log(this.x); //this指向window
}
}
obj.say();// 11
obj.say.call({x:13}) // 11
x = 14
obj.say() // 14
//对比一下
var obj2={
x:22,
say() {
console.log(this.x); //this指向window
}
}
obj2.say();// 22
obj2.say.call({x:13}) // 13
функция прослушивания событий
указывает на связанный элемент dom
document.body.addEventListener('click',function(){
console.log(this)
}
)
// 点击网页
// <body>...</body>
HTML
В атрибутах тегов HTML можно написать JS, в данном случае это относится к элементу HTML.
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
переменный объект
Объект переменной — это область данных, связанная с контекстом выполнения, в котором хранятся объявления переменных и функций, определенные в контексте.
Переменный объект — это абстрактное понятие, которое представляет разные объекты в разных контекстах.
Переменный объект глобального контекста выполнения
В глобальном контексте выполнения переменный объект является глобальным объектом.
В коде js верхнего уровня this указывает на глобальный объект, а глобальные переменные запрашиваются как свойства объекта. В браузерах окно является глобальным объектом.
var a = 1
console.log(window.a) // 1
console.log(this.1) // 1
Переменный объект контекста выполнения функции
В контексте функции переменный объект VO является активным объектом AO.
При инициализации со свойством arguments.
Код функции выполняется в два этапа
-
При входе в контекст выполнения
На данный момент переменный объект включает- формальный параметр
- Объявление функции, которая заменит существующий объект переменной
- Объявления переменных, без подстановки параметров и функций
-
выполнение функции
Измените значение объекта переменной в соответствии с кодом
Например
function test (a,c) {
console.log(a, b, c, d) // 5 undefined [Function: c] undefined
var b = 3;
a = 4
function c () {
}
var d = function () {
}
console.log(a, b, c, d) // 4 3 [Function: c] [Function: d]
var c = 5
console.log(a, b, c, d) // 4 3 5 [Function: d]
}
test(5,6)
анализировать процесс
1. При создании контекста выполнения
VO = {
arguments: {0:5},
a: 5,
b: undefined,
c: [Function], //Функция C переопределяет параметр c, но объявление переменной c не может переопределять объявление функции c
d: undefined, // выражение функции не поднимается, оно не определено до выполнения соответствующего оператора
}
- при выполнении кода
Через финальную консоль можно узнать, что объявление функции может быть перезаписано
цепочка прицелов
Сначала узнайте о роли
объем
Доступная область переменных и функций управляет видимостью и временем жизни переменных и функций. Делится на глобальную область действия и локальную область действия.
Глобальный охват:
Объекты, к которым можно получить доступ в любом месте кода, имеют глобальную область действия и включают следующее:
-
переменные, определенные на самом внешнем уровне;
-
Свойства глобального объекта
-
Переменные, которые неявно определены где-либо (переменные, которые не присваиваются напрямую), и переменные, которые неявно определены где-либо, определяются в глобальной области видимости, то есть переменные, которые присваиваются напрямую без объявления var.
Локальная область:
Область действия JavaScript определяется функциями. Переменные, определенные в функции, видны только внутри функции, которая называется функциональной (локальной) областью видимости.
цепочка прицелов
Цепочка областей действия — это список объектов, используемых для получения идентификаторов, которые появляются в коде контекста.
Под идентификаторами можно понимать имена переменных, параметры, объявления функций.
Когда функция определена, набор объектов переменного объекта родителей AO / VO хранится во внутреннем свойстве [[Scope]], который называется цепью области.
Свободные переменные — это переменные, которые не объявлены внутри функции.
Когда функции требуется доступ к свободной переменной, она следует по цепочке областей видимости, чтобы найти данные.
function foo() {
function bar() {
...
}
}
foo.[[scope]] = [
globalContext.VO
];
bar.[[scope]] = [
fooContext.AO,
globalContext.VO
];
Когда функция активирована, она сначала скопирует атрибут [[scope]] для создания цепочки областей видимости, затем создаст переменный объект VO, а затем добавит его в цепочку областей видимости.
executionContextObj: {
VO:{},
scopeChain: [VO, [[scope]]]
}
Закрытие
Что такое закрытие
Замыкание определяется mdn как функция, которая может обращаться к свободным переменным. Свободные переменные, как упоминалось ранее, относятся к переменным, которые не объявлены внутри функции.
форма закрытия
function a() {
var num = 1
function b() {
console.log(num++)
}
return b
}
var c1 = a()
c1() // '1'
c1() // '2'
var c2 = a()
c2() // '1'
c2() // '2'
закрытый процесс
Не очень строго написано. Некоторые процессы могут быть опущены
- запустить функцию а
- Создайте VO функции a, включая переменную num и функцию b
- При определении функции b переменный объект VO и глобальный переменный объект a будут сохранены в [[scope]]
- Функция возврата b, сохранение в c1
- запустить с1
- Создайте цепочку областей действия c1, которая содержит переменный объект VO объекта a.
- Создать озвучку для с1
- Запустив c1, обнаруживается, что требуется доступ к переменной num, которая не существует в текущем VO, поэтому доступ к ней осуществляется через цепочку областей видимости, и найдено num, сохраненное в VO a, и значение num устанавливается на 2.
- Снова запустите c1, повторите операцию второго шага и установите значение num равным 3.
некоторые проблемы
Из приведенных выше результатов выполнения мы можем заметить, что переменная num, к которой обращается c2, не является той же самой переменной, что и переменная num, к которой обращается c1. Мы можем изменить код, чтобы подтвердить нашу гипотезу
function a() {
var x = {y : 4}
function b() {
return x
}
return b
}
var c1 = a()
var c2 = a()
c1 === c2() // false
Поэтому мы можем быть уверены, что переменные, к которым обращается замыкание, воссоздаются каждый раз при запуске родительской функции независимо друг от друга.
Обратите внимание, что свободные переменные, созданные в одной и той же функции, могут быть общими для разных замыканий.
function a() {
var x = 0
function b() {
console.log(x++)
}
function c() {
console.log(x++)
}
return {
b,
c
}
}
var r = a()
r.b() // 0
r.c() // 1
наконец
Статья относительно длинная и охватывает широкий спектр.Ошибок может быть много.Надеюсь вы меня поправите.
Эта статьяПередовая продвинутая сериячасть,
Добро пожаловать, чтобы следовать иstarэтот блог или следуйте за мнойgithub
Ссылаться на
- Глубокое понимание этого в стрелочных функциях ES6
- Сводка JS, о которой вы не знали
- Углубленный стек контекста выполнения JavaScript
- Понимание цепочки областей видимости JavaScript
- Углубленный объект переменной JavaScript
- Глубокое понимание серии JavaScript (12): переменные объекты (переменная объект)
- Понимание контекста выполнения JavaScript