Вы можете передать его через IIFE :
let x = 5;
const p = (x => new Promise((resolve, reject) => {
// ^ use it here
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(x);
}))(x);
// ^ pass it here
x = 3;
Причина, по которой это работает, заключается в том, что мы создаем область с помощью нашей функции, которая связывает переменную x
в качестве одного из аргументов с любым значением, передаваемым в IIFE.
Это позволяет нам связать глобальный x
с чем-то другим, но x
, ограниченный внутри IIFE, не затрагивается.
Поскольку мы используем одно и то же имя как во IIFE, так и за его пределами, внутренний x
также затеняет внешнее.
Возможно, использование разных имен сделает вещи более читабельными:
let x = 5;
const p = (y => new Promise((resolve, reject) => {
// ^ use it here under a different name
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))(x);
// ^ pass it here
x = 3;
Примечание: вышеприведенное работает, потому что мы имеем дело с примитивными значениями , которые в JavaScript являются неизменяемыми и, таким образом, при каждом переназначении создается новое значение.
var a = 'a';
var b = a; // this will bind `b` to the copy of value of `a`
a = 'changed'; // this won't affect `b`
console.log(a, b); // 'changed', 'a'
Если бы мы имели дело с объектами, использование IIFE не сработало бы:
let x = { changed: false };
const p = (y => new Promise((resolve, reject) => {
// ^ still points to the same object as x
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))(x);
x.changed = true; // this will affect y as well
Причина в том, что объекты не являются неизменяемыми, и поэтому каждая связанная переменная указывает на один и тот же объект.
var a = { name: 'a' };
var b = a; // this will bind `b` to the value of `a` (not copy)
a.name = 'changed'; // this will also change `b`
console.log(a.name, b.name); // 'changed', 'changed'
Чтобы достичь того, что вам нужно с объектами, вам нужно будет подражать тому, что движок JS делает с примитивами, и клонировать объект
при передаче его во IIFE:
let x = {
changed: false
};
const p = (y => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))({ ...x });
// ^^^^^^^^ clone x when passing in
x.changed = true; // now this only affects the original, not the clone
Или используя Object.assign
:
let x = {
changed: false
};
const p = (y => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))(Object.assign({}, x));
// ^^^^^^^^^^^^^^^^^^^ clone x when passing in
x.changed = true; // now this only affects the original, not the clone
Примечание: оба объекта распространение и Object.assign
выполняют неглубокое клонирование. Для глубокого клонирования вы можете найти множество библиотек в NPM .
См .: Какой самый эффективный способ глубокого клонирования объекта в JavaScript?
В большинстве случаев это также может работать:
let x = {
changed: false
};
const p = (y => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
}))(JSON.parse(JSON.stringify(x)));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ clone x when passing in
x.changed = true; // now this only affects the original, not the clone
Примечание. Использование IIFE - только быстрый пример. Обычная функция будет работать так же хорошо (но все равно будет иметь те же проблемы для непримитивных значений):
let x = 5;
const p = createPromise(x);
x = 3;
function createPromise(y) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(y);
})
}