![](/img/trans.png)
[英]How to access variables in another scope inside a function using closure in javascript?
[英]How to access out of scope variables in Promise.then (similar to closure)
難以理解,確實有一種優雅的方式來做到這一點,但不知道是什么。
我想要像:
let x = 5;
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, 2000);
}).then(() => {
console.log(x);
});
x = 3;
// Print out 5 after 2 seconds.
基本上,給定類似於上面的設置,有沒有辦法打印'5'
,無論在異步超時期間x
的值是否改變? 在我的情況下,很難簡單地在resolve()
傳遞x
。
你可以通過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
綁定到其他東西,但IIFE內的x
不受影響。
由於我們在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); }) }
是的,您可以使用工廠函數生成您的承諾,該承諾可以充當變量的閉包。
function promiseFactory(x){
return new Promise(function(resolve){
setTimeout(function(){
console.log(x); // value as passed to factory call
resolve(x)
}, 1000)
});
}
let x = 5;
promiseFactory(x) // returns a promise which will always see x as 5
.then(function(x){console.log(x)})
一個小警告:這可以在這里工作,因為x是一個整數,它是一個基本類型,因此值被復制。 如果您使用像object / array這樣的引用類型,則必須傳遞克隆對象
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.