除了正常的运行模式,JavaScript 还有第二种运行模式:严格模式(strict mode)。顾名思义,这种模式采用更加严格的 JavaScript 语法。
同样的代码,在正常模式和严格模式中,可能会有不一样的运行结果。一些在正常模式下可以运行的语句,在严格模式下将不能运行。
严格模式:规避了js里不严谨不规范的地方,增强了代码的安全性,提高了编译器的编译效率,为后续版本做铺垫。
早期的 JavaScript 语言有很多设计不合理的地方,但是为了兼容以前的代码,又不能改变老的语法,只能不断添加新的语法,引导程序员使用新语法。
严格模式是从 ES5 进入标准的,主要目的有以下几个。
一 . 明确禁止一些不合理、不严谨的语法,减少 JavaScript 语言的一些怪异行为。
二 . 增加更多报错的场合,消除代码运行的一些不安全之处,保证代码运行的安全。
三 . 提高编译器效率,增加运行速度。
四 . 为未来新版本的 JavaScript 语法做好铺垫。
总之,严格模式体现了 JavaScript 更合理、更安全、更严谨的发展方向
进入严格模式的标志,是一行字符串use strict。
‘use strict’; strict 严格的
老版本的引擎会把它当作一行普通字符串,加以忽略。新版本的引擎就会进入严格模式。
严格模式可以用于整个脚本,也可以只用于单个函数
整个脚本文件:
use strict放在脚本文件的第一行,整个脚本都将以严格模式运行。如果这行语句不在第一行就无效,整个脚本会以正常模式运行。
(严格地说,只要前面不是产生实际运行结果的语句,use strict可以不在第一行,比如直接跟在一个空的分号后面,或者跟在注释后面。)
<script>
'use strict';
console.log('这是严格模式');
</script>
<script>
console.log('这是正常模式');
</script>
上面代码中,一个网页文件依次有两段 JavaScript 代码。前一个
<script>
console.log('这是正常模式');
'use strict';
</script>
单个函数:
use strict放在函数体的第一行,则整个函数以严格模式运行。
function strict() {
'use strict';
return '这是严格模式';
}
function notStrict() {
return '这是正常模式';
}
变量声明(必须要使用var)
函数不能有重名的参数
正常模式下,如果函数有多个重名的参数,可以用arguments[i]读取。严格模式下,这属于语法错误。
function f(a, a, b) {
'use strict';
return a + b;
}
禁止八进制的前缀0表示法
正常模式下,整数的第一位如果是0,表示这是八进制数,比如0100等于十进制的64。严格模式禁止这种表示法,整数第一位为0,将报错。
'use strict';
var n = 0100;
禁止 this 关键字指向全局对象
正常模式下,函数内部的this可能会指向全局对象(window),严格模式禁止这种用法,避免无意间创造全局变量。
function f() {// 正常模式
console.log(this === window);
}
f() // true
function f() {// 严格模式
'use strict';
console.log(this === undefined);
}
f() // true
上面代码中,严格模式的函数体内部this是undefined。这种限制对于构造函数尤其有用。使用构造函数时,有时忘了加new,这时this不再指向全局对象,而是报错。
function f() {
'use strict';
this.a = 1;
};f();// 报错,this 未定义
严格模式下,使用with语句将报错。
'use strict';
var obj = {v:1};
with (obj) { // SyntaxError: Strict mode code may not include a with statement
v = 2;//obj.v = 2;
}
相当于
obj.v
创设 eval 作用域
正常模式下,JavaScript 语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。
正常模式下,eval语句的作用域,取决于它处于全局作用域,还是函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够在其所运行的作用域创设新的变量了,也就是说,eval所生成的变量只能用于eval内部。
(function () {
'use strict';
var x = 2;
console.log(eval('var x = 5; x')) // 5
console.log(x) // 2
})()
上面代码中,由于eval语句内部是一个独立作用域,所以内部的变量x不会泄露到外部
删除变量
通过关键字delete删除
delete关键字通常同来删除对象的属性值和属性名
也可以用来删除普通模式下未声明的变量 有var let const声明的变量在普通模式下无法删除
用delete删除显示申明的标识符、名称和具名函数。
严格模式下
只有configurable设置为true的对象属性,才能被删除。
"use strict";
var x;
delete x; // 语法错误
var obj = Object.create(null, {'x': {
value: 1,
configurable: true
}});
delete oobj.x; // 删除成功
arguments
arguments在严格模式下有着很有意思的一面
普通模式下
function f(x){
console.log(arguments[0]);
x=20;
console.log(arguments[0])
}
f(10) // 10 20
严格模式下
有名参数是arguments参数的静态副本,而非引用。
<script>
'use strict';
function fun() {
console.log(arguments[0]);
arguments[0] = 20
console.log(arguments[0]);
}
fun(10) // 10 20
function f(x) {
console.log(arguments[0]);
arguments[0] = 20;
console.log(x);
x = 30
console.log(arguments[0])
console.log(x);
}
f(10) // 10 20 30
</script>
在无论有名或无名参数的情况下我们修改arguments[0]都可以修改
而在有名参数的情况下我们修改arguments[0]发现和命名参数没有任何的冲突
命名参数就是我们修改的命名参数的值
arguments[0]则是我们修改的另一个值
函数形参声明名不能重复
普通模式下
形参声明相同会导致函数内部打印参数选择第二个形参的值
<script>
function fun(a, a) {
console.log(a);
}
fun(10, 20) // 20
</script>
严格模式直接报错
<script>
'use strict';
function fun(a, a) {
console.log(a);
}
fun(10, 20) // Uncaught SyntaxError: Duplicate parameter name not allowed in this context
</script>