ES5最早引入了严格模式的概念。通过严格模式,可以在函数内部选择进行较为严格的全局或局部的错误条件检测。可以提早知道代码中存在的错误,及时捕获一些可能呆滞编程错误的ECMAScript行为
1.使用
在需要使用严格模式的作用域顶部加上如下代码:
"use strict"
此时该作用域(或文件)中的JS代码都将处于严格模式下。
如果没有控制页面中所有脚本的权力,建议只在需要测试的特定函数中开启严格模式
2.严格模式下的限制
(1)变量
- 不允许意外创建全局变量
- 如在非严格模式下,可以像下面这样创建全局变量:
-
msg = "hello"
-
- 严格模式下:
-
"use strict" msg = "hello" // Uncaught ReferenceError: msg is not defined
-
- 如在非严格模式下,可以像下面这样创建全局变量:
- 另外:严格模式下对变量名也有限制。特别地,不能使用 implements、interface、let、package、private、protected、public、static 和 yield 作为变量名。这些都是保留字,将来的 ECMAScript版本中可能会用到它们。在严格模式下,用以上标识符作为变量名会导致语法错误。
(2)对象
- 严格模式下操作对象比在非严格模式下更容易导致错误,一般来说,非严格模式下会静默失败的情况,严格模式下就会抛出错误,如:
- 为只读属性赋值会抛出TypeError(writeable = true)
- 非严格模式下默认失败:
-
1 let obj = { name: "张三" } 2 Object.defineProperty(obj, "name", { 3 writable: false 4 }) 5 6 obj.name = "李四" 7 8 console.log(obj.name); // 张三
-
- 严格模式下会抛出错误:
-
1 "use strict" 2 let obj = { name: "张三" } 3 Object.defineProperty(obj, "name", { 4 writable: false 5 }) 6 7 obj.name = "李四" 8 9 console.log(obj.name); // Uncaught TypeError: Cannot assign to read only property 'name' of object '#<Object>'
-
- 非严格模式下默认失败:
- 对不可配置的属性使用delete操作符会抛出TypeError(configurable = false)
- 非严格模式:
-
1 let obj = { name: "张三" } 2 Object.defineProperty(obj, "name", { 3 configurable: false 4 }) 5 6 delete obj.name 7 8 console.log(obj); // {name: "张三"}
-
- 严格模式:
-
1 "use strict" 2 let obj = { name: "张三" } 3 Object.defineProperty(obj, "name", { 4 configurable: false 5 }) 6 7 delete obj.name // Uncaught TypeError: Cannot delete property 'name' of #<Object> 8 9 console.log(obj);
-
- 非严格模式:
- 对不可扩展的对象添加属性会抛出TypeError(Object.preventExtensions()、Object.seal()、Object.freeze())
- 以上保护对象的三个方法从左到右,保护级别依次提升。具体区别见此
- 非严格模式:
-
1 let obj = { name: "张三" } 2 3 Object.preventExtensions(obj) 4 obj.age = 12 5 6 console.log(obj); // {name: "张三"}
-
- 严格模式:
-
1 "use strict" 2 let obj = { name: "张三" } 3 4 Object.preventExtensions(obj) 5 obj.age = 12 // Uncaught TypeError: Cannot add property age, object is not extensible 6 7 console.log(obj);
-
- 为只读属性赋值会抛出TypeError(writeable = true)
(3)函数
- 严格模式要求命名函数的参数必须唯一:
- 非严格模式:没有错误,只能访问第二个参数
-
1 function sum (num,num){ 2 console.log(num); 3 } 4 5 sum(1,2) // 2
-
- 严格模式:
-
1 "use strict" 2 function sum (num,num){ // Uncaught SyntaxError: Duplicate parameter name not allowed in this context 3 console.log(num); 4 } 5 6 sum(1,2)
-
- 非严格模式:没有错误,只能访问第二个参数
- 严格模式下,禁用了argument.callee和argument.caller
- 非严格模式:
-
1 function factorial(num){ 2 if(num <=1){ 3 return 1 4 }else{ 5 return num + arguments.callee(num-1) 6 } 7 } 8 9 console.log(factorial(100)); // 5050
-
- 严格模式:
-
1 function factorial(num){ 2 if(num <=1){ 3 return 1 4 }else{ 5 return num + arguments.callee(num-1) 6 } 7 } // Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them 8 9 console.log(factorial(100));
-
- 非严格模式:
- 还有一个限制:就是只能在脚本的顶级和在函数的内部声明函数。也就是说,在if语句中声明函数会导致语法错误
(4)eval
- eval在包含上下文中不再创建变量或者函数
- 非严格模式下,fn()中的eval代码执行后会在函数fn的作用域中创建一个局部变量x
-
1 function fn(){ 2 eval("var x = 1") 3 alert(x) 4 } 5 fn() // 弹框并出现1
-
- 严格模式下:
-
1 "use strict" 2 function fn(){ 3 eval("var x = 1") 4 alert(x) 5 } // Uncaught ReferenceError: x is not defined 6 fn()
-
- 非严格模式下,fn()中的eval代码执行后会在函数fn的作用域中创建一个局部变量x
(5)eval和arguments
- 禁止把eval和arguments作为变量引用
- 禁止重写eval和arguments:
- 使用var声明
- 赋予另外一个值
- 尝试修改包含的值
- 作为函数名
- 用作命名的函数参数
- 在try-catch语句中用作例外名
(6)this
严格模式下的函数中的this将指向undefined(在非严格模式下指向window)