with
声明に関する私の回答に対するアラン・ストームのコメントは私に考えさせられました。私はこの特定の言語機能を使用する理由をめったに見つけず、それがどのように問題を引き起こす可能性があるかについてあまり考えたことはありませんでした。さて、私はwith
その落とし穴を避けながら、私がをどのように効果的に使用できるかについて興味があります。
このwith
ステートメントはどこで役に立ちましたか?
with
ため、そのようなものはなくなりました。
with
声明に関する私の回答に対するアラン・ストームのコメントは私に考えさせられました。私はこの特定の言語機能を使用する理由をめったに見つけず、それがどのように問題を引き起こす可能性があるかについてあまり考えたことはありませんでした。さて、私はwith
その落とし穴を避けながら、私がをどのように効果的に使用できるかについて興味があります。
このwith
ステートメントはどこで役に立ちましたか?
with
ため、そのようなものはなくなりました。
回答:
今日、別の使用法が私に起こりました。私は興奮してWebを検索し、それに関する既存の言及を見つけました:ブロックスコープ内の変数の定義。
JavaScriptは、表面的にはCおよびC ++に似ていますが、変数のスコープを、それらが定義されているブロックに限定しません。
var name = "Joe";
if ( true )
{
var name = "Jack";
}
// name now contains "Jack"
ループでクロージャを宣言することは、これがエラーにつながる可能性がある一般的なタスクです。
for (var i=0; i<3; ++i)
{
var num = i;
setTimeout(function() { alert(num); }, 10);
}
forループは新しいスコープを導入しないため、同じnum
-値2
-が3つの関数すべてで共有されます。
let
とwith
ES6でのlet
ステートメントの導入により、これらの問題を回避する必要がある場合に、新しいスコープを簡単に導入できます。
// variables introduced in this statement
// are scoped to each iteration of the loop
for (let i=0; i<3; ++i)
{
setTimeout(function() { alert(i); }, 10);
}
あるいは:
for (var i=0; i<3; ++i)
{
// variables introduced in this statement
// are scoped to the block containing it.
let num = i;
setTimeout(function() { alert(num); }, 10);
}
ES6が世界中で利用できるようになるまで、この使用は、トランスパイラーを使用したい最新のブラウザーと開発者に限定されたままです。ただし、この動作は次のようにして簡単にシミュレーションできますwith
。
for (var i=0; i<3; ++i)
{
// object members introduced in this statement
// are scoped to the block following it.
with ({num: i})
{
setTimeout(function() { alert(num); }, 10);
}
}
ループは意図したとおりに機能し、0から2の値を持つ3つの別々の変数を作成します。ブロック内で宣言された変数は、C ++のブロックの動作とは異なり、スコープされないことに注意してください(Cでは、変数は最初に宣言する必要がありますブロックなので、同じように)。この動作は実際には、以前のバージョンのMozillaブラウザーで導入されたlet
ブロック構文に非常に似ていますが、他の場所では広く採用されていません。
for (var i = 0; i < 3; ++i) { setTimeout ((function () { var num = i; return function () { alert (num); }; }) (), 10);}
var toString = function () { return "Hello"; }; with ({"test":1}) { console.log(toString()); };
。withステートメントのスコープでは、toString()はObjectの継承プロパティであるため、明示的に定義された関数は呼び出されません。しかし、それでも素晴らしい回答です:-)
スコープインポートの単純な形式としてwithステートメントを使用しています。なんらかのマークアップビルダーがあるとします。書くよりも:
markupbuilder.div(
markupbuilder.p('Hi! I am a paragraph!',
markupbuilder.span('I am a span inside a paragraph')
)
)
代わりに次のように書くことができます:
with(markupbuilder){
div(
p('Hi! I am a paragraph!',
span('I am a span inside a paragraph')
)
)
}
この使用例では、割り当てを行っていないので、それに関連するあいまいさの問題はありません。
context.bezierCurveTo
、100回ストレートを使用している場合は、発声var bc2 = context.bezierCurveTo;
した後bc2(x,x,etc);
、発呼するたびに移動します。これは非常に高速で、冗長度は低くwith
なりますが、超低速です。
私の以前のコメントが示したように、with
どのような状況でもそれがどんなに魅力的であっても、安全に使用できるとは思いません。この問題はここでは直接取り上げられていないので、繰り返します。次のコードを検討してください
user = {};
someFunctionThatDoesStuffToUser(user);
someOtherFunction(user);
with(user){
name = 'Bob';
age = 20;
}
これらの関数呼び出しを注意深く調査しない限り、このコードの実行後のプログラムの状態を知る方法はありません。user.name
既に設定されている場合は、になりますBob
。設定されていない場合、グローバルname
は初期化または変更されBob
、user
オブジェクトはname
プロパティなしで残ります。
バグが発生します。一緒に使用すると、最終的にはこれが行われ、プログラムが失敗する可能性が高くなります。さらに悪いことに、意図的に、または作成者がこの構造の奇妙な点を知らない場合に、withブロックでグローバルを設定する作業コードに遭遇する場合があります。これは、スイッチでフォールスルーが発生するのによく似ています。作成者が意図したとおりであるかどうかはわかりません。また、コードを「修正」すると回帰が発生するかどうかを知る方法がありません。
現代のプログラミング言語は機能が満載です。長年の使用の結果、一部の機能は不良であることが判明し、回避する必要があります。JavaScript with
はその1つです。
私は実際、このwith
発言が最近非常に役に立ったと感じました。この手法は、JavaScriptで記述されたコマンドラインコンソールである現在のプロジェクトを開始するまで、実際には思いつきませんでした。Firebug / WebKitコンソールAPIをエミュレートしようとしていましたが、コンソールに特別なコマンドを入力できますが、グローバルスコープの変数はオーバーライドされません。Shog9の優れた答えに対するコメントで述べた問題を克服しようとするとき、私はこれを考えました。
この効果を達成するために、2つのwithステートメントを使用して、グローバルスコープの背後にあるスコープを「レイヤー化」しました。
with (consoleCommands) {
with (window) {
eval(expression);
}
}
この手法の優れた点は、パフォーマンスの不利な点を除けば、with
ステートメントの通常の恐れに悩まされないということです。なぜなら、私たちはとにかくグローバルスコープで評価しているからです。疑似スコープ外の変数が存在する危険はありません。変更されました。
驚いたことに、他の場所で使用されているのと同じ手法、Chromiumのソースコードを見つけたとき、私はこの回答を投稿するように促されました。
InjectedScript._evaluateOn = function(evalFunction, object, expression) {
InjectedScript._ensureCommandLineAPIInstalled();
// Surround the expression in with statements to inject our command line API so that
// the window object properties still take more precedent than our API functions.
expression = "with (window._inspectorCommandLineAPI) { with (window) { " + expression + " } }";
return evalFunction.call(object, expression);
}
編集: Firebugソースをチェックしただけで、4つのステートメントが一緒にチェーンされ、さらに多くのレイヤーが作成されます。クレイジー!
const evalScript = "with (__win__.__scope__.vars) { with (__win__.__scope__.api) { with (__win__.__scope__.userVars) { with (__win__) {" +
"try {" +
"__win__.__scope__.callback(eval(__win__.__scope__.expr));" +
"} catch (exc) {" +
"__win__.__scope__.callback(exc, true);" +
"}" +
"}}}}";
はい、はい、はい。非常に正当な使用があります。見る:
with (document.getElementById("blah").style) {
background = "black";
color = "blue";
border = "1px solid green";
}
基本的に、他のDOMまたはCSSフックはwithの素晴らしい使用法です。「CloneNode」が未定義になり、グローバルスコープに戻るようなわけではありません。自分の邪魔をせずに、それを可能にすることに決めた場合を除きます。
Crockfordの速度の不満は、withによって新しいコンテキストが作成されることです。コンテキストは一般的に高価です。同意する。しかし、divを作成したばかりで、CSSを設定するための手持ちのフレームワークがなく、手動で15程度のCSSプロパティを設定する必要がある場合、コンテキストの作成は、変数の作成と15の逆参照よりも安価です。
var element = document.createElement("div"),
elementStyle = element.style;
elementStyle.fontWeight = "bold";
elementStyle.fontSize = "1.5em";
elementStyle.color = "#55d";
elementStyle.marginLeft = "2px";
等...
with
。しかし、この特定のケースではあなただけ行うことができます:element.style.cssText="background: black ; color: blue ; border: 1px solid green"
extend
jQueryまたはUnderscore.jsからの単純なメソッドを使用して、同じことを1行で実現できます$.extend(element.style, {fontWeight: 'bold', fontSize: '1.5em', color: '#55d', marginLeft: '2px'})
。
.css()
メソッドを使用するだけです...
小さなヘルパー関数を定義してwith
、あいまいさのない利点を提供できます。
var with_ = function (obj, func) { func (obj); };
with_ (object_name_here, function (_)
{
_.a = "foo";
_.b = "bar";
});
with_
泥だらけの二重バージョン(function(_){ _.a="foo"; })(object_here);
(c / javaスタイルのブロックをシミュレートする標準的な方法)になると、さらに多くのバグが発生します。代わりにそれを使用してください。
次のことができるので、それだけの価値はないようです。
var o = incrediblyLongObjectNameThatNoOneWouldUse;
o.name = "Bob";
o.age = "50";
with
。
私はこれまでに使用したことがなく、理由も見たことがなく、推奨もしていません。
の問題with
は、ECMAScript実装が実行できる多くの字句の最適化を妨げることです。高速JITベースのエンジンの台頭を考えると、この問題は近い将来さらに重要になるでしょう。
それはwith
よりきれいな構造を可能にするように見えるかもしれませんが(たとえば、一般的な匿名関数ラッパーの代わりに新しいスコープを導入するか、詳細なエイリアスを置き換えるとき)、それは 本当に価値がありません。パフォーマンスの低下に加えて、間違ったオブジェクトのプロパティに割り当てられる(注入されたスコープ内のオブジェクトにプロパティが見つからない場合)可能性があり、おそらく誤ってグローバル変数を導入する危険があります。IIRC、後者の問題は、Crockfordが回避することを推奨する動機となった問題ですwith
。
with(){}
ここの他の回答で示されているような構成のコストについて、最新のブラウザで具体的な数値がある場合は、ぜひご覧くださいそれら!
with(){}
新しいスコープの設定は、with
テストしたすべてのブラウザーで非常に高価です。非常に頻繁に呼び出されるコードでは、これを回避する必要があります。さらに、Chromeはwith()
スコープ内で実行されるコードに対して劇的なヒットを示しました。興味深いことに、IEはwith()
ブロック内のコードに対して最高のパフォーマンス特性を備えていました。セットアップコストを考慮してwith()
、IE6およびIE8 VMでメンバーアクセスの最速の手段を提供します(これらのVMは全体的に最も遅いです)。良いもの、ありがとう...
with()
は、Chromeではほぼ1桁遅く、IEでは2倍以上高速です...!
Visual Basic.NETにも同様のWith
ステートメントがあります。私が使用する最も一般的な方法の1つは、いくつかのプロパティをすばやく設定することです。の代わりに:
someObject.Foo = ''
someObject.Bar = ''
someObject.Baz = ''
、私は書くことができます:
With someObject
.Foo = ''
.Bar = ''
.Baz = ''
End With
これは怠惰の問題だけではありません。また、より読みやすいコードになります。また、JavaScriptとは異なり、ステートメントの影響を受けるすべての要素の前に.
(ドット)を付ける必要があるため、あいまいさはありません。したがって、次の2つは明確に区別されます。
With someObject
.Foo = ''
End With
対
With someObject
Foo = ''
End With
前者はsomeObject.Foo
; 後者はFoo
範囲外 someObject
です。
あいまいさのリスクが高すぎるため、JavaScriptには区別がないため、Visual Basicのバリアントよりもはるかに有用性が低いことがわかりました。それ以外は、with
読みやすくするための強力なアイデアです。
with
この小さなテンプレートエンジンで行われているように、を使用して、オブジェクトのコンテンツをローカル変数としてブロックに導入できます。
「with」を使用すると、コードがよりドライになります。
次のコードを検討してください。
var photo = document.getElementById('photo');
photo.style.position = 'absolute';
photo.style.left = '10px';
photo.style.top = '10px';
次のように乾燥できます。
with(document.getElementById('photo').style) {
position = 'absolute';
left = '10px';
top = '10px';
}
読みやすさや表現力を優先するかどうかにもよると思います。
最初の例はより読みやすく、おそらくほとんどのコードに推奨されます。しかし、ほとんどのコードはとにかくかなり使いこなされています。2つ目はもう少しあいまいですが、言語の表現の性質を使用して、コードサイズと余分な変数を削減します。
JavaまたはC#が好きな人は最初の方法(object.member)を選択し、RubyまたはPythonを好む人は後者を選択すると思います。
明らかな使い方はショートカットだと思います。たとえば、オブジェクトを初期化する場合は、「ObjectName」を何度も入力する手間を省くだけです。lispの "with-slots"のようなものです。
(with-slots (foo bar) objectname
"some code that accesses foo and bar"
書くのと同じ
"some code that accesses (slot-value objectname 'foo) and (slot-value objectname 'bar)""
言語が「Objectname.foo」を許可している場合に、これがショートカットである理由はより明白ですが、それでもまだです。
with-slots
、with
どのスロットを使用するかを指定する必要がありますが、実行時にバインドされたスロットを使用します。
Delphiでの経験を持って、私が使用していることを言うだろうとすると、おそらく、その安全性を確認するために、静的コード解析へのアクセス権を持つJavaScriptの最小化アルゴリズムのいくつかの種類によって実行される、最後の手段サイズを最適化する必要があります。
withステートメントを自由に使用することで発生する可能性のあるスコープの問題は、a **に大きな影響を与える可能性があります。コードで何が起こっているのかを理解するために、デバッグセッションを体験してほしくありません。 、意図したグローバルまたは外部スコープ変数ではなく、オブジェクトメンバーまたは誤ったローカル変数をキャプチャしたことを確認するためだけです。
VB withステートメントはスコープを明確にするためにドットが必要であるという点で優れていますが、Delphi withステートメントはヘアトリガーを備えたロードされたガンであり、JavaScriptは同じ警告を保証するのに十分似ているように見えます。
withの使用は推奨されておらず、ECMAScript 5のstrictモードでは禁止されています。推奨される代替方法は、一時変数にアクセスするプロパティを持つオブジェクトを割り当てることです。
withステートメントを使用して、コードサイズを小さくしたり、プライベートクラスメンバーを使用したりできます。次に例を示します。
// demo class framework
var Class= function(name, o) {
var c=function(){};
if( o.hasOwnProperty("constructor") ) {
c= o.constructor;
}
delete o["constructor"];
delete o["prototype"];
c.prototype= {};
for( var k in o ) c.prototype[k]= o[k];
c.scope= Class.scope;
c.scope.Class= c;
c.Name= name;
return c;
}
Class.newScope= function() {
Class.scope= {};
Class.scope.Scope= Class.scope;
return Class.scope;
}
// create a new class
with( Class.newScope() ) {
window.Foo= Class("Foo",{
test: function() {
alert( Class.Name );
}
});
}
(new Foo()).test();
withステートメントは、スコープを変更する場合に非常に役立ちます。実行時に操作できる独自のグローバルスコープを作成するために必要なことです。定数や、「toUpper」、「toLower」、「isNumber」、「clipNumber」など、よく使用される特定のヘルパー関数を追加できます。
頻繁に読むパフォーマンスの低下について:関数のスコープを指定してもパフォーマンスに影響はありません。実際、私のFFではスコープ付き関数はスコープなしの関数よりも速く実行されます。
var o={x: 5},r, fnRAW= function(a,b){ return a*b; }, fnScoped, s, e, i;
with( o ) {
fnScoped= function(a,b){ return a*b; };
}
s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
r+= fnRAW(i,i);
}
e= Date.now();
console.log( (e-s)+"ms" );
s= Date.now();
r= 0;
for( i=0; i < 1000000; i++ ) {
r+= fnScoped(i,i);
}
e= Date.now();
console.log( (e-s)+"ms" );
したがって、上記の方法でwithステートメントを使用しても、パフォーマンスに悪影響はありませんが、モバイルデバイスのメモリ使用量に影響を与えるコードサイズが減少するため、効果があります。
withを使用すると、多くの実装でコードが遅くなります。これは、すべてがルックアップ用の追加スコープにラップされるためです。JavaScriptでを使用する正当な理由はありません。
var obj={a:0,b:0,c:0};var d=+new Date;with(obj){for(var i=0;i<1000000;++i){a+=1;b+=1;c+=1}}+new Date-d;
平均で2,500、var obj={a:0,b:0,c:0};var d=+new Date;for(var i=0;i<1000000;++i){obj.a+=1;obj.b+=1;obj.c+=1}+new Date-d;
平均で750です。これにより、使用時間が3倍以上遅くなります。
with
コードで1138、なしで903でした。タイトループでもこの小さな違いがあるので、パフォーマンスを心配する前に、コーディングの単純さとケースバイケースでのリファクタリングの容易さに基づいて選択を行います。
オブジェクトリテラルの使用は、クロージャーを使用するためのドロップイン置換のように興味深いと思います
for(var i = nodes.length; i--;)
{
// info is namespaced in a closure the click handler can access!
(function(info)
{
nodes[i].onclick = function(){ showStuff(info) };
})(data[i]);
}
または、クロージャと同等のwithステートメント
for(var i = nodes.length; i--;)
{
// info is namespaced in a closure the click handler can access!
with({info: data[i]})
{
nodes[i].onclick = function(){ showStuff(info) };
}
}
実際のリスクは、withステートメントの一部ではない変数を誤って最小化することだと思います。そのため、オブジェクトリテラルが一緒に渡されるのが好きなのですが、コードで追加されたコンテキストでそれがどうなるかを正確に確認できます。
with
ステートメントでこのあいまいさを解消する「マージ」関数を作成しました。
if (typeof Object.merge !== 'function') {
Object.merge = function (o1, o2) { // Function to merge all of the properties from one object into another
for(var i in o2) { o1[i] = o2[i]; }
return o1;
};
}
と同様に使用できますがwith
、意図しないスコープには影響しないことがわかります。
使用法:
var eDiv = document.createElement("div");
var eHeader = Object.merge(eDiv.cloneNode(false), {className: "header", onclick: function(){ alert("Click!"); }});
function NewObj() {
Object.merge(this, {size: 4096, initDate: new Date()});
}
一部の短いコードでは、放射モードではなく、度モードsin
でcos
などの三角関数を使用したいと思います。この目的のために、私はAngularDegree
オブジェクトを使用します:
AngularDegree = new function() {
this.CONV = Math.PI / 180;
this.sin = function(x) { return Math.sin( x * this.CONV ) };
this.cos = function(x) { return Math.cos( x * this.CONV ) };
this.tan = function(x) { return Math.tan( x * this.CONV ) };
this.asin = function(x) { return Math.asin( x ) / this.CONV };
this.acos = function(x) { return Math.acos( x ) / this.CONV };
this.atan = function(x) { return Math.atan( x ) / this.CONV };
this.atan2 = function(x,y) { return Math.atan2(x,y) / this.CONV };
};
次に、with
ブロックでさらに言語ノイズを発生させることなく、三角関数を次数モードで使用できます。
function getAzimut(pol,pos) {
...
var d = pos.lon - pol.lon;
with(AngularDegree) {
var z = atan2( sin(d), cos(pol.lat)*tan(pos.lat) - sin(pol.lat)*cos(d) );
return z;
}
}
つまり、オブジェクトを関数のコレクションとして使用し、限られたコード領域で直接アクセスできるようにします。これは便利だと思います。
with
この方法でステートメントを使用するのは良い考えではありません。どの関数がグローバルであり、どの関数がwithオブジェクトのスコープ内で呼び出されるかわからないため、コードが読みにくくなるだけです。オブジェクトスコープは、グローバルネームスペースでアクセスしようとします
z = Math.atan2( Math.sin(d * Math.PI / 180), Math.cos( pol.lat * Math.PI / 180) * Math.tan( pos.lat * Math.PI / 180 ) - Math.sin( pol.lat * Math.PI / 180 ) * Math.cos( d * Math.PI / 180) ) * 180 / Math.PI;
ます。同じ結果が得られますが、それは恐怖です。
with
せるだろういくつかの使用法をあなたに示すことができるとかなり確信しています。
の有用性はwith
、コードが適切に記述されているかどうかに依存すると考えられます。たとえば、次のようなコードを書いているとします。
var sHeader = object.data.header.toString();
var sContent = object.data.content.toString();
var sFooter = object.data.footer.toString();
その後、次のようにすることでwith
コードの可読性が向上すると主張できます。
var sHeader = null, sContent = null, sFooter = null;
with(object.data) {
sHeader = header.toString();
sContent = content.toString();
sFooter = content.toString();
}
逆に、あなたがデメテルの法則に違反していると主張することはできますが、もう一度、多分そうではありません。余談です=)。
何よりも、Douglas Crockford はを使用しないことをお勧めしwith
ます。ここで彼のブログ投稿with
とその代替案をチェックすることをお勧めします。
W3schools http://www.w3schools.com/js/js_form_validation.aspでJavaScriptのフォームの検証を見る必要がありますで「email」という名前の入力を見つけるためにオブジェクトフォームを「スキャン」する
しかし、どのフォームからでも取得できるように変更しました。フォーム内のフィールドの名前や数量に関係なく、すべてのフィールドが空ではないことが検証されます。さて、私はテキストフィールドのみをテストしました。
しかし、with()は物事をより単純にしました。コードは次のとおりです。
function validate_required(field)
{
with (field)
{
if (value==null||value=="")
{
alert('All fields are mandtory');return false;
}
else
{
return true;
}
}
}
function validate_form(thisform)
{
with (thisform)
{
for(fiie in elements){
if (validate_required(elements[fiie])==false){
elements[fiie].focus();
elements[fiie].style.border='1px solid red';
return false;
} else {elements[fiie].style.border='1px solid #7F9DB9';}
}
}
return false;
}
ここに良い使い方があります with
。オブジェクトに格納されている値に基づいて、オブジェクトリテラルに新しい要素を追加する。これが私が今日使った例です:
使用可能なタイルのセット(開口部が上、下、左、または右に面している)があり、ゲームの開始時に常に配置およびロックされるタイルのリストをすばやく追加する方法が必要でした。types.tbr
リストのタイプごとにタイプし続けたくなかったので、そのまま使用しましたwith
。
Tile.types = (function(t,l,b,r) {
function j(a) { return a.join(' '); }
// all possible types
var types = {
br: j( [b,r]),
lbr: j([l,b,r]),
lb: j([l,b] ),
tbr: j([t,b,r]),
tbl: j([t,b,l]),
tlr: j([t,l,r]),
tr: j([t,r] ),
tl: j([t,l] ),
locked: []
};
// store starting (base/locked) tiles in types.locked
with( types ) { locked = [
br, lbr, lbr, lb,
tbr, tbr, lbr, tbl,
tbr, tlr, tbl, tbl,
tr, tlr, tlr, tl
] }
return types;
})("top","left","bottom","right");
with。を使用すると、require.jsを使用するときにアリティを明示的に管理する必要がなくなります。
var modules = requirejs.declare([{
'App' : 'app/app'
}]);
require(modules.paths(), function() { with (modules.resolve(arguments)) {
App.run();
}});
requirejs.declareの実装:
requirejs.declare = function(dependencyPairs) {
var pair;
var dependencyKeys = [];
var dependencyValues = [];
for (var i=0, n=dependencyPairs.length; i<n; i++) {
pair = dependencyPairs[i];
for (var key in dependencyPairs[i]) {
dependencyKeys.push(key);
dependencyValues.push(pair[key]);
break;
}
};
return {
paths : function() {
return dependencyValues;
},
resolve : function(args) {
var modules = {};
for (var i=0, n=args.length; i<n; i++) {
modules[dependencyKeys[i]] = args[i];
}
return modules;
}
}
}
Andy EがShog9の回答のコメントで指摘したようにwith
、オブジェクトリテラルで使用すると、この潜在的に予期しない動作が発生します。
for (var i = 0; i < 3; i++) {
function toString() {
return 'a';
}
with ({num: i}) {
setTimeout(function() { console.log(num); }, 10);
console.log(toString()); // prints "[object Object]"
}
}
予期しない動作ではありませんでしたではないことをすでにの特徴with
。
それでもこの手法を使用したい場合は、少なくともプロトタイプがnullのオブジェクトを使用してください。
function scope(o) {
var ret = Object.create(null);
if (typeof o !== 'object') return ret;
Object.keys(o).forEach(function (key) {
ret[key] = o[key];
});
return ret;
}
for (var i = 0; i < 3; i++) {
function toString() {
return 'a';
}
with (scope({num: i})) {
setTimeout(function() { console.log(num); }, 10);
console.log(toString()); // prints "a"
}
}
ただし、これはES5 +でのみ機能します。また、使用しないでくださいwith
。
私は、ユーザーがアプリケーションの一部の動作を変更するためにコードをアップロードできるようにするプロジェクトに取り組んでいます。このシナリオでは、私はwith
句を使用して、コードの範囲外で、いじくりまわしたいコードを変更しないようにしています。これを行うために使用するコードの(簡略化された)部分は次のとおりです。
// this code is only executed once
var localScope = {
build: undefined,
// this is where all of the values I want to hide go; the list is rather long
window: undefined,
console: undefined,
...
};
with(localScope) {
build = function(userCode) {
eval('var builtFunction = function(options) {' + userCode + '}');
return builtFunction;
}
}
var build = localScope.build;
delete localScope.build;
// this is how I use the build method
var userCode = 'return "Hello, World!";';
var userFunction = build(userCode);
このコードは、ユーザー定義のコードが、グローバルスコープのオブジェクトなどにアクセスしたりwindow
、クロージャーを通じてローカル変数にアクセスしたりしないことを(ある程度)保証します。
賢明な言葉として、私はまだユーザーが送信したコードに対して静的コードチェックを実行して、グローバルスコープにアクセスするために他の卑劣な方法を使用していないことを確認する必要があります。たとえば、次のユーザー定義コードはへの直接アクセスを取得しますwindow
。
test = function() {
return this.window
};
return test();
俺の
switch(e.type) {
case gapi.drive.realtime.ErrorType.TOKEN_REFRESH_REQUIRED: blah
case gapi.drive.realtime.ErrorType.CLIENT_ERROR: blah
case gapi.drive.realtime.ErrorType.NOT_FOUND: blah
}
沸騰する
with(gapi.drive.realtime.ErrorType) {switch(e.type) {
case TOKEN_REFRESH_REQUIRED: blah
case CLIENT_ERROR: blah
case NOT_FOUND: blah
}}
低品質のコードを信頼できますか?いいえ、まったく読めなくなったようです。この例は、私が読みやすさを理解している場合、with-statementの必要がないことを明白に証明しています;)