web-dev-qa-db-ja.com

特定の機能に対してECMAscript厳格モードを無効にできますか?

MDCやECMAscript仕様に関する質問については、ここでは何も見つけられません。おそらく誰かがこれを解決するためのより「ハックな」方法を知っています。

私の環境のすべてのjavascriptファイルで"use strict"を呼び出しています。私のファイルはすべてこのように始まります

(function(win, doc, undef) {
    "use strict";

    // code & functions
}(window, window.document));

これで、エラーを処理するカスタム関数ができました。その関数は、.callerプロパティを使用して、コンテキストスタックトレースを提供します。次のようになります。

var chain = (function() {
    var _parent = _error,
        _ret = '';

    while( _parent.caller ) {
        _ret += ' -> ' + _parent.caller.name;
        _parent = _parent.caller;
    }

    return _ret;
}());

しかし、もちろん、厳格モードでは.callerは、取得時にスローされる削除不可能なプロップです。だから私の質問は、disable strict more "function-wise"への方法を知っている人はいますか?

"use strict";は、呼び出された後、すべての関数に継承されます。これで、特定の関数の先頭で"use strict";を呼び出すだけで特定の関数で厳密モードを使用できるようになりましたが、反対の方法を実現する方法はありますか?

67
jAndy

いいえ、機能ごとに厳格モードを無効にすることはできません。

Strictモードが機能することを理解することが重要ですlexically;意味—実行ではなく、関数宣言に影響します。 strictコード内のすべての関数declaredは、それ自体が厳密な関数になります。ただし、厳密なコード内からの関数calledは必ずしも厳密ではありません。

(function(sloppy) {
  "use strict";

   function strict() {
     // this function is strict, as it is _declared_ within strict code
   }

   strict();
   sloppy();

})(sloppy);

function sloppy(){
  // this function is not strict as it is _declared outside_ of strict code
}

関数を定義する方法に注意してください厳密なコードの外側、それから厳密な関数に渡します。

あなたの例で似たようなことをすることができます-「だらしない」関数を持つオブジェクトを持ち、そのオブジェクトをそのすぐに呼び出される厳密な関数に渡します。もちろん、「粗雑な」関数がメインのラッパー関数内から変数を参照する必要がある場合、それは機能しません。

また、 indirect eval —他の人から提案された—は、ここではあまり役に立ちません。グローバルコンテキストでコードを実行するだけです。ローカルで定義された関数を呼び出そうとしても、間接的なevalはそれを見つけさえしません:

(function(){
  "use strict";

  function whichDoesSomethingNaughty(){ /* ... */ }

  // ReferenceError as function is not globally accessible
  // and indirect eval obviously tries to "find" it in global scope
  (1,eval)('whichDoesSomethingNaughty')();

})();

グローバルevalに関するこの混乱は、おそらく、グローバルevalを使用して、厳密モード(これ以上thisを介してアクセスできない)からグローバルオブジェクトへのアクセスを取得できるという事実に起因しています。

(function(){
  "use strict";

  this; // undefined
  (1,eval)('this'); // global object
})();

しかし、質問に戻って...

Functionコンストラクターを介してちょっとしたチートと新しい関数の宣言ができます。これはnot inherit strictnessに起こりますが、それは(非標準の)関数の逆コンパイルに依存し、 外部変数を参照する機能を失う

(function(){
  "use strict";

  function strict(){ /* ... */ }

  // compile new function from the string representation of another one
  var sneaky = Function('return (' + strict + ')()');

  sneaky();
})();

FF4 +は(私の知る限り)仕様に同意していないようであり、Functionを介して作成された関数を厳格としてマークします。これは、他の strict-mode-supporting implementation (Chrome 12+、IE10、WebKit)などでは発生しません。

78
kangax

http://javascriptweblog.wordpress.com/2011/05/03/javascript-strict-mode/ から)

(...)ストリクトモードは、ストリクト関数の本体内で呼び出される非ストリクト関数には適用されません(引数として渡されるか、callまたはapplyを使用して呼び出されるため) 。

したがって、厳格モードを使用せずに別のファイルでエラーメソッドを設定し、次のようにそれらをパラメータとして渡す場合:

var test = function(fn) {
  'use strict';
  fn();
}

var deleteNonConfigurable = function () {
  var obj = {};
  Object.defineProperty(obj, "name", {
    configurable: false
  });
  delete obj.name; //will throw TypeError in Strict Mode
}

test(deleteNonConfigurable); //no error (Strict Mode not enforced)

...動作するはずです。

3
Niloct

代替手段はこれを単に行うことです

var stack;
if (console && console.trace) {
     stack = console.trace();
} else {
    try {
        var fail = 1 / 0;
    } catch (e) {
        if (e.stack) {
            stack = e.stack;
        } else if (e.stacktrace) {
            stack = e.stacktrace;
        }
    }
}
// have fun implementing normalize.
return normalize(stack);
2
Raynos