题 JavaScript中使用“严格”做什么,背后的原因是什么?


最近,我通过Crockford运行了一些JavaScript代码 JSLint的,它给出了以下错误:

第1行问题1:缺少“使用严格”声明。

做一些搜索,我意识到有些人补充道 "use strict"; 进入他们的JavaScript代码。一旦我添加了语句,错误就会停止显示。不幸的是,谷歌没有透露这个字符串声明背后的历史。当然它必须与浏览器如何解释JavaScript有关,但我不知道效果会是什么。

那是什么 "use strict"; 一切,它意味着什么,它仍然相关吗?

当前任何浏览器都会响应 "use strict"; 字符串或将来使用?


6712
2017-08-26 16:10


起源




答案:


这篇关于Javascript Strict Mode的文章可能会让您感兴趣: John Resig - ECMAScript 5严格模式,JSON等

引用一些有趣的部分:

严格模式是ECMAScript 5中的一项新功能,允许您在“严格”操作上下文中放置程序或函数。这种严格的上下文阻止了某些操作被采取并引发更多异常。

和:

严格模式有两种方式:

  • 它捕获了一些常见的编码bloopers,抛出异常。
  • 当采取相对“不安全”的操作(例如获取对全局对象的访问权限)时,它会阻止或抛出错误。
  • 它会禁用令人困惑或经过深思熟虑的功能。

另请注意,您可以对整个文件应用“严格模式”...或者您只能将其用于特定功能 (仍引用John Resig的文章)

// Non-strict code...

(function(){
  "use strict";

  // Define your library strictly...
})();

// Non-strict code... 

如果你必须混合旧代码和新代码,这可能会有所帮助;-)

所以,我想这有点像 "use strict" 你可以在Perl中使用 (由此得名?):通过检测可能导致破损的更多事情,它可以帮助您减少错误。

目前,它是 所有主流浏览器都支持  (IE 9及以下)


4399
2017-08-26 16:15



这么多年后改变默认值?太迟了:它会打破这么多现有的网站/脚本/应用程序......唯一可能的事情是帮助改善未来的事情。 - Pascal MARTIN
我尝试了一个使用时无效的小代码片段 "use strict" 在Firefox 3.6,Safari 5,Chrome 7和Opera 10.6(所有Mac)中。没有任何错误,所以我猜任何浏览器都不支持'use strict'。虽然没有在IE9中测试;) - Husky
快速更新:Firefox 4完全支持严格模式,据我所知,没有其他浏览器可以。 Safari和Chrome有“部分”支持,但我真的不知道这意味着什么。 - Sasha Chedygov
Chrome 11似乎和IE10一样通过了所有这些测试 ie.microsoft.com/testdrive/HTML5/TryStrict/Default.html# - gman
@Julius - 这可能不是使用保留关键字实现的,因为尝试触发严格模式的代码会在旧浏览器中中断。添加“随机”字符串文字不会破坏任何内容。 - nnnnnn


这是ECMAScript 5的新功能.John Resig写道 一个很好的总结 它

它只是一个放在JavaScript文件中的字符串(位于文件顶部或函数内部),如下所示:

"use strict";

现在将它放在你的代码中不应该导致当前浏览器出现任何问题,因为它只是一个字符串。如果您的代码违反了编译指示,将来可能会导致您的代码出现问题。例如,如果你现在有 foo = "bar" 没有定义 foo 首先,你的代码将开始失败......在我看来这是一件好事。


1103
2017-08-26 16:14



快速失败并大声失败。 - Niels Bom
如果您在HTML文件中编写内联Javascript,请使用以下命令启动每个新块 <script>"use strict";。该标志仅适用于包含它的块。 - nobar
这很有趣,这导致字符串必须有单引号。所以写 'use strict'; 代替 - nilsi
然后javascript的提升概念会发生什么? - Sunil Sharma
@SunilSharma如果您尝试提升,但由于未定义变量而失败,此时它会将其添加到全局对象。同 "use strict";,它会失败。这更有意义,因为如果它将它添加到全局对象,这意味着它可能在下次运行函数时不起作用/执行重置块的其他操作,因为它将位于最高块(全局)中。 - wizzwizz4


该声明 "use strict"; 指示浏览器使用严格模式,这是一种简化且更安全的JavaScript功能集。

功能列表(非详尽)

  1. 不允许全局变量。 (抓到了失踪 var 变量名中的声明和拼写错误)

  2. 无提示失败的分配将在严格模式下抛出错误(分配 NaN = 5;

  3. 尝试删除不可删除的属性将抛出(delete Object.prototype

  4. 要求对象文字中的所有属性名称都是唯一的(var x = {x1: "1", x1: "2"}

  5. 函数参数名称必须是唯一的(function sum (x, x) {...}

  6. 禁止八进制语法(var x = 023; 一些开发者错误地假设前面的零点没有改变数字。)

  7. 禁止 with 关键词

  8. eval 在严格模式下不会引入新变量

  9. 禁止删除普通名称(delete x;

  10. 禁止绑定或分配名称 eval 和 arguments 以任何形式

  11. 严格模式不包含属性 arguments 具有形式参数的对象。 (即在...中 function sum (a,b) { return arguments[0] + b;} 这是因为 arguments[0] 一定会 a 等等。 )

  12. arguments.callee 不受支持

[参考: 严格的模式Mozilla开发者网络]


519
2017-11-24 21:22



Nit:允许全局变量,只需要明确(例如 window.foo = bar)。 - gcampbell
要求对象文字中的所有属性名称都是唯一的(var x = {x1:“1”,x1:“2”})这是有效的 - Arun Killu
您在11中的示例缺少对a的修改(否则没有意义)。 I. e。函数和(a,b){a = 0; return arguments [0] + b;由于别名,alert(sum(1,2))将返回3,严格模式,2,没有严格模式。 - David Gausmann
你刚刚用#6节省了我几个小时的调试时间 - jazzcat


如果人们担心使用 use strict 可能值得查看这篇文章:

ECMAScript 5在浏览器中支持“严格模式”。这是什么意思?
NovoGeek.com - Krishna的博客

它讨论了浏览器支持,但更重要的是如何安全地处理它:

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.
*/

369
2017-07-15 23:25



我不同意。我认为这说明了它非常有用的原因。本质上它意味着它返回它的功能而不是它 window - Jamie Hutber
你什么时候想要窗户 this 那是你不能瞄准的 window? - Jamie Hutber
它指的是它自己。 this 属于自己的功能,而不是全局窗口 - Jamie Hutber
在第二个 this 一个是 undefined。 - Broxzier
关键是你的JS程序会因为访问未定义的属性而开始失败,而不是在全局对象上默默地做错事。使跟踪微妙的错误更容易。 - Stephen Chung


需要注意的是,所有难以为之付费的程序员:应用 "use strict" 现有代码可能有危险!这个东西不是一些感觉良好,快乐的贴纸,你可以打上代码,让它“更好”。随着 "use strict" pragma,浏览器会突然在随机的地方突然出现异常,因为在那个地方你正在做一些默认/松散的JavaScript快乐允许但严格的JavaScript憎恶!你可能有严格的违规行为隐藏在代码中很少使用的调用中,这些调用只会在最终运行时抛出异常 - 例如,在付费客户使用的生产环境中!

如果你想要冒险,最好申请 "use strict" 除了全面的单元测试和严格配置的JSHint构建任务之外,还可以让您确信模块中没有黑暗的角落会因为您打开严格模式而可怕地爆炸。或者,嘿,这是另一种选择:只是不添加 "use strict" 对于任何遗留代码,老实说,它可能更安全。 绝对不要 加 "use strict" 您不拥有或维护的任何模块,例如第三方模块。

我想即使它是一种致命的笼养动物, "use strict" 可以是好东西,但你必须做得对。严格要求的最佳时机是您的项目是绿地并且您从头开始。配置 JSHint/JSLint 所有的警告和选项都像你的团队一样紧张,得到一个良好的构建/测试/断言系统 Grunt+Karma+Chai,然后只开始将所有新模块标记为 "use strict"。准备好治愈许多琐碎的错误和警告。如果将构建配置为FAIL,请确保每个人都了解重力 JSHint/JSLint产生任何违规行为

当我采纳时,我的项目不是一个绿地项目 "use strict"。结果,我的IDE充满了红色标记,因为我没有 "use strict" 在我的一半模块上,JSHint抱怨这一点。这让我想起了将来我应该做什么重构。我的目标是因为我所有的遗失而成为红色标记 "use strict" 声明,但现在已经有几年了。


182
2018-03-03 07:37



为什么这个线程中的开发人员如此傲慢地使用“严格使用”?它出现了例外情况 否则工作JavaScript为了善良的缘故!把它洒在像玉米片上的糖一样的代码上,是吗?没有!坏!应谨慎使用“use strict”,最好只在您控制的代码中使用,该代码具有针对所有主要浏览器并且运行所有代码路径的单元测试。你有测试吗?好吧,“使用严格”对你来说没问题,你可以自己敲门。 - DWoldrich
是。显然,“使用严格”可以打破看似有效的javascript,这在以前没有打破过。但是之前没有破解过的代码并不等于代码是正确的并且做了它应该做的事情。通常引用未声明的变量会发出错误信号等。使用严格允许您捕获这些类型的错误,并希望在您发布生产代码之前。 - Jostein Kjønigsen
...或者只是将“使用严格”作为最后一遍代码的一部分,修复所有明显的问题,耸耸肩,说“足够好”,然后把它拿出去制作:) - Wolfie Inu
就个人而言,我从来没有/很少 加  "use strict"; 现有代码。话虽这么说,当我从头开始编写新代码时,我几乎总是会使用它 - Martin
如果您已经在使用JSLint,那么您可能已经修复了大多数“use strict”会破坏事物的地方。 - Jonathan Cast


运用 '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语句是   淘汰,以及评估功能的篡改能力   其来电者的环境受到严格限制。

严格的代码的好处之一是像工具一样 YUI压缩机   在处理它时可以做得更好。

隐含的全局变量

JavaScript隐含了全局变量。如果   你没有显式声明一个变量,一个全局变量是   隐含地为你宣布。这使编程更容易   初学者,因为他们可以忽略一些基本的家务   家务。但它使更大程序的管理更多   困难,它显着降低了可靠性。严格来说   模式,不再创建隐含的全局变量。你应该   明确声明所有变量。

全球泄漏

有许多情况可能导致 this   绑定到全局对象。例如,如果你忘了   提供 new 调用构造函数时的前缀,   构造函数的 this 将意外地绑定到全局对象,所以   而不是初始化一个新对象,它将是静默的   篡改全局变量。在这些情况下,严格模式会   而是绑定 this 至 undefined,这将导致构造函数   抛出异常,允许检测错误   更早。

吵闹失败

JavaScript一直都有只读属性,但是你   在ES5之前不能自己制作它们 Object.createProperty   功能暴露了这种能力。如果您尝试分配值   对于只读属性,它将无声地失败。任务将   不更改属性的值,但您的程序将继续执行   虽然它有。这是一种可导致程序的完整性危害   进入一个不一致的状态。在严格模式下,尝试更改   只读属性将抛出异常。

八进制

数字的八进制(或基数8)表示极其重要   在使用word的机器上进行机器级编程时很有用   大小是3的倍数。在使用CDC时,您需要八进制   6600主机,字长为60位。如果你能读懂   八进制,你可以看一个单词为20位数。代表两位数   操作码,一位数字识别出8个寄存器中的一个。在此期间   从机器代码到高级语言的缓慢过渡,确实如此   被认为在编程语言中提供八进制形式很有用。

在C中,一个非常不幸的八进制表示是   选中:领先零。所以在C中 0100 意味着64,而不是100,和 08 是一个   错误,而不是8.更不幸的是,这种时代错误已经存在   复制到几乎所有现代语言,包括JavaScript,在哪里   它仅用于创建错误。它没有其他目的。所以   严格模式,不再允许八进制形式。

等等

参数伪数组变得多一点   ES5中的数组类似。在严格模式下,它失去了它 callee 和 caller   属性。这使你有可能通过你的 arguments 不信任   代码没有放弃很多保密的背景。而且,    arguments 功能的属性被消除。

在严格模式下,函数文字中的重复键将产生一个   语法错误。函数不能有两个具有相同名称的参数。   函数不能具有与其中一个名称相同的变量   参数。一个功能不能 delete 它自己的变量。试图    delete 不可配置的属性现在抛出异常。原始   值不是隐式包装的。


未来JavaScript版本的保留字

ECMAScript 5添加了一个保留字列表。如果将它们用作变量或参数,则严格模式将引发错误。保留字是:

implementsinterfaceletpackageprivateprotectedpublicstatic,和 yield


进一步阅读


131
2018-01-29 11:35



这是非常好的解释。但是,我有一个疑问,我可以将“严格”模式与其他java脚本库(如Angular js)结合使用吗? - UVM
@UVM:strict-mode指令仅影响词法范围。即只声明它的文件/功能。如果你有另一个没有的文件/功能 'use strict' 指令,它们将以非严格模式执行,即使从以严格模式运行的函数调用时也是如此。看到 这个asnwer 作出解释。 - Krumia
谢谢你的解释。据我所知,“严格”模式只影响“代码”,而不影响“执行” - UVM
再来看,你是对的。我以为你的意思是它只抛出异常,但没有改变代码的工作方式(比如改变 this)。现在我看到你指的是调用其他功能。 - CyberEd
在某些情况下,八进制是有用的。它的C语法是可怕的,但我希望看到语言添加一个新的八进制语法,然后可以允许前零表单被弃用。当然,对于支持前导零形式的Javascript来说只是愚蠢。 - supercat


我强烈建议每个开发人员现在开始使用严格模式。有足够的浏览器支持它,严格的模式将合法地帮助我们避免我们甚至不知道你的代码中的错误。

显然,在初始阶段,我们以前从未遇到过错误。为了获得全部好处,我们需要在切换到严格模式后进行适当的测试,以确保我们已经捕获了所有内容。绝对我们不只是扔 use strict 在我们的代码中并假设没有错误。所以,流失是时候开始使用这个非常有用的语言功能来编写更好的代码。

例如,

var person = {
    name : 'xyz',
    position : 'abc',
    fullname : function () {  "use strict"; return this.name; }
};

JSLint的 是Douglas Crockford编写的调试器。只需粘贴您的脚本,它就会快速扫描代码中的任何明显问题和错误。


122
2017-07-05 19:38



@JamieHutber:请访问此链接 caniuse.com/use-strict  和 kangax.github.io/es5-compat-table。它将为所有浏览器提供准确的想法。 - Pank


我想提供一个更有根据的答案,补充其他答案。我希望编辑最流行的答案,但失败了。我试图让它尽可能全面和完整。

你可以参考 MDN文档 了解更多信息。

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

指令与陈述类似,但不同。

  • use strict 不包含关键字:该指令是一个简单的表达式语句,它由一个特殊的字符串文字(单引号或双引号)组成。没有实现ECMAScript 5的JavaScript引擎只能看到没有副作用的表达式语句。预计将引入ECMAScript标准的未来版本 use 作为一个真正的关键词;因此报价将变得过时。
  • use strict 只能在脚本或函数的开头使用,即它必须在每个其他(真实)语句之前。它不必是函数脚本中的第一条指令:它可以在其他由字符串文字组成的语句表达式之前(并且JavaScript实现可以将它们视为特定于实现的指令)。字符串文字语句遵循第一个真实语句(在脚本或函数中)是简单的表达式语句。口译员不得将其解释为指令,也不得影响。

use strict指令表示以下代码(在脚本或函数中)是严格的代码。 当脚本包含a时,脚本最高级别的代码(不在函数中的代码)被视为严格代码 use strict 指示。 当函数本身在严格的代码中定义或函数包含a时,函数的内容被认为是严格的代码 use strict 指示。 传递给的代码 eval() 方法被认为是严格的代码 eval() 是从严格的代码调用或包含 use strict 指令本身。

ECMAScript 5的严格模式是JavaScript语言的有限子集,它消除了语言的相关缺陷,并具有更严格的错误检查和更高的安全性。以下列出了严格模式和普通模式之间的区别(前三个特别重要):

  • 你不能使用 with-statement在严格模式下。
  • 在严格模式下,必须声明所有变量:如果为尚未声明为变量的标识符,函数,函数参数,catch-clause参数或全局属性赋值 Object那么你会得到一个 ReferenceError。在正常模式下,标识符被隐式声明为全局变量(作为全局变量的属性) Object
  • 在严格模式下关键字 this 有价值 undefined 在作为函数调用的函数中(而不是作为方法)。 (在正常模式下 this 总是指向全球 Object)。这种差异可用于测试实现是否支持严格模式:
var hasStrictMode = (function() { "use strict"; return this===undefined }());
  • 当调用函数时也是如此 call() 要么 apply 那么在严格模式下 this 正好是第一个参数的值 call()要么 apply() 调用。 (在正常模式下 null 和 undefined 被全球取代 Object 和值,不是对象,被强制转换为对象。)

  • 在严格模式下,你会得到一个 TypeError,当您尝试分配给只读属性或为不可扩展的对象定义新属性时。 (在正常模式下,两者都会失败而没有错误消息。)

  • 在严格模式下,将代码传递给 eval(),您不能在调用者的范围内声明或定义变量或函数(因为您可以在正常模式下执行)。相反,为其创建了一个新范围 eval() 变量和函数都在该范围内。该范围在之后被销毁 eval() 完成执行。
  • 在严格模式下,函数的arguments-object包含值的静态副本,这些副本将传递给该函数。在正常模式下,arguments-object有一些“神奇”的行为:数组的元素和命名的函数参数都引用相同的值。
  • 在严格模式下,你会得到一个 SyntaxError 当。。。的时候 delete 运算符后跟一个非限定标识符(变量,函数或函数参数)。在正常模式下 delete 表达式将不执行任何操作并进行评估 false
  • 在严格模式下,你会得到一个 TypeError 当您尝试删除不可配置的属性时。 (在正常模式下,尝试只是失败而且 delete表达式被评估为 false)。
  • 在严格模式下,当您尝试为对象文字定义具有相同名称的多个属性时,会将其视为语法错误。 (在正常模式下没有错误。)
  • 在严格模式下,当函数声明具有多个具有相同名称的参数时,它被认为是语法错误。 (在正常模式下没有错误。)
  • 在严格模式下,不允许八进制文字(这些是以文字开头的文字 0x。 (在正常模式下,某些实现允许八进制文字。)
  • 在严格模式下标识符 eval 和 arguments 被视为关键字。您不能更改它们的值,不能为它们赋值,也不能将它们用作变量,函数,函数参数或catch块标识符的名称。
  • 在严格模式下,对检查调用堆栈的可能性有更多限制。 arguments.caller 和 arguments.callee 导致a TypeError 在严格模式下的函数。此外,严格模式下函数的一些调用者和参数属性会导致a TypeError 当你尝试阅读它们时。

81
2018-05-15 06:58



“在严格模式下,不允许八进制文字(这些是以0x开头的文字......)”八进制文字以一个引导开头 0。 - Alex Gittemeier


我的两分钱:

严格模式的目标之一是允许更快地调试问题。它可以帮助开发人员在发生某些可能导致网页无声和奇怪行为的错误事件时抛出异常。我们使用的那一刻 use strict,代码将抛出错误,这有助于开发人员提前修复它。

使用后我学到的很少重要的东西 use strict :

防止全局变量声明:

var tree1Data = { name: 'Banana Tree',age: 100,leafCount: 100000};

function Tree(typeOfTree) {
    var age;
    var leafCount;

    age = typeOfTree.age;
    leafCount = typeOfTree.leafCount;
    nameoftree = typeOfTree.name;
};

var tree1 = new Tree(tree1Data);
console.log(window);

现在,这段代码创建了 nameoftree 在全球范围内可以使用 window.nameoftree。当我们实施 use strict 代码会抛出错误。

未捕获的ReferenceError:未定义nameoftree

样品

省去了 with 声明:

with 使用像这样的工具不能缩小语句 丑化-JS。他们也是 弃用 并从以后的JavaScript版本中删除。

样品

防止重复:

当我们有重复属性时,它会抛出异常

未捕获的SyntaxError:对象文字中的重复数据属性不是   在严格模式下允许

"use strict";
var tree1Data = {
    name: 'Banana Tree',
    age: 100,
    leafCount: 100000,
    name:'Banana Tree'
};

还有更多,但我需要获得更多的知识。


73
2018-03-10 03:31





如果您使用过去一年左右发布的浏览器,那么它很可能支持JavaScript Strict模式。只有在ECMAScript 5成为当前标准之前的旧浏览器才支持它。

命令周围的引号确保代码仍然可以在旧版浏览器中工作(尽管在严格模式下生成语法错误的事情通常只会导致脚本在这些旧版浏览器中以某种难以检测的方式出现故障)。


54
2018-03-27 12:18



然后它做了什么? - Anish Gupta
......这个描述 部分 兼容性,但不是它实际做的。 - courtsimas


严格模式对常规JavaScript语义进行了一些更改:

  • 通过更改它们消除了一些JavaScript无声错误 抛出错误。

  • 修复了让JavaScript变得困难的错误 引擎进行优化。

  • 禁止将来可能定义的某些语法 ECMAScript的版本。

有关更多信息,请访问 严格的模式 - Javascript


48
2018-05-31 18:29