1.什么是严格模式?
js运行有两种模式:一种是普通模式;一种是严格模式。
严格模式是ES5添加的,是比普通模式多一部分的js规则。如果在ES5之前js解析引擎,会忽略严格模式。
js一般默认是普通模式,ES6的模块和Class类默认是严格模式。
2. 严格模式的使用场景
严格模式的触发是使用: "use strict"
有两种使用场合:一种是脚本范围;一种是函数范围
1.脚本范围
1.在html文件中,可以在<script> 标签内的顶部直接使用"use strict";
"use strict"上面不能有可执行代码,否则失效;但是上面可以是注释内容或者空行。
❗️一个脚本内抛出异常,后面的代码不再执行;但是其他的脚本可以。如下:
<script> console.log(1); "use strict"; //上面有代码,自动失效 a=6; </script> <script> /* 这是个脚本注释,并且上面空了一行*/ "use strict"; // 严格模式;下面是声明时报错 b=6; // Uncaught ReferenceError: b is not defined </script> <script> "use strict"; // 严格模式 c=6; // Uncaught ReferenceError: c is not defined </script>
2.在一个脚本文件中,在顶部声明"use strict";顶部有注释或者空行(空;行不可以)也可以。
//--- es5.js
// 顶部的注释;并且有一个空行,整个文件都是严格模式 "use strict"; function test(a,a) { // Uncaught SyntaxError: Duplicate parameter name not allowed in this context // 严格模式不允许参数重复;声明时报错 }
上面的写法有隐患,如果项目内部需要脚本合并,如严格模式A.js和普通模式B.js,如果A在前,那么
B也会被解释成严格模式;如果B在前,那么A的严格模式会失效。
所以,如果是单独的文件,可以使用立即执行函数包裹以下,这样可以避免脚本合并的BUG。
// 这个是A.js的代码;代码效果和上面的相同,但是可以保证代码的独立 (function() { "use strict"; // 函数内部严格模式 function test(a,a) { // Uncaught SyntaxError: Duplicate parameter name not allowed in this context } })();
2.函数范围
在一个函数内顶部使用"use strict";那么在一个函数内是严格模式。
function test() { // 函数的注释 "use strict"; t = 7; } // 声明时不报错;执行时报错 test(); // Uncaught ReferenceError: t is not defined
3. 浏览器控制台范围
开发者最方便的调试工具是console控制台;默认是普通模式,可以手动设置严格模式;
3. 严格模式的内容
1. 显式报错
将普通模式中默默失败的错误,改为显式报错。
- 1. 只读属性赋值报错;删除不可配置属性报错
原先只读属性赋值或者删除不可配置属性,默默失败,不会抛出异常;严格模式下,会抛出异常。
"use strict"; class A { } class B{} // 类的prototype属性的writable,configurable,enumerable都是false A.prototype = new B(); // Uncaught TypeError: Cannot assign to read only property 'prototype' of function 'class A {}' delete A.prototype; // Uncaught TypeError: Cannot delete property 'prototype' of class A {}'
- 2.只设置了取值器的对象不可写
"use strict"; var a = { get prop() { return 1; } } a.prop = 5; //Uncaught TypeError: Cannot set property prop of #<Object> which has only a getter
- 3.禁止扩展的对象不可扩展(不能添加新属性)
"use strict"; var a = {}; Object.preventExtensions(a); a.x = 0; //Uncaught TypeError: Cannot add property x, object is not extensible
- 4.eval,arguments不可用作标识名
javascript中的保留字在严格模式下都会报错;实际开发中注意变量名不要是保留关键字。
非严格模式下,不会报错。
"use strict"; var eval = 5; //Uncaught SyntaxError: Unexpected eval or arguments in strict mode function test(arguments) { //Uncaught SyntaxError: Unexpected eval or arguments in strict mode }
- 5.函数参数名不能重复
- 6. 禁止使用0前缀表示八进制数。
ES6中也有规定,八进制数应该使用“0o”表示。
"use strict"; var a = 0o10; console.log(a); // 8 var b = 010; // Uncaught SyntaxError: Octal literals are not allowed in strict mode.
2. 加强安全
从语法书写上避免错误的产生。
- 1. 严格模式下,不允许this指向window
js引擎将其指向undefined。这个很好的解释了React类组件中方法必须绑定this,
否则默认this是undefined。
这时fn.call()/fn.call(null)/fn.call(undefined)不再默认绑定window。绑定的就是括号中的内容。
- 2. 不允许未声明的变量出现
即变量必须使用var, let等声明,否则报错。原来未声明的变量会默认成为全局变量。
"use strict"; a = 5; // Uncaught ReferenceError
- 3.禁止使用fn.caller/fn.arguments
首先fn.caller不是标准语法;生产环境禁止使用;fn.arguments已被废弃
但是某些情况下也会使用。
fn.caller是返回fn的调用栈,即触发该函数的函数;
如果在全局环境下调用,fn.caller()是null。
// 这是非严格模式;只是为了解释caller的概念;严格模式下报错 function test() { a(); console.log(test.caller);//null } function a() { console.log(a.caller); // function test(){a();} } test();
fn.arguments其实就是参数对象。可以在函数中直接使用arguments对象。
- 4.禁止使用arguments.callee/arguments.caller
这两个属性已经废弃。普通模式下使用,代码无效,不报错;严格模式下报错。
原来arguments.callee表示当前函数;arguments.caller和fn.caller一样。
- 5.不可删除声明的普通变量
普通模式下可以删除,并且可以删除成功。
"use strict"; let a = 6; delete a; //Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
- 6.严格模式下原始类型的值不能赋属性
普通模式下不报错,会自动将原值值转为包装对象。
"use strict"; (1).prop = 9; // Uncaught TypeError: Cannot create property 'prop' on number '1'
3. 禁止出现动态作用域
普通模式下,eval()和with()会在执行时动态生成作用域。
- 1. 禁止使用with语句
在严格模式下,使用with语句会报错。其实普通模式下,也不要使用with语句。
"use strict"; var obj ={}; with(obj) { //Uncaught SyntaxError: Strict mode code may not include a with statement a = 5; }
- 2.创建eval作用域
严格模式下,eval()会创建一个eval函数内部的作用域。
普通模式下, eval内部代码所在的作用域是函数所在的作用域。
// 普通模式下 function test() { var x = 5; eval("var x = 6"); //相当于直接var x= 6; console.log(x); // 6 } test(); // 严格模式下 "use strict"; // 1.第一种声明位置 function test() { // "use strict"; // 2.也可以在这里声明 var x = 5; eval("var x = 6"); // 只在eval内部有效 // 3. 还可以如下声明 // eval('"use strict"; var x= 6'); console.log(x); // 5 } test();
- 3.arguments对象不再随参数改变而改变
// 普通模式 function test(a) { a = 2; return [a, arguments[0]]; } console.log(test(1)); // [2, 2] // 严格模式 "use strict"; function test(a) { a = 2; return [a, arguments[0]]; } console.log(test(1)); // [2, 1]