Javascript 使用prototype向函数添加属性会导致函数参数未定义
我有一个执行数据库调用(sqlite3)的循环,以减少回调中的库存。它工作得很好,将“使用的部分”减少了1 平均可能有1到60个数组元素,因此此循环将快速连续创建1到60个异步任务。回调函数签名是(error,row),由绑定到sqlite3的JS确定。我不能改变它Javascript 使用prototype向函数添加属性会导致函数参数未定义,javascript,sqlite,callback,prototype,Javascript,Sqlite,Callback,Prototype,我有一个执行数据库调用(sqlite3)的循环,以减少回调中的库存。它工作得很好,将“使用的部分”减少了1 平均可能有1到60个数组元素,因此此循环将快速连续创建1到60个异步任务。回调函数签名是(error,row),由绑定到sqlite3的JS确定。我不能改变它 i = 0; while (i < struct.PortionsUsed.length) { portionUsed = struct.PortionsUsed[i]; D
i = 0;
while (i < struct.PortionsUsed.length) {
portionUsed = struct.PortionsUsed[i];
Db.get("SELECT blah blah WHERE portion = ? ORDER BY date LIMIT 1", portionUsed, selectCallBack);
i++;
}
关闭输出:
Starting Select for Coffee - count=5
Starting Select for Hot Tea - count=2
Hit selectCallBack. count=2 portionUsed=Hot Tea
objectobject
Hit selectCallBack. count=2 portionUsed=Hot Tea
objectobject
原型方法输出:
Starting Select for Coffee - count=5
Hit selectCallBack. count=5 portionUsed=Coffee
undefinedundefined
selectCallBack error:
undefined
Starting Select for Hot Tea - count=2
Hit selectCallBack. count=2 portionUsed=Hot Tea
undefinedundefined
selectCallBack error:
undefined
在JavaScript中创建新变量作用域的唯一方法是调用函数,这一事实使您的闭包尝试受到影响。在循环中创建函数时,所有函数都在同一变量范围内创建 为了解决这个问题,您需要在循环的每次迭代中调用一个函数,传入需要保存在该新变量范围内的值,并在该范围内创建回调函数。这样,在循环中创建的每个函数都在一个唯一的函数作用域中创建 IMO实现这一点最清晰的方法是将需要作用域的代码移动到一个新函数中,并在循环中调用它
struct.PortionsUsed = struct.PortionsUsed.sort();
i = 0;
while (i < struct.PortionsUsed.length) {
j = i + 1;
while (j < struct.PortionsUsed.length && struct.PortionsUsed[i] === struct.PortionsUsed[j]) {
++j;
}
count = j - i;
portionUsed = struct.PortionsUsed[i];
if (debug) {console.log('Starting Select for ' + portionUsed + ' - count=' + count);}
setHandler(Db, count, portionUsed, selectCallback);
i = j;
}
function setHandler(Db, count, portionUsed, callback) {
// In here, any of the above parameters can be used within the
// handler function created below.
Db.get("SELECT rowid AS rowNum, portion, qty FROM Portion WHERE portion = ? ORDER BY date LIMIT 1",
portionUsed,
function(error, row) {
console.log(count, portionUsed); // Not sure how you wanted to use these
callback(error, row);
}
);
}
struct.PortionsUsed=struct.PortionsUsed.sort();
i=0;
while(i
类似的解决方案是只在新函数中创建处理程序,并让函数返回它
struct.PortionsUsed = struct.PortionsUsed.sort();
i = 0;
while (i < struct.PortionsUsed.length) {
j = i + 1;
while (j < struct.PortionsUsed.length && struct.PortionsUsed[i] === struct.PortionsUsed[j]) {
++j;
}
count = j - i;
portionUsed = struct.PortionsUsed[i];
if (debug) {console.log('Starting Select for ' + portionUsed + ' - count=' + count);}
Db.get("SELECT rowid AS rowNum, portion, qty FROM Portion WHERE portion = ? ORDER BY date LIMIT 1",
portionUsed,
setHandler(count, portionUsed, selectCallback)
);
i = j;
}
function setHandler(count, portionUsed, callback) {
// In here, any of the above parameters can be used within the
// handler function that we create and return below.
return function(error, row) {
console.log(count, portionUsed); // Not sure how you wanted to use these
callback(error, row);
};
}
struct.PortionsUsed=struct.PortionsUsed.sort();
i=0;
while(i
有些人喜欢在循环中直接使用内联的、立即调用的函数来实现这一点,但我认为这会使代码过于混乱。我更喜欢使用命名函数。“闭包不起作用(尝试过了),因为当回调启动时,计数是循环中最后一个计数的值。”…那么你做得不正确。当你在循环中修改
selectCallBack.prototype.count
时,所有从new selectCallBack()创建的对象
将看到更新。换句话说,.prototype
对象在所有实例之间共享,因此它们都观察更新。为什么不直接将属性放在正在创建的对象上?…如果DB.get()
的第三个参数应该是回调函数,除非调用时从selectCallback
返回一个,否则在执行new selectCallback
时不会传递一个。从您的评论中,我意识到,我所认为的是由于Db调用而实际执行回调函数的输出实际上是我使用“new”的输出因此与实际的Db调用无关。我现在意识到原型方法根本不起作用,因为新方法将以构造函数的形式执行它。我更新了代码,以显示我试图使用的闭包尝试,因为您指出我可能做错了。当我看到您使用函数的输出返回函数时,您就让我走上了正确的道路。这就是我错过的。我从来没有想到过。非常感谢。
struct.PortionsUsed = struct.PortionsUsed.sort();
i = 0;
while (i < struct.PortionsUsed.length) {
j = i + 1;
while (j < struct.PortionsUsed.length && struct.PortionsUsed[i] === struct.PortionsUsed[j]) {
++j;
}
count = j - i;
portionUsed = struct.PortionsUsed[i];
if (debug) {console.log('Starting Select for ' + portionUsed + ' - count=' + count);}
setHandler(Db, count, portionUsed, selectCallback);
i = j;
}
function setHandler(Db, count, portionUsed, callback) {
// In here, any of the above parameters can be used within the
// handler function created below.
Db.get("SELECT rowid AS rowNum, portion, qty FROM Portion WHERE portion = ? ORDER BY date LIMIT 1",
portionUsed,
function(error, row) {
console.log(count, portionUsed); // Not sure how you wanted to use these
callback(error, row);
}
);
}
struct.PortionsUsed = struct.PortionsUsed.sort();
i = 0;
while (i < struct.PortionsUsed.length) {
j = i + 1;
while (j < struct.PortionsUsed.length && struct.PortionsUsed[i] === struct.PortionsUsed[j]) {
++j;
}
count = j - i;
portionUsed = struct.PortionsUsed[i];
if (debug) {console.log('Starting Select for ' + portionUsed + ' - count=' + count);}
Db.get("SELECT rowid AS rowNum, portion, qty FROM Portion WHERE portion = ? ORDER BY date LIMIT 1",
portionUsed,
setHandler(count, portionUsed, selectCallback)
);
i = j;
}
function setHandler(count, portionUsed, callback) {
// In here, any of the above parameters can be used within the
// handler function that we create and return below.
return function(error, row) {
console.log(count, portionUsed); // Not sure how you wanted to use these
callback(error, row);
};
}