附思维导图
严格模式的概念,是从ECMAScript5
引入的,通过严格模式,可以在函数内部选择进行较为严格的全局或局部的错误条件检测。
使用严格模式的好处是可以提早知道代码中存在的错误,及时捕获一些可能导致编程错误的 ECMAScript
行为。
支持严格模式的浏览器包括
IE10+
、Firefox 4+
、Safari 5.1+
和Chrome
。”
一、前言——如何使用严格模式
要选择进入严格模式,可以使用严格模式的编译指示(pragma):"use strict"
- 支持严格模式的引擎会启动这种模式,
- 而不支持该模式的引擎就当遇到了一个未赋值的字符串字面量,会忽略这个编译指示。
1、如果是在全局作用域中(函数外部)给出"use strict"
,则整个代码都将使用严格模式。(如果把带有"use strict"
的代码放到其他文件的全局中,则该文件中的 JavaScript
代码也将处于严格模式下。)
2、也可以只在函数中打开严格模式,就像下面这样:
function xiaozhima(){
"use strict";
//其他代码
}
复制代码
如果不想让整篇代码都处在严格模式下,建议只在需要测试的特定函数中开启严格模式。
二、严格模式 VS 非严格模式——变量
1、创建变量
在严格模式下,什么时候创建变量以及怎么创建变量都是有限制的。
”
- 在非严格模式下,可以像下面这样创建全局变量:
//未声明变量
a = 1;
//非严格模式:创建全局变量
//严格模式:抛出 ReferenceError message = "Hello world! ";
复制代码
即使 a
前面没有 var
等关键字,即使没有将它定义为某个全局对象的属性,也能将 a
创建为全局变量。
- 严格模式下,不允许意外创建全局变量。
"use strict"
//未声明变量
a = 1;
//严格模式:抛出 ReferenceError message = "Hello world! ";
复制代码
但在严格模式下,如果给一个没有声明的变量赋值,那代码在执行时就会抛出ReferenceError
。
2、delete
删除变量
- 非严格模式允许这样操作,但会失败(返回 false)。
var color = "red";
delete color;
//删除变量
//非严格模式:静默失败
//返回 false
复制代码
- 在严格模式下,删除变量也会导致错误。
"use strict"
var color = "red";
delete color;
//删除变量
//严格模式:抛出 ReferenceError
复制代码
3、变量名
严格模式下对变量名也有限制。
特别地,不能使用 implements
、interface
、let
、package
、private
、protected
、public
、static
和 yield
等作为变量名。
这些都是保留字,将来的 ECMAScript
版本中可能会用到它们。在严格模式下,用以上标识符作为变量名会导致语法错误。
三、严格模式 VS 非严格模式——对象
在严格模式下操作对象比在非严格模式下更容易导致错误。一般来说,非严格模式下会静默失败的情形,在严格模式下就会抛出错误。因此,在开发中使用严格模式会加大早发现错误的可能性。
”
1、在下列情形下操作对象的属性会导致错误:
- 为只读属性赋值会抛出
TypeError
; - 对不可配置的(nonconfigurable)的属性使用
delete
操作符会抛出TypeError
; - 为不可扩展的(nonextensible)的对象添加属性会抛出
TypeError
。
2、在使用对象字面量时,属性名必须唯一。例如:
//重名属性
//非严格模式:没有错误,以第二个属性为准
//严格模式:抛出语法错误
var person = {
name: "Nicholas",
name: "Greg"
};
复制代码
这里的对象 person
有两个属性,都叫 name
。
- 非严格模式下:
person
对象的name
属性值是第二个; - 严格模式下:而在严格模式下,这样的代码会导致语法错误。
四、严格模式 VS 非严格模式——函数
1、命名函数的参数必须唯一
以下面这个函数为例:
//重名参数
//非严格模式:没有错误,只能访问第二个参数
//严格模式:抛出语法错误
function sum (num, num){
//do something
}
复制代码
- 在非严格模式:这个函数声明不会抛出错误。 通过参数名只能访问第二个参数,要访问第一个参数必须通过
arguments
对象。 - 严格模式:要求命名函数的参数必须唯一。会抛出错误
2、函数体中的arguments
严格模式下,arguments
对象的行为也有所不同。
- 非严格模式下,修改命名参数的值也会反映到
arguments
对象中,例如:
//修改命名参数的值
//非严格模式:修改会反映到 arguments 中
function showValue(value){
value = "Foo";
alert(value); //"Foo"
alert(arguments[0]); //非严格模式:"Foo"
}
showValue("Hi");
复制代码
- 严格模式下这两个值是完全独立的。
//修改命名参数的值
//严格模式:修改不会反映到 arguments 中
function showValue(value){
"use strict"
value = "Foo";
alert(value); //"Foo"
alert(arguments[0]); //严格模式:"Hi"
}
showValue("Hi");
复制代码
以上代码中,函数
showValue()
只有一个命名参数value
。调用这个函数时传入了一个参数"Hi"
, 这个值赋给了value
。而在函数内部,value
被改为"Foo"
。”
- 在非严格模式下,这个修改也会改变
arguments[0]
的值, - 但在严格模式下,
arguments[0]
的值仍然是传入的值。
与变量类似,严格模式对函数名也做出了限制,不允许用 implements
、interface
、let
、package
、private
、protected
、public
、static
和 yield
等作为函数名。
3、if
语句中声明函数会导致语法错误
对函数的最后一点限制,就是只能在代码的顶级和在函数内部声明函数。也就是说,在 if
语句中声明函数会导致语法错误:
//在 if 语句中声明函数
//非严格模式:将函数提升到 if 语句外部
//严格模式:抛出语法错误
if (true){
function doSomething(){
//...
}
}
复制代码
- 在非严格模式下,以上代码能在所有浏览器中运行,
- 但在严格模式下会导致语法错误。
五、严格模式 VS 非严格模式—— eval()
饱受诟病的 eval()
函数在严格模式下也得到了提升。最大的变化就是它在包含上下文中不再创建变量或函数。
例如:
//使用 eval()创建变量
//非严格模式:弹出对话框显示 10
//严格模式:调用 alert(x)时会抛出 ReferenceError
function doSomething(){
eval("var x=10");
alert(x);
}
复制代码
- 非严格模式下,以上代码会在函数
doSomething()
中创建一个局部变量x
,然后alert()
还会显示该变量的值。 - 在严格模式下,在
doSomething()
函数中调用eval()
不会创建变量x
,因此调用alert()
会导致抛出ReferenceError
,因为x
没有定义。
可以在 eval()
中声明变量和函数,但这些变量或函数只能在被求值的特殊作用域中有效,随后就将被销毁。因此,以下代码可以运行,没有问题:
"use strict";
var result = eval("var x=10, y=11; x+y");
alert(result); //=> 21
复制代码
这里在 eval()
中声明了变量 x
和 y
,然后将它们加在一起,返回了它们的和。于是,result
变量的值是 21
,即 x
和 y
相加的结果。而在调用 alert()
时,尽管 x
和 y
已经不存在了,result
变量的值仍然是有效的。
六、严格模式 VS 非严格模式—— eval 与 arguments
- 严格模式已经明确禁止使用
eval
和arguments
作为标识符,也不允许读写它们的值。例如:
//把 eval 和 arguments 作为变量引用
//非严格模式:没问题,不出错
//严格模式:抛出语法错误
var eval = 10;
var arguments = "Hello world!";
复制代码
- 在非严格模式下,可以重写
eval
,也可以给arguments
赋值。但在严格模式下,这样做会导致语法错误。
不能将它们用作标识符,意味着以下几种使用方式都会抛出语法错误:
- 使用 var 声明;
- 赋予另一个值;
- 尝试修改包含的值,如使用++;
- 用作函数名;
- 用作命名的函数参数;
- 在
try-catch
语句中用作例外名。
七、严格模式 VS 非严格模式—— this
JavaScript
中一个最大的安全问题,也是最容易让人迷茫的地方,就是在某些情况下如何抑制 this
的值。
- 在非严格模式下使用函数的
apply()
或call()
方法时,null
或undefined
值会被转换为全局对象。 - 在严格模式下,函数的
this
值始终是指定的值,无论指定的是什么值。例如:
//访问属性
//非严格模式:访问全局属性
//严格模式:抛出错误,因为 this 的值为 null
var color = "red";
function displayColor(){
alert(this.color);
}
displayColor.call(null);
复制代码
以上代码向displayColor.call()
中传入了null
,
如果在是非严格模式下,这意味着函数的this
值是全局对象。结果就是弹出对话框显示"red"
。
而在严格模式下,这个函数的 this
的值是 null
,因此在访问 null
的属性时就会抛出错误。
八、严格模式 VS 非严格模式—— 其他
1、抛弃了 with
语句。
- 非严格模式下的
with
语句能够改变解析标识符的路径, - 但在严格模式下,
with
被简化掉了。因此,在严格模式下使用with
会导致语法错误。
//with 的语句用法
//非严格模式:允许
//严格模式:抛出语法错误
with(location){
alert(href);
}
复制代码
2、去掉了 JavaScript
中的八进制字面量
严格模式也去掉了
JavaScript
中的八进制字面量。以0
开头的八进制字面量过去经常会导致很多错误。在严格模式下,八进制字面量已经成为无效的语法了。”
//使用八进制字面量
//非严格模式:值为 8
//严格模式:抛出语法错误
var value = 010;
复制代码
注意⚠️:使用parseInt()
解析八进制字面量在严格模式下会被当作以 0
开头的十进制字面量。例如:
//使用 parseInt()解析八进制字面量
//非严格模式:值为 8
//严格模式:值为 10
var value = parseInt("010");
复制代码
文章借鉴于:javascript高级程序设计第三版
思维导图
本文使用 mdnice 排版