javascript严格模式

  目录

js的严格模式和普通模式的区别

javascript严格模式

随着javascript的不断发展,严格模式在开发中是必须使用的,他有什么好处呢?
严格模式消除了一些不确定的行为,并且对某些不安全的操作抛出异常。它有助于解析引擎,优化代码,提高执行速度,也为以后新标准的制定留出余地。下面将对严格模式做一个详细的介绍。

1.启用严格模式

要使一个javascript文件运行于严格模式,只需要在文件顶部添加如下代码:

1
"use strict";

或者

1
'use strict';

这行代码是一个编译指示,用以告知解析引擎以严格模式解析脚本。严格模式可以用于整个脚本或单个函数。在用于脚本文件时,”use strict”需放在所有其它语句前面。

1
2
3
// whole-script strict mode syntax
"use strict";
var v = "Hi! I'm a strict mode script!";

而用于函数时,需方在函数内第一行。

1
2
3
4
5
6
7
8
9
10
11
function strict() {
// Function-level strict mode syntax
'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.";
}

2.严格模式带来的变化

在语法和行为这两方面,严格模式都做了一些改变。这些变化主要分为以下几类。

  • 对错误抛出异常,而不是静默地忽略;
  • 简化变量的使用,去掉引擎难以优化的语法功能;
  • 简化eval和arguments的使用;
  • 增加安全特性;
  • 为javascript迎接新标准做准备;

1)

对错误抛出异常,而不是静默的忽略。严格模式将过去那些能够被静默忽略的错误变成异常抛出,因为这类错误代表着代码目的的矛盾。不一致的代码也许在当时不会产生什么不良后果,但未来可能会引起严重问题。严格模式不会容忍这些错误,使得开发者能够立即发现并且解决。

(1)

在正常模式下,对一个没有声明的变量赋值,会自动作用到全局对象上(node的global对象,浏览器的window对象)。严格模式禁止这种做法,以避免意外地修改全局对象。

1
2
"use strict"
mistypedVaraible = 17; // ReferenceError

上面的代码将会抛出类型为ReferenceError的异常

(2)

在正常模式下,引擎会默认忽略对NaN赋值的语句,但在严格模式下,引擎会以抛异常的方式,立即向开发者反馈错误。类似的还有给一个指定为不可写的属性赋值,对只有取值函数getter的属性赋值,给一个不可扩展的对象增加属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"use strict"
// Assignment to NaN
NaN = 'a'; // TypeError: Cannot assign to read noly property 'NaN' of #<Object>
// Assignment to a non-writable property
var obj1 = {};
Object.defineProperty(obj1, "x", {
value: 42,
writable: false
});
obj1.x = 9; // throws a TypeError
// Assignment to a getter-only property
var obj2 = {
get x() {
return 18;
}
};
obj2.x = 5; // throws a TypeError
// Assignment to a new property on a non-extensible object
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // throws a TypeError

(3)

严格模式禁止删除一个声明为不可删除的属性。

1
2
"use strict";
delete Object.prototype; // throws a TypeError

(4)

严格模式禁止声明重名属性。

1
2
3
4
5
"use strict";
var o = {
p: 1,
p: 2
}; // !!! syntax error

(5)

严格模式规定,函数的参数名必须唯一,否则抛出语法错误。在正常模式下,相同名称的参数,位置最靠后的会把前面的隐藏,但所有参数仍然可以借由arguments[i]访问,因此这种隐藏的意义不大,很可能写错了。

1
2
3
4
function sum(a, a, c) { // syntax error
"use strict";
return a + b + c; // wrong if this code ran
}

(6)

八进制数的写法。ECMAScript 5 标准下的严格模式禁止八进制数,但在ECMAScript 6标准下,八进制数前面需要加0o。Node支持前面加0o的八进制数,例如:

1
2
3
4
5
6
7
8
9
"use strict";
// Right
var a = 0o10; // ES6: Octal
console.log(a);

// 以下代码异常
// SyntaxError
var sum = 015 + // syntax error
197 + 142;

(7)

严格模式禁止为基本数据类型添加属性,以下操作非法。

1
2
3
4
5
6
(function() {
"use strict";
false.true = ""; // TypeError
(14).sailing = "home"; // TypeError
"with".you = "far away"; // TypeError
})();

2)

简化变量的使用,去掉引擎难以优化的语法功能。

(1)

严格模式禁止使用with。with的问题在于,其语句内部的变量名只有在运行的时候才能够被决定,这使得引擎在编译阶段难以生成高效的代码。因为with代码块中的名称即有可能代表语句内部的变量,也有可能是with表达式中的对象属性,还有可能位于代码块外,甚至是全局对象的属性。

1
2
3
4
5
"use strict";
var x = 18;
with(obj) { // syntax error
x;
}

(2)

严格模式下,eval有单独的作用域,不能够使用eval语句在它之外创建变量。正常模式下,语句

x;")```会为它所在的运行环境声明一个变量x,在严格模式下,x只在eval语句的内部有效。
1
2
3
4
5
```
var x = 18;
var evalX = eval("'use strict'; var x = 42; x");
console.assert(x === 18);
console.assert(evalX === 42);

(3)

严格模式禁止删除变量。

1
2
3
4
"use strict";
var x;
delete x; // syntax error
eval("var y; delete y;"); // syntax error

3)

简化eval和arguments的使用。严格模式将eval和arguments的一些怪异和奇特的用法做了限制,并倾向于将eval和arguments当作关键字处理。

(1)

严格模式不允许对eval和arguments赋值。以下语句运行都会报错。

1
2
3
4
5
6
7
8
9
10
11
"use strict";
eval = 18;
arguments++;
++eval;
var obj = { set p(arguments) { } };
var eval;
try { } catch(arguments) { }
function x(eval) { }
function arguments() { }
var y = function eval() { };
var f = new Function("arguments", "'use strict'; return 18;");

(2)

在严格模式下,修改函数参数不会影响arguments,下面的示例代码能够正常运行。

1
2
3
4
5
6
7
8
function f(a) {
"use strict";
a = 42;
return [a, arguments[0]];
}
var pair = f(18);
console.assert(pair[0] === 42);
console.assert(pair[1] === 18);

(3)

arguments.callee不能再使用了。正常模式下,arguments.callee返回正在执行的函数本身的引用。在严格模式下,这种用法被禁止。

1
2
3
4
5
"use strict"
var f = function() {
return arguments.callee;
}
f(); // throws a TypeError;

4)

增加安全特性。在严格模式下,写出安全的代码变得更容易,引擎不会越俎代庖,除非使用者有意地这样做。

(1)

在严格模式下,函数的上下文对象this可以是简单的值,并且避免了对全局对象的引用。在正常模式下,this只是一个对象,例如下面的代码:

1
2
3
4
function() {
console.log(this);
}
f.call(true);

运行结果为[Boolean: true],引擎会自动地将简单类型打包为对应的对象。单严格模式不会做这样的转换。

1
2
3
4
5
"use strict";
function f(a) {
console.log(this);
}
f.call(true);

运行结果为true。
正常模式下,如果不指定this对象,或者指定为undefined或null,则this引用的是全局对象。

1
2
3
4
function f(a) {
console.log(this);
}
f.call(null);

上面的代码打印出全局的global对象。但在严格模式下,除非使用call或apply明确指定this为global对象,否则this为null或者undefined。

1
2
3
4
5
6
"use strict";
function f(a) {
console.log(this);
}
f.call(null);
f();

结果为:

1
2
null
undefined

(2)

严格模式禁止访问函数对象属性caller和arguments,这意味着不再可能遍历调用堆栈了。

1
2
3
4
5
6
7
8
9
10
11
12
"use strict";
function outer() {
inner();
}
function inner() {
console.log(arguments.callee.caller);
// TypeError: 'caller', 'callee', and
// 'arguments' properties may not be accessed
// on strict mode functions or the arguments
// objects for calls to them
}
outer();

5)

保留关键字。严格模式将implements,interface,let,package,private,protected,public,static和yield作为保留字,用户代码不能以这些名称命名变量。

1
2
3
4
5
6
7
8
9
10
11
12
function package(protected) { // SyntaxError
"use strict";
var implements; // SyntaxError
interface; // SyntaxError
while(true) {
break interface; // SyntaxError
}
function private() { } // SyntaxError
}
function fun(static) { // SyntaxError
"use strict";
}