JavaScript严格模式约束规则
前言
当初刚学JavaScript的时候看的入门书曾经有一个概念就是可以在一定的条件下使用 "use strict"
进入严格模式,但并没有阐明严格模式和非严格模式的不同,最近在看到有人分享的前端面试题中有一道题目就是阐述一下严格模式的规则,特地找了一下资料,并做了一下总结。
严格模式可以在函数内部进行较为严格的全局或局部的错误条件检测,可以提早知道代码中存在的错误,即时捕获一些可能导致编程错误的行为。严格模式的约束规则主要包括以下几个部分:
- 变量
- 对象
- 函数
eval()
- eval和arguments
- 抑制this
- 其他
约束规则
变量
严格模式对于变量的约束主要总结为三个方面,一个是不能意外创建全局变量,一个是不能对变量调用 delete
操作符,还有就是对变量名有了限制。先说说不能意外创建全局变量,在非严格模式下,有人会这样写
instance1="hello"
这样写在非严格模式下会创建一个全局的 instance1
变量,但在严格模式下这样的写法就会抛出错误。接着是对 delete
操作符的约束,在非严格模式下是允许 delete
操作的,但会静默失败,而在严格模式下,删除变量会导致错误,抛出 ReferenceError
。最后一个约束就是对于变量名的限制,在严格模式下不能使用 implements
、interface
、let
、 package
、 private
、 protected
、 public
、 static
和 yield
作为变量名,这些都是保留字在ECMA6或以后的版本会用到它们。
对象
在严格模式下列情况下操作对象的属性会导致错误:
- 为只读属性赋值会抛出
TypeError
- 对不可配置的属性使用
delete
操作符会抛出TypeError
- 为不可扩展的对象添加属性会跑跑出
TypeError
另外一个限制是在使用对象字面量时属性名必须唯一,例如以下代码:
var person={
name: "Tony",
name: "Tom"
}
在非严格模式下 name
属性的值去后一个即 “Tom” 而在严格模式下,这样的代码会导致语法错误。
函数
严格模式对于函数的约束主要体现在,不能使用重名参数;命名参数的值和 arguments
的值相互独立;淘汰了 arguments.callee
和 arguments.caller
;不能使用保留字作为函数名;只能在脚本的顶级和函数内部声明函数。先来看一下对于重名参数的限制,以下代码
function display(num,num){
console.log(num)
}
在非严格模式下会在控制台上输出第二个num,而在严格模式下则会抛出语法错误。接着看一下命名参数值和 arguments
相互独立的情况,以下代码
function diaplay(value){
value="FOO";
console.log(value);
console.log(arguments[0]);
}
display("BAR");
在非严格模式下两个输出都是”BAR”,而在严格模式下第一个输出为”FOO”,第二个输出为”BAR”。然后看一下淘汰的 arguments.callee
和 arguments.caller
这两个属性一个引用函数本身,一个引用调用函数,以下代码
function factorial(num){
if(num<=1){
return 1;
}else{
return num* arguments.callee(num-1);
}
}
var result=factorial(5);
在非严格模式下能够正确算出阶乘的正确值,而在严格模式下则会抛出 TypeError
异常。访问 factorial.caller
也会抛出错误。下一个约束是,函数名不能使用保留字这是很容易理解的。接下来就是,只能在脚本的顶级和在函数内部声明函数,也就是说不能在 if
和 while
等控制语句中声明函数,例如以下代码
if(true){
function doSomething(){
...
}
}
在非严格模式下是能够运行的,而在严格模式下则会抛出语法错误。
eval()
在严格模式中, eval()
在包含上下文中不再创建变量或函数,以下代码
function doSomething(){
eval("var x=10");
console.log(x);
}
在非严格模式下,会在控制台输出10,而在严格模式下,x变量没有被创建,所以会抛出 ReferenceError
。但也可以在 eval()
中声明变量或函数,但这些变量或函数智能在被求值的特殊作用晕有效,随后就将被销毁。以下代码
"use strict"
var result=eval("var x=10,y=11;x+y");
console.log(result);
执行后会在控制台上输出21,因为 eval()
中声明了变量x和y,但最终返回的是x+y的值,返回的值赋予了result,所以能够输出21。
eval
和 arguments
在严格模式中明确禁止使用 eval
和 arguments
作为标识符名,也不允许读写它们的值。而在非严格模式中,可以重写 eval
也可以给 arguments
赋值。对于 eval
和 arguments
以下几种使用方式都会抛出语法错误:
- 使用
var
声明 - 赋予另外一个值
- 尝试修改包含的值或使用
++
- 用作函数名
- 用作命名的函数参数
- 在
try-catch
语句中用作例外名
抑制 this
在非严格模式下使用函数的 apply()
或 call()
方法时,null
或 undefined
值会被转换为全局对象。而在严格模式下,函数的 this
值时钟是指定的值,例如以下代码
var color ="red"
function display(){
console.log(this.color);
}
display(null);
在非严格模式下,意味着函数的 this
值是全局对象,在控制台输出的结果是red,而在严格模式中,这个函数的 this
值是 null
,因此会抛出错误.
其他变化
严格模式还有其他的约束,例如:
- 抛弃了
with
语句 - 去掉了八进制字面量
总结
通过这篇文章总结了一些关于严格模式的约束问题,其实严格模式的约束规则也可以作为参考来规范化自己的JS代码,毕竟严格模式的约束规则都是一些不良的代码风格。而且下一个版本的ES也是以严格模式为基础的,所以熟悉严格模式的规则能够让自己的代码少出错,也能够更平滑的过度到ES6。
参考资料《JavaScript高级程序设计》