JavaScript中使用“嚴格使用”是什麼,它背後的原因是什麼?


Answers

這是ECMAScript 5的一個新功能。John Resig寫了一個很好的總結

它只是一個你放入JavaScript文件的字符串(無論是在你的文件的頂部還是在函數的內部),看起來像這樣:

"use strict";

現在將它放入代碼中不應該對當前瀏覽器造成任何問題,因為它只是一個字符串。 如果您的代碼違反了編譯指示,將來可能會導致代碼出現問題。 例如,如果你現在有foo = "bar"而沒有先定義foo ,你的代碼就會失敗......這在我看來是一件好事。

Question

最近,我通過Crockford的JSLint運行了一些JavaScript代碼,並給出了以下錯誤:

第1行的問題字符1:缺少“使用嚴格”語句。

做一些搜索,我意識到有些人加上"use strict"; 到他們的JavaScript代碼中。 一旦我添加了該語句,錯誤就會停止顯示。 不幸的是,Google沒有透露這個字符串聲明背後的大部分歷史。 當然,它必須與JavaScript如何被瀏覽器解釋有關,但我不知道會產生什麼效果。

那麼什麼是"use strict"; 所有關於,它意味著什麼,它仍然是相關的?

目前的瀏覽器是否對"use strict";做出回應"use strict"; 字符串還是將來使用?




如果您使用過去一年左右發布的瀏覽器,那麼它很可能支持JavaScript嚴格模式。 在ECMAScript 5成為當前標準之前,只有較老的瀏覽器才支持它。

命令周圍的引號確保代碼在舊版瀏覽器中仍能正常工作(儘管在嚴格模式下產生語法錯誤的東西通常只會導致腳本在某些較舊的瀏覽器中難以檢測到故障)。




There's a good talk by some people who were on the ECMAScript committee: Changes to JavaScript, Part 1: ECMAScript 5" about how incremental use of the "use strict" switch allows JavaScript implementers to clean up a lot of the dangerous features of JavaScript without suddenly breaking every website in the world.

Of course it also talks about just what a lot of those misfeatures are (were) and how ECMAScript 5 fixes them.




Note that use strict was introduced in EcmaScript 5 and was kept since then.

Below are the conditions to trigger strict mode in ES6 and ES7 :

  • Global code is strict mode code if it begins with a Directive Prologue that contains a Use Strict Directive (see 14.1.1).
  • Module code is always strict mode code.
  • All parts of a ClassDeclaration or a ClassExpression are strict mode code.
  • Eval code is strict mode code if it begins with a Directive Prologue that contains a Use Strict Directive or if the call to eval is a direct eval (see 12.3.4.1) that is contained in strict mode code.
  • Function code is strict mode code if the associated FunctionDeclaration, FunctionExpression, GeneratorDeclaration, GeneratorExpression, MethodDefinition, or ArrowFunction is contained in strict mode code or if the code that produces the value of the function's [[ECMAScriptCode]] internal slot begins with a Directive Prologue that contains a Use Strict Directive.
  • Function code that is supplied as the arguments to the built-in Function and Generator constructors is strict mode code if the last argument is a String that when processed is a FunctionBody that begins with a Directive Prologue that contains a Use Strict Directive.



"use strict"; is the ECMA effort to make JavaScript a little bit more robust. It brings in JS an attempt to make it at least a little "strict" (other languages implement strict rules since the 90s). It actually "forces" JavaScript developers to follow some sort of coding best practices. Still, JavaScript is very fragile. There is no such thing as typed variables, typed methods, etc. I strongly recommend JavaScript developers to learn a more robust language such as Java or ActionScript3, and implement the same best practices in your JavaScript code, it will work better and be easier to debug.




我想提供一個更為成熟的答案,補充其他答案。 我希望編輯最流行的答案,但失敗了。 我試圖盡可能全面和完整地完成它。

您可以參考MDN文檔以獲取更多信息。

"use strict" ECMAScript 5中引入的指令。

指令與陳述類似,但不同。

  • use strict不包含關鍵字:該指令是一個簡單的表達式語句,它由一個特殊的字符串文字(單引號或雙引號)組成。 沒有實現ECMAScript 5的JavaScript引擎只能看到沒有副作用的表達式語句。 預計未來版本的ECMAScript標準將use作為一個真正的關鍵詞; 報價將因此變得過時。
  • use strict只能在腳本或函數的開頭使用,即它必須在每隔一個(真實)語句之前。 它不一定是函數腳本中的第一條指令:它可以由包含字符串文本的其他語句表達式(以及JavaScript實現可以將它們視為特定於實現的指令)作為前綴。 遵循第一個真實語句(在腳本或函數中)的字符串文字語句是簡單的表達式語句。 口譯員不得將其解釋為指示,並且不起作用。

use strict指令表示以下代碼(在腳本或函數中)是嚴格代碼。 當腳本包含use strict指令時,腳本最高級別的代碼(不在函數中的代碼)被視為嚴格代碼。 當函數本身在嚴格代碼中定義或函數包含use strict指令時,函數的內容被視為嚴格代碼。 當從嚴格代碼調用eval()或包含use strict指令本身時,傳遞給eval()方法的代碼被視為嚴格代碼。

ECMAScript 5的嚴格模式是JavaScript語言的一個受限子集,它消除了語言的相關缺陷,並具有更嚴格的錯誤檢查和更高的安全性。 下面列出了嚴格模式和正常模式之間的區別(其中前三個特別重要):

  • 嚴格模式下不能使用with -statement。
  • 在嚴格模式下,所有變量都必須聲明:如果您為尚未聲明為全局Object變量,函數,函數參數,catch-clause參數或屬性的標識符賦值,則會得到一個ReferenceError 。 在正常模式下,標識符被隱式聲明為全局變量(作為全局Object的屬性)
  • 在嚴格模式下,這個關鍵字的值在未被調用為函數的函數中(而不是方法) undefined 。 (在正常模式下, this總是指向全局Object )。 這種差異可用於測試實現是否支持嚴格模式:
var hasStrictMode = (function() { "use strict"; return this===undefined }());
  • 另外,當通過call()調用函數或在嚴格模式下apply函數時,則this正是call()apply()調用的第一個參數的值。 (在正常模式下, nullundefined被全局Object替代,而不是對象的值被轉換為對象。)

  • 在嚴格模式下,當您嘗試分配給只讀屬性或為不可擴展對象定義新屬性時,您將得到一個TypeError 。 (在正常模式下,兩者都會失敗,沒有錯誤信息。)

  • 在嚴格模式下,將代碼傳遞給eval() ,不能在調用者的範圍內聲明或定義變量或函數(正如您在普通模式下所做的那樣)。 相反,為eval()創建一個新的作用域,並且變量和函數在該範圍內。 eval()完成執行後,該範圍被銷毀。
  • 在嚴格模式下,函數的arguments-object包含值的靜態副本,並將其傳遞給該函數。 在正常模式下,arguments-object有一些“神奇”的行為:數組的元素和指定的函數參數引用兩個相同的值。
  • 在嚴格模式下,當delete操作符後跟非標準標識符(變量,函數或函數參數)時,您將收到SyntaxError 。 在正常模式下, delete表達式不會執行任何操作,並且評估為false
  • 在嚴格模式下,當你嘗試刪除一個不可配置的屬性時,你會得到一個TypeError 。 (在正常模式下,嘗試簡單失敗, delete表達式評估為false )。
  • 在嚴格模式下,當您嘗試為對象文字定義具有相同名稱的多個屬性時,將其視為語法錯誤。 (在正常模式下沒有錯誤。)
  • 在嚴格模式下,當函數聲明具有多個具有相同名稱的參數時,它被認為是語法錯誤。 (在正常模式下沒有錯誤。)
  • 在嚴格模式下,不允許使用八進製文字(這些是以0x文字)(在正常模式下,某些實現允許使用八進製文字)。
  • 在嚴格模式下,標識符evalarguments被視為關鍵字。 你不能改變它們的值,不能給它們賦值,也不能用它們作為變量,函數,函數參數或catch塊標識符的名字。
  • 在嚴格模式下,對檢查調用堆棧的可能性有更多的限制。 arguments.callerarguments.callee在嚴格模式下在函數中導致TypeError 。 此外,當您嘗試讀取函數時,嚴格模式下函數的某些調用方和參數屬性會導致TypeError



Just wanted to add some more points.

The Reason to Use Strict Mode--->

  • Strict mode makes it easier to write "secure" JavaScript.

  • Strict mode changes previously accepted "bad syntax" into real
    錯誤。

  • As an example, in normal JavaScript, mistyping a variable name
    creates a new global variable.

  • In strict mode, this will throw an error, making it impossible to accidentally create a global variable.

  • In strict mode, any assignment to a non-writable property, a
    getter-only property, a non-existing property, a non-existing
    variable, or a non-existing object, will throw an error.

The things that will throw errors in Strict Mode Using a variable, without declaring it, is not allowed:

"use strict";
 x = 3.14;                // This will cause an error

Objects are variables too.

Using an object, without declaring it, is not allowed:

  "use strict";
  x = {p1:10, p2:20};      // This will cause an error

Deleting a variable (or object) is not allowed.

  "use strict";
   var x = 3.14;
   delete x;                // This will cause an error

For security reasons, eval() is not allowed to create variables in the scope from which it was called:

"use strict";
 eval ("var x = 2");
 alert (x);               // This will cause an error

In function calls like f(), the this value was the global object. In strict mode, it is now undefined.

"use strict" is only recognized at the beginning of a script.




When adding "use strict"; , the following cases will throw a SyntaxError before the script is executing:

  • Paving the way for future ECMAScript versions , using one of the newly reserved keywords (in prevision for ECMAScript 6 ): implements , interface , let , package , private , protected , public , static , and yield .

  • Declaring function in blocks

    if(a<b){ function f(){} }
    
  • Octal syntax

    var n = 023;
    
  • this point to the global object.

     function f() {
          "use strict";
          this.a = 1;
     };
     f(); 
    
  • Declaring twice the same name for a property name in an object literal

     {a: 1, b: 3, a: 7} 
    

    This is no longer the case in ECMAScript 6 ( bug 1041128 ).

  • Declaring two function arguments with the same name function

    f(a, b, b){}
    
  • Setting a value to an undeclared variable

    function f(x){
       "use strict";
       var a = 12;
       b = a + x*35; // error!
    }
    f();
    
  • Using delete on a variable name delete myVariable;

  • Using eval or arguments as variable or function argument name

    "use strict";
    arguments++;
    var obj = { set p(arguments) { } };
    try { } catch (arguments) { }
    function arguments() { } 
    

Sources:




使用'use strict'; 不會突然讓你的代碼更好。

JavaScript嚴格模式ECMAScript 5中的一項功能。 您可以通過在腳本/函數的頂部聲明它來啟用嚴格模式。

'use strict';

當JavaScript引擎看到這個指令時 ,它將開始以特殊模式解釋代碼。 在這種模式下,當某些編碼實踐可能最終成為潛在的錯誤時(這是嚴格模式背後的原因),錯誤會被拋出。

考慮這個例子:

var a = 365;
var b = 030;

在排列數字文字時,開發人員無意中用八進製文字初始化了變量b 。 非嚴格模式會將其解釋為值為24的數字文字(以10為底)。 但是,嚴格模式會引發錯誤。

對於嚴格模式下非詳盡的專業列表,請參閱此答案 。

我應該在哪裡使用'use strict';

  • 在我的 JavaScript應用程序中: 絕對! 當你對你的代碼做一些愚蠢的事時,嚴格模式可以用作舉報者。

  • 在我現有的 JavaScript代碼中: 可能不是! 如果您現有的JavaScript代碼有嚴格模式禁止的語句,則應用程序將會中斷。 如果你想要嚴格模式,你應該準備好調試和糾正你現有的代碼。 這就是為什麼使用'use strict'; 不會突然讓你的代碼更好

我如何使用嚴格模式?

  1. 插入'use strict'; 在你的腳本之上的聲明:

    // File: myscript.js
    
    'use strict';
    var a = 2;
    ....
    

    請注意,文件myscript.js中的所有內容都將以嚴格模式進行解釋。

  2. 或者,插入'use strict'; 聲明在你的函數體之上:

    function doSomething() {
        'use strict';
        ...
    }
    

    函數doSomething詞彙範圍中的所有內容都將以嚴格模式進行解釋。 詞彙範圍這個詞在這裡很重要。 看到這個答案更好的解釋。

什麼東西在嚴格模式下被禁止?

我發現了一篇很好的文章,描述了在嚴格模式下禁止的幾件事情(請注意,這不是一個獨占列表):

範圍

歷史上,JavaScript一直困惑於函數的作用域如何。 有時它們似乎是靜態範圍的,但有些功能會使它們像動態範圍一樣運行。 這很混亂,使得程序難以閱讀和理解。 誤解導致錯誤。 這也是一個性能問題。 靜態範圍設定將允許變量綁定在編譯時發生,但動態範圍的要求意味著綁定必須延遲到運行時,這會帶來顯著的性能損失。

嚴格模式要求所有變量綁定都要靜態完成。 這意味著之前需要動態綁定的功能必須被刪除或修改。 特別是,with語句被消除,並且eval函數篡改調用者環境的能力受到嚴格限制。

嚴格代碼的好處之一是,像YUI Compressor這樣的工具在處理它時可以做得更好。

隱含的全局變量

JavaScript暗含著全局變量。 如果你沒有顯式地聲明一個變量,那麼為你隱式聲明一個全局變量。 這使初學者的編程更容易,因為他們可以忽略他們的一些基本的家務勞動。 但是這使得大型項目的管理變得更加困難,並且顯著降低了可靠性。 所以在嚴格模式下,隱含的全局變量不再被創建。 你應該明確地聲明所有的變量。

全球洩漏

有很多情況可能會導致this情況被綁定到全局對象。 例如,如果在調用構造函數時忘記提供new前綴,則構造函數的this將被意外地綁定到全局對象,所以不是初始化一個新對象,而是默默地篡改全局變量。 在這些情況下,嚴格模式會將其綁定到undefined ,這將導致構造函數拋出異常,從而允許更快地檢測到錯誤。

嘈雜的失敗

JavaScript一直具有隻讀屬性,但是直到ES5的Object.createProperty函數公開該功能之前,您才能創建它們。 如果您試圖將值分配給只讀屬性,則它將以無提示方式失敗。 作業不會改變該屬性的值,但程序會像進行一樣繼續。 這是一種可能導致程序進入不一致狀態的完整性危害。 在嚴格模式下,嘗試更改只讀屬性會引發異常。

八進制

在字長為3的倍數的機器上進行機器級編程時,八進制(或基數為8)的數字表示非常有用。使用字長為60位的CDC 6600主機時,需要八進制數。 如果你能讀八進制數,你可以看一個字作為20位數字。 兩個數字表示操作碼,一個數字表示8個寄存器之一。 在從機器代碼到高級語言的緩慢過渡期間,認為在編程語言中提供八進制形式是有用的。

在C中,選擇了一個非常不幸的八進製表示法:前導零。 所以在C語言中, 0100表示64而不是0100表示錯誤,而不是8.更糟糕的是,這種時代錯誤已經被複製到幾乎所有現代語言中,包括JavaScript,它只被用於創建錯誤。 它沒有其他目的。 所以在嚴格模式下,不再允許使用八進制格式。

等等

參數偽數組在ES5中變得更像數組。 在嚴格模式下,它會丟失其calleecaller屬性。 這使得將您的arguments傳遞給不可信的代碼成為可能,而不會放棄很多機密上下文。 此外,函數的arguments屬性被消除。

在嚴格模式下,函數文字中的重複鍵會產生語法錯誤。 一個函數不能有兩個具有相同名稱的參數。 一個函數不能有一個與其參數名稱相同的變量。 一個函數不能delete它自己的變量。 嘗試delete不可配置的屬性現在會引發異常。 原始值不會隱式包裝。

未來JavaScript版本的保留字

ECMAScript 5添加了一個保留字列表。 如果您將它們用作變量或參數,則嚴格模式會引發錯誤。 保留字是:

implementsinterfaceletpackageprivateprotectedpublicstaticyield

進一步閱讀




The main reasons why developers should use "use strict" are:

  1. Prevents accidental declaration of global variables.Using "use strict()" will make sure that variables are declared with var before use. 例如:

    function useStrictDemo(){
     'use strict';
     //works fine
     var a = 'No Problem';
    
     //does not work fine and throws error
     k = "problem"
    
     //even this will throw error
     someObject = {'problem': 'lot of problem'};
    }
    
  2. NB: The "use strict" directive is only recognized at the beginning of a script or a function.
  3. The string "arguments" cannot be used as a variable:

    "use strict";
    var arguments = 3.14;    // This will cause an error
    
  4. Will restrict uses of keywords as variables. Trying to use them will throw errors.

In short will make your code less error prone and in turn will make you write good code.

To read more about it you can refer http://www.w3schools.com/js/js_strict.asp .




Normally java script does not follow strict rules hence increasing chances of errors. After using "use strict" , the java script code should follow strict set of rules as like in other programming languages such as use of terminators, declaration before initialization etc.

If "use strict" is used then the code should be written by following a strict set of rules hence decreasing the chances of errors and ambiguities.




“嚴格使用”; 是程序員不會使用JavaScript的鬆散或不良屬性的保險。 這是一個指導,就像統治者會幫助你制定直線一樣。 “嚴格使用”將有助於您進行“直接編碼”。

那些寧願不使用統治者直線行的人通常會在那些要求他人調試他們的代碼的頁面中結束。

相信我。 與設計不佳的代碼相比,開銷可以忽略不計。 多年來一直擔任高級JavaScript開發人員的Doug Crockford在這裡發表了一篇非常有趣的文章 。 就我個人而言,我總是喜歡回到他的網站,以確保我不會忘記我的良好做法。

現代JavaScript實踐應該始終喚起“嚴格使用”; 附註。 The only reason that the ECMA Group has made the "Strict" mode optional is to permit less experienced coders access to JavaScript and give then time to adapt to the new and safer coding practices.




如果人們擔心use strict ,可能值得看看這篇文章:

ECMAScript 5'瀏覽器中的嚴格模式'支持。 這是什麼意思?
NovoGeek.com - 克里希納的博客

它討論瀏覽器支持,但更重要的是如何安全地處理它:

function isStrictMode(){
    return !this;
} 
/*
   returns false, since 'this' refers to global object and 
   '!this' becomes false
*/

function isStrictMode(){   
    "use strict";
    return !this;
} 
/* 
   returns true, since in strict mode the keyword 'this'
   does not refer to global object, unlike traditional JS. 
   So here, 'this' is 'undefined' and '!this' becomes true.
*/





Related