2011-01-23 8 views
28

がここにスクリプトです:"引数"をシフトする方法は?

function runScripts() { 
    if (arguments.length === 0) return; 
    chrome.tabs.executeScript(null, { 
     file: arguments[0] 
    }, function() { 
     arguments.shift(); 
     runScripts.apply(null, arguments); 
    }); 
} 

argumentsは実際には配列ではありませんので、それが動作しない、それだけで、アレイのようです。だから私はそれを "シフト"するか、最初の要素をハックして再帰的にこの関数を適用することができますか?

答えて

19

私はあなたがchrome.tabs.executeScriptに渡しているコールバックから、代わりにそのの、arguments元を参照するようにしたいと仮定します。

もしそうなら、最初にキャッシュする必要があります。

function runScripts() { 
    if (arguments.length === 0) return; 
    var args = []; 
    Array.prototype.push.apply(args, arguments); 

    chrome.tabs.executeScript(null, { 
     file: args.shift(); 
    }, function() { 
      // using the modified Array based on the original arguments object 
     runScripts.apply(null, args); 
    }); 
} 
+0

Eh ...?なぜあなたはそれを仮定しますか?各反復は最初の要素のみを処理し、残っている要素がなくなるまで残りの要素を呼び出します。あなたのバージョンが何をすべきかわからない。 – mpen

+0

ああ、何もしない。匿名の機能のために、あなたは正しいですが、最初の要素を渡すことはまだ想定されていません。最初の要素以外はすべて渡すことになっています。 – mpen

+0

@マーク:あなたは2つの機能を持っています。たぶん私は間違っていますが、あなたの質問は 'runScripts()' *の 'arguments'を' executeScript'に渡すコールバックに渡したいと解釈しました。コールバックの外側で 'arguments [0]' *を参照してから、コールバックの内部で '.shift()' *しようとしているので、これは奇妙な仮定ではありません。 – user113716

31
var params = Array.prototype.slice.call(arguments); 
params.shift(); 

あなたは、さらに詳細にそれを説明し、このblog postをチェックアウトすることができます。

+0

私は 'alert(args.length)'を実行すると、それは私に0を通知しますが、 'arguments.length'は私に2と言います。 **編集:**クラップ...私は参照してください。無名関数はそれを台無しにしています。 – mpen

+1

修正された 'Array':' [] .slice.call(arguments) 'からあなたを守るマイナーな最適化があります。 – fny

+1

'[] .shift.call(arguments)'を使わないのはなぜですか? ;) – thewildpendulum

2

これを配列に変換してシフトする必要があります。または、配列に変換するときに最初の項目を削除します。 Array.prototype.slice.call(arguments, 1)がこれに対応します。

6

次のような規則的な配列にargumentsを変換することができます:

var args = Array.prototype.slice.call(arguments); 
1

あなたが実際の配列に引数を変換して、機能であなたのロジックの残りの部分でその配列を使用することができます。

function runScripts() 
{ 
    var i=0, l=arguments.length, arr=[]; 
    while(i<l) 
    { 
    arr.push(arguments[i++]); 
    } 
...rest of your function code 

編集追加する:私は、IEの古いバージョンでprototypecallの問題を持っていたので、それは本当にあなたが必要とするもののサポートに依存します。

+0

幸いにも私はIEをサポートする必要はありません:)ただクロム。 – mpen

9

[].shift.call(arguments)も有効です。私はこれをプロダクションコードで使用しており、期待どおりに動作します。このアプローチでは、あなたの関数は、もう少し簡潔になり

function executeScripts() { 
    if (arguments.length === 0) return; 
    chrome.tabs.executeScript(null, { 
     file: [].shift.call(arguments) 
    }, function() { 
     executeScripts.apply(null, arguments); 
    }); 
} 

あなたはMDNに見れば、彼らはshift()を念頭に置いて、この柔軟性を実現したと述べています。

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/shift

+0

あまりにも悪いことに、実際には' arguments'を実際の配列として実装しただけではありません。しかし、あなたは正しいです。実際、 'Array'の全てのメソッドは、そのオブジェクトが' length'プロパティを持っている限り、* any *オブジェクトで使うことができます。それは言語仕様によって義務付けられています。この魔法の秘密は、表面の下にある配列は、プロパティキーとして数字を持つオブジェクトに過ぎないということです。 –

3

ジャスト[] .shift.call(引数)との潜在的な問題を指摘したかったです。

これは、shift文の前に使用されていても、関数のというパラメータがというパラメータであっても、引数がシフトする可能性があるかどうかは不明です。例えば

function testShift (param1, param2) { 
    [].shift.call(arguments); 
    if (param1=="ONE") alert("ONE"); 
} 

あなたは、次の呼び出しを行う場合は、あなたが起こるために何を期待するかもしれませんか?

testShift("ONE", "TWO"); 

param1が "ONE"のままになることを期待した場合は、シフトが発生する前にparam1にvarを設定してください。 javascriptが呼び出されるまでparam1をバインドしていないようです - 関数が呼び出されたときではない...パラメータを使用する前に引数を変更すると、予期しない結果が生じる可能性があります。

うまくいけば、期待することができます。

+0

TIL。それはまったく予想外の動作です。共有していただきありがとうございます。 – mpen

0

私はこれで行きました:

function executeScripts() { 
    if (arguments.length === 0) return; 
    var args = Array.prototype.slice.call(arguments); 
    chrome.tabs.executeScript(null, { 
     file: args.shift() 
    }, function() { 
     executeScripts.apply(null, args); 
    }); 
} 

Google Chromeの拡張機能を書くときに便利です。コンテンツスクリプトでjQueryを使いたかったのですが、最初に読み込む必要がありました。あなたがこれを行うことができますchrome.tabs.executeScriptへの呼び出しを連鎖によって判明:ここ

chrome.browserAction.onClicked.addListener(function(tab) { 
    executeScripts('jquery-1.4.4.min.js', 'content.js'); 
}); 
1

は、記事が本当によくこれを説明しています。以下の重要な点をいくつかコピーしました。 http://www.javascriptkit.com/javatutors/arrayprototypeslice.shtml

配列の場合、スライス関数を呼び出してサブ配列を取得できます。

var abc = [1,2,3,4,5]; 
abc.slice(0); //[1,2,3,4,5] 
abc.slice(1,3); //[2,3] 

引数オブジェクトは配列のようにしか配列ではないので、実際は配列です。 call()/ apply()関数は、基本的にArrayからスライス関数を単に借用して、それをArgumentオブジェクトで使用するだけで、配列に作用するようにスライス関数にパラメータを渡すことさえできます。

残りの質問の1つは、アレイインスタンスの代わりにArrayのプロトタイプオブジェクトでslice()を呼び出す理由です。なぜなら、これがArrayのslice()メソッドにアクセスするための最も直接的なルートであり、これが私たちが興味を持っているからです。私たちは、最初の配列のインスタンスを作成している可能性があり、それはあまり効率的で、間違いなく、より難解だ:

var myarray = new Array().prototype.slice.call(myobject) // less efficient 
2

ES6では、あなたが今Array.from()MDN ref

例えばを使用することができます

const args = Array.from(arguments); 
const str = args.shift(); 
+1

ES6では、variadic argsを使うこともできます: 'function f(... args){args.shift(); } ' – mpen

関連する問題