次のようなJavaScriptコードがあります。
function statechangedPostQuestion()
{
//alert("statechangedPostQuestion");
if (xmlhttp.readyState==4)
{
var topicId = xmlhttp.responseText;
setTimeout("postinsql(topicId)",4000);
}
}
function postinsql(topicId)
{
//alert(topicId);
}
topicId
が定義されていないというエラーが出ます。setTimeout()
関数を使う前は、すべてうまくいきました。
しばらくしてからpostinsql(topicId)
関数を呼び出したいです。私は何をすべきか?
setTimeout(function() {
postinsql(topicId);
}, 4000)
あなたは文字列の代わりにパラメータとして無名関数を供給する必要があります、後者のメソッドはECMAScript仕様に従ってさえ働くべきではありませんが、ブラウザは単に寛大です。これは適切な解決策です。setTimeout()
またはsetInterval()
を使用するときに文字列を「関数」として渡すことに頼らないでください。評価しなければならず、正しくないので時間がかかります。
更新:
Hobblinがその質問へのコメントで述べたように、Function.prototype.bind()
を使用してsetTimeout内で関数に引数を渡すことができます。
例:
setTimeout(postinsql.bind(null, topicId), 4000);
最近のブラウザでは、 "setTimeout"はタイマーの終了時に内部関数へのパラメータとして送信される3番目のパラメータを受け取ります。
例:
var hello = "Hello World";
setTimeout(alert, 1000, hello);
もっと詳しく
いくつかの調査とテストを行った後、唯一の正しい実装は以下のとおりです。
setTimeout(yourFunctionReference, 4000, param1, param2, paramN);
setTimeoutは、追加のパラメータをすべて関数に渡して、そこで処理できるようにします。
匿名関数は非常に基本的なもののために働くことができますが、 "this"を使わなければならないオブジェクトのインスタンスの中では、それを働かせる方法はありません。匿名の関数はすべて "this"をwindowを指すように変更するので、あなたはあなたのオブジェクト参照を失うことになります。
これは非常に古くからある質問で、すでに「正しい」答えがありますが、ここでは誰も言及していない別のアプローチに言及することにしました。これは、優れた アンダースコア ライブラリからコピーして貼り付けます。
_.delay = function(func, wait) {
var args = slice.call(arguments, 2);
return setTimeout(function(){ return func.apply(null, args); }, wait);
};
SetTimeout および によって呼び出される関数には、追加のボーナスとして(通常はボーナスとして)必要なだけ引数を渡すことができます。setTimeoutを呼び出すと、関数に渡される引数の値は固定されますそのため、setTimeout()が呼び出されてからタイムアウトになるまでの間に値が変更されても、それほどひどくイライラすることはありません。
ここにいじる ここで、私の言っていることを見ることができる。
私は最近、 loop でsetTimeout
を使う必要があるという独特の状況に遭遇しました。これを理解することはsetTimeout
にパラメータを渡す方法を理解するのに役立ちます。
方法1
Sukimaの 提案 に従って、forEach
とObject.keys
を使用してください。
var testObject = {
prop1: 'test1',
prop2: 'test2',
prop3: 'test3'
};
Object.keys(testObject).forEach(function(propertyName, i) {
setTimeout(function() {
console.log(testObject[propertyName]);
}, i * 1000);
});
私はこの方法をお勧めします。
方法2
bind
を使う:
var i = 0;
for (var propertyName in testObject) {
setTimeout(function(propertyName) {
console.log(testObject[propertyName]);
}.bind(this, propertyName), i++ * 1000);
}
JSFiddle: http://jsfiddle.net/MsBkW/ /
方法3
forEach
またはbind
を使用できない場合は、 _ iife _ を使用します。
var i = 0;
for (var propertyName in testObject) {
setTimeout((function(propertyName) {
return function() {
console.log(testObject[propertyName]);
};
})(propertyName), i++ * 1000);
}
方法4
しかし、あなたがIE <10を気にしないのであれば、Fabioの 提案 :を使うことができます。
var i = 0;
for (var propertyName in testObject) {
setTimeout(function(propertyName) {
console.log(testObject[propertyName]);
}, i++ * 1000, propertyName);
}
方法5(ES6)
ブロックスコープ変数を使用します。
let i = 0;
for (let propertyName in testObject) {
setTimeout(() => console.log(testObject[propertyName]), i++ * 1000);
}
ES6ではforEach
とObject.keys
の併用をお勧めします。
Hobblinはすでにこの問題についてコメントしていますが、それは本当に答えになるはずです。
Function.prototype.bind()
を使用するのがこれを行うための最もクリーンで最も柔軟な方法です(this
コンテキストを設定できるという追加のボーナスと共に):
setTimeout(postinsql.bind(null, topicId), 4000);
詳細については、これらのMDNリンクを参照してください。
https://developer.mozilla.org/en/docs/DOM/window.setTimeout#highlighter_547041https://developer.mozilla.org/en/docs/JavaScript/Reference/ Global_Objects/Function/bind#With_setTimeout
いくつかの答えは正しいですが複雑です。
私はまだこの質問を正確に解決するために過度に複雑なコードに出くわすので、私は4年後に、これに再び答えています。そこにIS優雅な解決策があります。
まず第一に、setTimeoutを呼び出すときに最初のパラメータとして文字列を渡さないでください。遅い "eval"関数の呼び出しを効果的に呼び出すからです。
では、タイムアウト関数にパラメータを渡すにはどうすればよいでしょうか。クロージャを使って:
settopic=function(topicid){
setTimeout(function(){
//thanks to closure, topicid is visible here
postinsql(topicid);
},4000);
}
...
if (xhr.readyState==4){
settopic(xhr.responseText);
}
タイムアウト関数を呼び出すときに匿名関数を使用することをお勧めします。
if (xhr.readyState==4){
setTimeout(function(){
settopic(xhr.responseText);
},4000);
}
構文はうまくいきます。しかし、settopicが呼ばれる時、すなわち4秒後までに、XHRオブジェクトは同じではないかもしれません。したがって、 変数を事前バインドすることが重要です 。
私の答え:
setTimeout((function(topicId) {
return function() {
postinsql(topicId);
};
})(topicId), 4000);
説明:
作成された無名関数は別の無名関数を返します。この関数は最初に渡された
topicId
にアクセスできるので、エラーにはなりません。最初の無名関数はすぐに呼び出され、topicId
を渡します。そのため、遅延のある登録済み関数は、呼び出し時にクロージャを通じてtopicId
にアクセスできます。
OR
これは基本的に次のように変換されます。
setTimeout(function() {
postinsql(topicId); // topicId inside higher scope (passed to returning function)
}, 4000);
編集:私は同じ答えを見たので、彼を見てください。しかし、私は彼の答えを盗みませんでした!私は見るのを忘れました。説明を読み、それがコードを理解するのに役立つかどうかを確認してください。
交換する
setTimeout("postinsql(topicId)", 4000);
と
setTimeout("postinsql(" + topicId + ")", 4000);
もっと良いのは、文字列式を無名関数に置き換えることです。
setTimeout(function () { postinsql(topicId); }, 4000);
編集:
Brownstoneのコメントは正しくありません、これはFirebugコンソールでこれを実行することによって実証されるように、意図したとおりに動作します。
(function() {
function postinsql(id) {
console.log(id);
}
var topicId = 3
window.setTimeout("postinsql(" + topicId + ")",4000); // outputs 3 after 4 seconds
})();
setTimeout
に文字列を渡すのは避けるべきだと私は他の人と同意していることに注意してください。これは文字列に対してeval()
を呼び出し、代わりに関数を渡すからです。
SetTimeoutでパラメータをサポートするための最も簡単なクロスブラウザソリューション:
setTimeout(function() {
postinsql(topicId);
}, 4000)
IE 9以下をサポートしていないのであれば:
setTimeout(postinsql, 4000, topicId);
https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
私はそれが古いことを知っていますが、私はこれに私の(好みの)味を加えたいと思いました。
これを達成するためのかなり読みやすい方法はtopicId
を関数に渡すことだと思います。関数はトピックIDを内部的に参照するために引数を使います。すぐ後に外側のtopicId
が変更されても、この値は変わりません。
var topicId = xmlhttp.responseText;
var fDelayed = function(tid) {
return function() {
postinsql(tid);
};
}
setTimeout(fDelayed(topicId),4000);
または短い:
var topicId = xmlhttp.responseText;
setTimeout(function(tid) {
return function() { postinsql(tid); };
}(topicId), 4000);
これはすべてのブラウザで動作します(IEはおかしなことです)。
setTimeout( (function(x) {
return function() {
postinsql(x);
};
})(topicId) , 4000);
David Meisterによる答えは、setTimeout()を呼び出した直後で、無名関数が呼び出される前に変更される可能性があるパラメータを考慮しているようです。しかし、それは面倒すぎてあまり明白ではありません。私はIIFE(すぐに呼び出される関数式)を使ってほぼ同じことをする優雅な方法を発見しました。
以下の例では、currentList
変数がIIFEに渡され、遅延関数が呼び出されるまで、変数は閉じて保存されます。表示されたコードの直後に変数currentList
が変わっても、setInterval()
は正しいことをします。
このIIFEテクニックがなければ、setTimeout()
関数はDOMの各h2
要素に対して確実に呼び出されますが、それらの呼び出しはすべて last h2
要素のテキスト値のみを見ることになります。
<script>
// Wait for the document to load.
$(document).ready(function() {
$("h2").each(function (index) {
currentList = $(this).text();
(function (param1, param2) {
setTimeout(function() {
$("span").text(param1 + ' : ' + param2 );
}, param1 * 1000);
})(index, currentList);
});
</script>
一般に、特定のパラメータを持つコールバックとして関数を渡す必要がある場合は、高階関数を使用できます。これはES6ではかなりエレガントです。
const someFunction = (params) => () => {
//do whatever
};
setTimeout(someFunction(params), 1000);
someFunction
が1次の場合
setTimeout(() => someFunction(params), 1000);
どのように私はこの段階を解決しましたか?
ちょうどそのように:
setTimeout((function(_deepFunction ,_deepData){
var _deepResultFunction = function _deepResultFunction(){
_deepFunction(_deepData);
};
return _deepResultFunction;
})(fromOuterFunction, fromOuterData ) , 1000 );
setTimeoutは関数への参照を待つので、私はそれをクロージャで作成しました。それは私のデータを解釈し、私のデータの良いインスタンスを持つ関数を返します!
たぶん、あなたはこの部分を改善することができます:
_deepFunction(_deepData);
// change to something like :
_deepFunction.apply(contextFromParams , args);
私はそれをchrome、firefoxそしてIEでテストしました、そしてそれはうまく実行されます、私はパフォーマンスについては知らないが、私はそれが働くことを必要としました。
サンプルテスト
myDelay_function = function(fn , params , ctxt , _time){
setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
var _deepResultFunction = function _deepResultFunction(){
//_deepFunction(_deepData);
_deepFunction.call( _deepCtxt , _deepData);
};
return _deepResultFunction;
})(fn , params , ctxt)
, _time)
};
// the function to be used :
myFunc = function(param){ console.log(param + this.name) }
// note that we call this.name
// a context object :
myObjet = {
id : "myId" ,
name : "myName"
}
// setting a parmeter
myParamter = "I am the outer parameter : ";
//and now let's make the call :
myDelay_function(myFunc , myParamter , myObjet , 1000)
// this will produce this result on the console line :
// I am the outer parameter : myName
たぶんあなたはそれがより遵守するように署名を変更することができます:
myNass_setTimeOut = function (fn , _time , params , ctxt ){
return setTimeout((function(_deepFunction ,_deepData, _deepCtxt){
var _deepResultFunction = function _deepResultFunction(){
//_deepFunction(_deepData);
_deepFunction.apply( _deepCtxt , _deepData);
};
return _deepResultFunction;
})(fn , params , ctxt)
, _time)
};
// and try again :
for(var i=0; i<10; i++){
myNass_setTimeOut(console.log ,1000 , [i] , console)
}
そして最後に元の質問に答える:
myNass_setTimeOut( postinsql, 4000, topicId );
それが役立つことを願っています!
ps:申し訳ありませんが英語それは私の母国語ではありません!
エラーメッセージに従ってtopicIdが「定義されていない」理由は、setTimeoutが実行されたときにローカル変数として存在していたが、postinsqlへの遅延呼び出しが発生したときではないことに注意してください。特に「this」をオブジェクト参照として渡すようなことを試みるときは、可変寿命が特に注意を払うために重要です。
SetTimeout関数の3番目のパラメータとしてtopicIdを渡すことができると聞きました。詳細は説明されていませんが、それを機能させるのに十分な情報が得られました。Safariでは成功しています。私は彼らが "ミリ秒エラー"についてどういう意味を知らない。ここでそれをチェックしてください。
あなたがパラメータとして変数を渡したい場合はこれを試してみましょう
必要条件がparmasとしてのfunctionとvarであるならば、これを試してください
setTimeout((param1,param2) => {
alert(param1 + param2);
postinsql(topicId);
},2000,'msg1', 'msg2')
要件がパラメータとしての変数にすぎない場合は、これを試してください
setTimeout((param1,param2) => { alert(param1 + param2) },2000,'msg1', 'msg2')
あなたはES5とES6でこれを試すことができます
あなたはこのような 'apply()'のデフォルト機能を試すことができます、あなたは配列としてあなたの要求としてより多くの引数を渡すことができます
function postinsql(topicId)
{
//alert(topicId);
}
setTimeout(
postinsql.apply(window,["mytopic"])
,500);
//これらは非常に単純で簡潔な3つの答えです。
function fun() {
console.log(this.prop1, this.prop2, this.prop3);
}
let obj = { prop1: 'one', prop2: 'two', prop3: 'three' };
let bound = fun.bind(obj);
setTimeout(bound, 3000);
// or
function funOut(par1, par2, par3) {
return function() {
console.log(par1, par2, par3);
}
};
setTimeout(funOut('one', 'two', 'three'), 5000);
// or
let funny = function(a, b, c) { console.log(a, b, c); };
setTimeout(funny, 2000, 'hello', 'worldly', 'people');
IEの3番目のoptonalパラメータに問題があり、クロージャを使用すると、変数を変更して(たとえばループ内で)希望どおりの結果が得られないため、次の解決策をお勧めします。
このように再帰を使ってみることができます。
var i = 0;
var hellos = ["Hello World1!", "Hello World2!", "Hello World3!", "Hello World4!", "Hello World5!"];
if(hellos.length > 0) timeout();
function timeout() {
document.write('<p>' + hellos[i] + '<p>');
i++;
if (i < hellos.length)
setTimeout(timeout, 500);
}
他に何もこれらの変数を変更しないこと、そして無限再帰を避けるために適切な再帰条件を書くことを確かめる必要があります。
次のようにsetTimeoutコールバック関数にパラメータを渡すことができます。
setTimeout(関数、ミリ秒、パラメータ1、パラメータ2、...)
例えば。
function myFunction() {
setTimeout(alertMsg, 3000, "Hello");
}
function alertMsg(message) {
alert(message)
}
@ Jiri Vetyskaが投稿してくれてありがとう、でもあなたの例には問題がある。ホバーアウトされているターゲット(this)をタイムアウトした関数に渡す必要があり、あなたのアプローチを試しました。 IE9でテスト - 動作しません。私はまたいくつかの研究をしました、そして先に指摘したように ここ /第三パラメータは使用されているスクリプト言語です。追加のパラメータについての言及はありません。
それで、私は@ mederの答えに従い、このコードで私の問題を解決しました:
$('.targetItemClass').hover(ItemHoverIn, ItemHoverOut);
function ItemHoverIn() {
//some code here
}
function ItemHoverOut() {
var THIS = this;
setTimeout(
function () { ItemHoverOut_timeout(THIS); },
100
);
}
function ItemHoverOut_timeout(target) {
//do something with target which is hovered out
}
願って、これは他の誰かにとって便利です。