为了使Javascript
代码更加严谨,在EMCAScript 5
添加了一种新的模式 -strict mode
,也就是常说的严格模式。严格模式是与正常模式比较而言的。
开启 Strict 模式
开启strict
模式用一句话就可以实现:
"use strict";
但面临的问题是这个strict
模式起作用的范围有多大。当我们在一个脚本的第一行加上这个语句,那么这个脚本都会处于strict
模式下。
<script>"use strict";...
但是这会面临一个问题,如果拼合严格模式和正常模式的脚本可能导致整个代码混论不堪,与严格模式的初衷相悖,所以对整个脚本实行严格模式时需要相当谨慎,部署严格模式的脚本到整个项目中要考虑拼接的结果。
还有一种比较安全的方法就是函数中使用strict
模式,当然也要在函数体内的第一行。
function() {"use strict";...}
此时严格模式只在函数体内生效,这会比脚本生效更加安全。
Strict 模式的具体表现
1.全局变量
在strict
模式下,不可以给一个未声明的全局变量赋值:
<script>"use strict";a = 1;</script>
此时会抛出错误:
Uncaught ReferenceError: a is not defined
2.不可写变量
今天在博文-《细说 Javascript 拾遗篇(二) : undefined 和 null》已经确定了在EMCAScript
全局变量undefined
属性是不可重写,虽然不可重写,但在正常模式下赋值并不会报错,但是在strict
模式如果对不可写变量赋值将会报错:
<script>"use strict";undefined = 123;</script>
此时会抛出错误:
Uncaught TypeError: Cannot assign to read only property 'undefined' of [object Object]
3.删除机制
在正常模式下删除不可删除的变量或属性时并不会报错(对于删除变量会返回false
),然而在strict
模式下删除不可删除的变量货属性时则是不可行的,因为为报错。
<script>"use strict";var a = 1;delete a;</script>
此时会抛出错误:
Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
4.命名的唯一性
对于strict
模式下,函数的参数和对象内的变量都不能有重命名现象。
而在正常模式下是允许的。
<script>"use strict";function foo(a, a) {return a*a;}</script>
此时会抛出错误:
Uncaught SyntaxError: Strict mode function may not have duplicate parameter names
5.八进制的支持
strict
模式不支持数字的八进制表示,我们知道在正常模式下,第一位为的数字将会认为是八进制,但是在strict
模式不允许。
<script>"use strict";var a = 01;</script>
此时会抛出错误:
Uncaught SyntaxError: Octal literals are not allowed in strict mode.
6.with 语句
Javascript
的strict
模式很重要的一个改变就是变量在编译阶段就已经确定,这与正常模式下允许运行时确定变量有很大的不同。这对Javascript
代码的优化作用很大。
因此with
语句在strict
模式下是不被支持的,因为我们都知道with
语句只有在运行时才能确定变量。
<script>"use strict";var obj = {a:1};with(obj) {var b = a;}</script>
此时会抛出错误:
Uncaught SyntaxError: Strict mode code may not include a with statement
7.eval 函数作用域
正常模式下,eval
函数在哪个作用域下执行就属于哪个作用域,例如在全局作用域下执行则属于全局作用域,但在strict
模式下,eval
函数拥有自己的作用域。
<script>"use strict";var a = 1;eval('var a = 2');console.log(a);</script>
正常模式下输出为: 2。
strict
模式下输出为 1。
此外,strict
模式下,不可以对eval
赋值。
<script>"use strict";eval = 1;</script>
此时会抛出错误:
Uncaught SyntaxError: Unexpected eval or arguments in strict mode
8.arguments 对象
在strict
模式下对函数的额arguments
对象做了很大的限制。
首先,arguments
跟eval
一样,不可被赋值。
<script>"use strict";arguments = 1;</script>
此时会抛出错误:
Uncaught SyntaxError: Unexpected eval or arguments in strict mode
其次,不再动态追踪函数的参数。
<script>"use strict";function foo(a) {a = 2;return arguments[0];}console.log(foo(1));</script>
正常模式下输出为: 2。
strict
模式下输出为 1。
最后,strict
模式不再支持arguments.callee
的使用。
9.函数体内的 this
在正常模式下,我们都知道函数体内的this
将指向全局对象,然而在strict
模式下,this
不仅不会指向全局对象,而且在函数定义体内直接使用还会报错,只有在使用new
创建新对象实例时才可以使用this
,而且指向的是新的对象实例,并非全局对象。
<script>"use strict";var a = 1;function foo() {console.log(this.a);}foo();</script>
此时会抛出错误:
Uncaught TypeError: Cannot read property 'a' of undefined
10.函数体内访问调用栈
在strict
模式下,函数体内不再运行访问调用栈,所以下例会报错:
<script>"use strict";function foo() {foo.callee;foo.caller;foo.arguments;}foo();</script>
此时会抛出错误:
Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
11.函数声明的位置
在正常模式下,函数声明可以在任何位置,然后再strict
模式下,必须在全局作用域或函数作用域的顶端声明函数。
<script>"use strict";var a = 1;if(a === 1) {function foo() {}}</script>
此时会抛出错误:
Uncaught SyntaxError: In strict mode code, functions can only be declared at top level or immediately within another function
总结
阅读完MDN
对strict
模式的阐述,不仅能看出strict
模式是对Javascript
代码规范性所起到的作用,同时也能看出这也为了新规范新版本的Javascript
功能做好了铺垫,例如最后一个在函数声明位置上的表现,能够看出浓浓的块级作用域的想法。所以建议大家在书写Javascript
代码时尽量以strict
模式规范自己的代码。
参考
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/Strict_mode