概述

严格模式是什么

严格模式是Javascript中的一种限制性更强的変种方式。严格模式不是一个子集:它在语义上与正常代码有着明显的差异。

不支持严格模式的刘览器与支持严格模式的浏览器行为上也不一样,所以不要在未经严格模式特性测试情况下使用严格模式。

严格模式可以与非严格模式共存,所以脚本可以逐渐的选择性加入严格模式。

严格模式的目的

首先,严格模式会将Javascript陷阱直接变成明显的错误。

其次,严格模式修正了一些引擎难以优化的错误:同样的代码有些时候严格模式会比非严格模式下更快

第三,严格模式禁用了一些有可能在未来版本中定义的语法。

开启严格模式

全局开启严格模式

只需要在全局写以下字符串即可。作用于全局作用域

1
2
3
"use strict";
a = 100;
console.log(a);

函数开启严格模式

在函数内写以下字符串即可。只作用于函数作用域。例如:

1
2
3
4
5
function fn() {
"use strict";
v = 200;
console.log(v);
}

变量

禁止意外创建变量

  1. 非严格模式

    在函数作用域中定义变量,不适用var关键字那么自动将其提升为全局变量。例如:

    1
    2
    3
    4
    5
    6
    function fn() {
    w = 200;
    console.log(w); //200
    }
    fn();
    console.log(w); //200
  2. 严格模式下

    在严格模式下则会抛出异常

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    "use strict";
    function fn() {
    // 在函数作用域中定义变量 - 不适用var关键字-> 自动将其提升为全局变量
    w = 200;
    console.log(w);
    }
    fn();
    console.log(w);
    // v = 100;
    // ^

静默失败转为异常

所谓静默失败就是既不报错也没有任何效果,例如改变常量的值。在严格模式下,静默失败会转换成抛出异常。

例如:

1
2
3
4
5
6
// 定义一个常量
const v = 3.14;

// 重新赋值
v = 1.14;
console.log(v);

以上代码在稍微老一点的浏览器可能并不会报错(新版报错),但开启严格模式后,一定会报错。

禁止delete关键字

在严格模式下不能对变量使用delete运算符。

例如:

1
2
3
4
5
6
var v = 100;

console.log(v); //100

delete v;
console.log(v); //100
  1. 严格模式下会抛出一个错误
  2. 非严格模式下会输出两个100

严格模式下禁用delete只针对删除变量,而不是数组元素和对象属性。

1
2
3
4
5
6
7
8
9
10
"use strict";
var arr = [0, 1, 2, 3, 4];
delete arr[0];
console.log(arr); //[ <1 empty item>, 1, 2, 3, 4 ]

var obj = {
name: "张无忌",
};
delete obj.name;
console.log(obj.name); // undefined

对变量名的限制

在严格模式下,JavaScript对变量名也有限制。特别不能使用如下内容作为变量名:

  • implements
  • interface
  • let
  • package
  • private
  • protected
  • public
  • static
  • yield

上述关键词表示在ECMAScript的下一个版本中可能会用到他们,在严格模式下使用以上字符作为变量名会导致语法错误。

对象

不可删除的属性

1
2
3
4
"use strict";
delete Object.prototype;
console.log(Object.prototype);
// 报错

非严格模式下不会报错,但也不会删除成功。但在严格模式下会直接抛出错误。

但严格模式并不会限制所有对象,例如:

1
2
3
4
"use strict";
delete Math.random;
console.log(Math.random); //undefined
Math.random();

即使在严格模式下,还是可以删除Math.random方法。

属性名必须唯一

在严格模式下,一个对象内的所有属性名在对象内必须唯一。

1
2
3
4
5
6
"use strict";
var obj = {
name: "张无忌",
name: "周芷若",
};
console.log(obj.name); // 周芷若

开启严格模式后,如果对象具有相同属性,那么并不会报错,而是覆盖。

image-20200605175526975

只读属性的赋值

1
2
3
4
5
6
7
8
9
10
11
12
"use strict";
var obj = {};
Object.defineProperty(obj, "age", {
value: 18,
});
// 针对只读属性进行修改操作

obj.age = 80;
console.log(obj.age);

delete obj.age;
console.log(obj.age);

对于不可修改的属性,无论是修改还是删除都会发生报错。

不可扩展的对象

在严格模式下,不能为不可扩展的对象添加新属性。

1
2
3
4
5
6
7
8
9
"use strict";
var obj = {};
// 设置对象obj是一个不可扩展的对象
Object.preventExtensions(obj);

// 为对象obj新增属性或方法

obj.name = "张无忌";
console.log(obj);

以上代码在严格模式下会报错,非严格模式下不会报错。

函数

参数名必须唯一

在严格模式下,要求命名函数的参数必须唯一。

1
2
3
4
function fn(a, a, b) {
console.log(a + a + b);
}
fn(1, 2, 3); //7

例如以上代码,非严格模式下会输出7,两个参数a都会被当作2;但在严格模式下,会抛出错误。

arguments的不同

在严格模式下, arguments对象的行为也有所不同。

  • 非严格模式下,修改命名参数的值也会反应到arguments对象中。
  • 严格模式下,命名参数与arguments对象是完全独立的。
1
2
3
4
5
6
7
"use strict";
function fn(value) {
var value = "张无忌";
console.log(value); // 张无忌
console.log(arguments[0]); //严格模式下为周芷若 非严格模式下为周芷若
}
fn("周芷若");

非严格模式下arguments对象获取参数的值与形参有关。(如果局部变量与形参名相同,则根据就近原则获取);严格模式下arguments对象获取参数的值与形参无关。

arguments.callee()

在严格模式下,不能使用armaments对象的callee()方法。

1
2
3
4
5
"use strict";
function fn() {
return arguments.callee;
}
fn();

以上代码在严格模式下会直接报错。

函数声明的限制

在严格模式下,只能在全局域和函数域中声明函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"use strict";
// 在全局作用域
function fn() {
function n() {}
}

for (var i = 0; i < 10; i++) {
// ECMAscript 6 新增 - 存在块级作用域
var v = 100;
// 开启严格模式后在块级不能定义函数
function f() {
console.log("this is function");
}
}
console.log(v); // 100
f(); // ReferenceError: f is not defined

在严格模式下,函数的定义只能在全局作用域与函数作用域,不能在块级作用域

增加eval()作用域

在严格模式下,使用eval()函数创建的变量只能在eval()函数内部使用。

1
2
eval("var v = 100");
console.log(v);

以上代码在非严格模式下会输出100,而在严格模式下会抛出错误。

在严格模式下,会增加eval作用域。也就是说在eval函数定义的变量只能在当前eval函数使用。

arguments对象–禁止读写

在严格模式下,禁止使用eval()和arguments作为标示符,也不允许读写它们的值。

  • 使用var声明。
  • 赋予另一个值
  • 尝试修改包含的值。
  • 用作函数名。
  • 用作命名的函数的参数。
  • 在 try-catch语句中用作例外名。

以下语句在严格模式下均会报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
eval = 17;

arguments++;

++eval;

var obj = {
set p(arguments) {},
};

var eval;

try {
} catch (arguments) {}

function x(eval) {}

function (eval) { }

function arguments() { }

var y = function eval() { }

var f = new Function('arguments', "'use strict';return 17;")

抑制this

  • 在非严格模式下使用数的apyly()call()方法时,nullundefined值会被转换为全局对象。
  • 在严格模式下,函数的this值始终是指定的值(无论什么值)。
1
2
3
4
5
6
7
8
9
10
11
"use strict";
var v = 100;

function fn() {
console.log(this.v);
}

var obj = {
v: 200,
};
fn.call(null);

在严格模式下会抛出错误,必须明确指定this,例如fn.call(obj);