严格模式
严格模式
- ECMAScript 5的严格模式是采用具有限制性JavaScript变体的一种方式,从而使代码隐式地脱离“马虎模式/稀松模式/懒散模式“(sloppy)模式。
目的
- 消除JS语法中一些不合理、不严谨之处。
- 修复了一些导致 JavaScript引擎难以执行优化的缺陷:有时候,相同的代码,严格模式可以比非严格模式下运行得更快。
- 严格模式禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来的版本做铺垫。
调用
1、脚本
- 为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句 "use strict"; (或 'use strict';)
// 整个脚本都开启严格模式的语法
"use strict";
var v = "Hi! I'm a strict mode script!";
注: 盲目的合并严格和非严格模式的脚本可能会出现巨大的问题,建议按照一个个函数去开启严格模式,或者将整个脚本文件放在一个立即执行的匿名函数之中。
(function (){
"use strict";
// some code here
})();
2、函数
- 要给某个函数开启严格模式,得把 "use strict"; (或 'use strict'; )声明一字不漏地放在函数体所有语句之前。
function strict() {
// 函数级别严格模式语法
'use strict';
function nested() {
return "And so am I!";
}
return "Hi! I'm a strict mode function! " + nested();
}
function notStrict() {
return "I'm not strict.";
}
语法和行为改变
1. 全局变量显式声明
- 正常模式下,如果一个变量没有声明就赋值,则默认为全局变量。但严格模式禁止该做法,必须显式声明。
"use strict";
v = 1; // 报错,v未声明
for(i = 0; i < 2; i++) { // 报错,i未声明
}
2. 静态绑定
- Javascript语言的一个特点,就是允许"动态绑定",即某些属性和方法到底属于哪一个对象,不是在编译时确定的,而是在运行时(runtime)确定的。
- 严格模式对动态绑定做了一些限制。某些情况下,只允许静态绑定。也就是说,属性和方法到底归属哪个对象,在编译阶段就确定。这样做有利于编译效率的提高,也使得代码更容易阅读,更少出现意外
2.1 禁止使用with语句
"use strict";
var v = 1;
with (o){ // 语法错误
v = 2;
}
2.2 创设eval作用域
- 正常模式下,Javascript语言有两种变量作用域(scope):全局作用域和函数作用域。严格模式创设了第三种作用域:eval作用域。
- 正常模式下,eval语句的作用域,取决于它处于全局作用域,还是处于函数作用域。严格模式下,eval语句本身就是一个作用域,不再能够生成全局变量了,它所生成的变量只能用于eval内部。
"use strict";
var x = 2;
console.info(eval("var x = 5; x")); // 5
console.info(x); // 2
3. 增强安全措施
3.1 禁止this关键字指向全局对象
function f(){
return !this;
}// 返回false,因为"this"指向全局对象,"!this"就false
function f(){
"use strict";
return !this;
}// 返回true,因为严格模式下,this的值为undefine,所以"!this"为true。
- 在使用构造函数时,如果没有加new,this不再指向全局对象,而是报错
function f(){
"use strict";
this.a = 1;
};
f();// 报错,this未定义
3.2 禁止函数内部遍历调用栈
function f1(){
"use strict";
f1.caller; // 报错
f1.arguments; // 报错
}
f1();
4. 禁止删除变量
- 严格模式下无法删除变量。只有configurable设置为true的对象属性,才能被删除。
"use strict";
var x;
delete x; // 语法错误
var o = Object.create(null, {'x': {
value: 1,
configurable: true
}});
delete o.x; // 删除成功
5. 显示报错
- 正常模式下,对一个对象的只读属性进行赋值,不会报错,只会默默地失败。严格模式下,将报错。
"use strict";
var o = {};
Object.defineProperty(o, "v", { value: 1,writable: false });
o.v = 2; // 报错
- 严格模式下,对一个使用getter方法读取的属性进行赋值,会报错。
"use strict";
var o = {
get v() { return 1; }
};
o.v = 2; // 报错
- 严格模式下,对禁止扩展的对象添加新属性,会报错。
"use strict";
var o = {};
Object.preventExtensions(o);
o.v = 1; // 报错
- 严格模式下,删除一个不可删除的属性,会报错。
"use strict";
delete Object.prototype; // 报错
6. 重名错误
6.1 对象不能有重名的属性
- 正常情况下重名,后一个的值会覆盖前一个的值。但严格模式不允许。
"use strict";
var o = {
p: 1,
p: 2
}; //语法错误
6.1 函数不能有重名的参数
- 正常模式下,如果函数有多个重名参数,可以用arguments[i]读取。严格模式下,这属于语法错误。
"use strict"
function fun(a,a,b){ //语法错误
}
7. 禁止八进制
- ECMAScript并不包含八进制语法, 但所有的浏览器都支持这种以零(0)开头的八进制语法: 0644 === 420 还有 "\045" === "%".在ECMAScript 6中支持为一个数字加"0o"的前缀来表示八进制数.
- 严格模式不支持八进制
var a = 0o10 // ES6支持八进制
"use strict"
var sum = 015 + // 语法错误
100;
8. arguments对象的限制
- arguments是函数的参数对象,严格模式对其进行了限制。
8.1 不允许对arguments对象赋值
"use strict";
arguments++; // 语法错误
var obj = { set p(arguments) { } }; // 语法错误
try { } catch (arguments) { } // 语法错误
function arguments() { } // 语法错误
var f = new Function("arguments", "'use strict'; return 17;"); // 语法错误
8.2 arguments不再追踪参数的变化
function f(a) {
a = 2;
return [a, arguments[0]];
}
f(1); // 正常模式为[2,2]
function f(a) {
"use strict";
a = 2;
return [a, arguments[0]];
}
f(1); // 严格模式为[2,1]
8.3 禁止使用arguments.callee
- 正常模式下,arguments.callee 指向当前正在执行的函数。这个作用很小:直接给执行函数命名就可以了!
- 此外,arguments.callee 十分不利于优化,例如内联函数,因为 arguments.callee 会依赖对非内联函数的引用。在严格模式下,arguments.callee 是一个不可删除属性,而且赋值和读取时都会抛出异常:
- 这意味着无法在匿名函数内部调用自身了
"use strict";
var f = function() { return arguments.callee; };
f(); // 抛出类型错误
9. 函数必须声明在顶层
- 严格模式禁止不在脚本或者函数层面上的函数声明。在浏览器的普通代码中,在所有地方的函数声明都是合法的。
"use strict";
if (true) {
function f() { } // !!! 语法错误
f();
}
for (var i = 0; i < 5; i++) {
function f2() { } // !!! 语法错误
f2();
}
function baz() { // 合法
function eit() { } // 同样合法
}
10. 保留字
- 在严格模式下,不能用以下名作作为变量名或者参数名
- implements
- interface
- let
- package
- private
- public
- static
- yield
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通