JavaScript中的严格模式

本文同步自 我的博客,地址:http://reeoo.me/archives/strictmode.html

什么是严格模式

我们平时写的JavaScript代码一般都运行在正常模式中的,除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict mode)。看名字就知道,这种模式会让JavaScript在更严格的环境中运行。

包括IE 10在内的主流浏览器,都已经支持它,许多大项目已经开始全面拥抱。(github上面好多项目都是用的严格模式)

启用严格模式

为整个脚本启用严格模式

在所有语句之前放一个特定语句 "use strict",假设有一个脚本reeoo.js,可以这样开启严格模式:

"use strict";
var name = "Reeoo";
console.log(name);

BUT这种写法存在天然的坑,假如我们要做代码合并,我现在要把heigui.js

heigui = "db";

reeoo.js进行合并,本来两个脚本分开执行是好好的,合起来就会报错。

Uncaught ReferenceError: heigui is not defined(…)

一个严格模式的脚本和一个非严格模式的脚本合并可能会导致非严格模式的脚本代码报错,建议代码都包在一个立即执行函数里面。

(function(){
    "use strict";
    var name = "reeoo";
})();

(function(){
    heigui = "db";
})();

这样合并之后就不会报错了。

为某个函数启用严格模式

要给某个函数开启严格模式,得把"use strict"; 声明放在函数体所有语句之前就行了。

function strictFun()
{
  // 函数级别严格模式语法
  'use strict';
  console.log('I am a strictmode function!');
}

function normalFun() { 
    console.log('I am a mormal function!');
}

Chrome中调试严格模式

我有这么一段代码:

'use strict'
name = "reeoo";
console.log(name) 

把这段代码直接粘贴到Chrome的控制台中执行,正常情况下应该报错,但是并没有报错,

ChromeConsole

很显然,严格模式下变量不适用var声明是不合法的,但是为什么没有报错?

这是什么鬼,难道Chrome不支持严格模式?开什么玩笑。。。

网上搜了一下,原来Chrome的控制台的代码是运行在eval之中的,你没法对eval函数使用严格模式(应该也不完全对,但是具体Chrome做了什么,不得而知),下图说明eval函数可以使用严格模式:

NodeEval

要想在Chrome浏览器中对严格模式正常报错,需要在代码外层套一个立即执行函数,或者其它类似的措施。

(function(){
    'use strict'
    name = "reeoo";
    console.log(name) 
})()

这样就可以了

FireFox代码草稿纸调试严格模式

Chrome非要我们包一层闭包才能跑严格模式,既然这么麻烦,有没有别的方式可以直接跑严格模式的代码呢?

FireFox有一个代码草稿纸可以直接跑,快捷键SHIFT+F4

FF代码草稿纸

严格模式到底有多严格

严格模式中一些重要的限制

1. 变量声明

不允许使用一个没有声明的变量

"use strict";
name = "reeoo";

报错(代码草稿纸,下同)

Exception: ReferenceError: assignment to undeclared variable name

2. 修改只读属性的值

"use strict";
var testObj = Object.defineProperties({}, {
    prop1: {
        value: 10,
        writable: false // 一个只读的属性
    },
    prop2: {
        get: function () {
        }
    }
});
testObj.prop1 = 20; //尝试改变prop1的值
testObj.prop2 = 30;//尝试改变prop2的值

严格模式下会报错:

Uncaught TypeError: Cannot assign to read only property 'prop1' of #<Object>

非严格模式顶多就是值赋不上去而已,并不会报错

3. 修改不可扩展的属性

表现为将属性添加到 extensible 属性设置为 false 的对象。

"use strict";
var testObj = new Object();
Object.preventExtensions(testObj);//经过这个方法处理过的对象,不影响原有对象的删除,修改.但是无法添加新的属性成员了.
testObj.name = "reeoo";

严格模式报错:

Uncaught TypeError: Can't add property name, object is not extensible

非严格模式不会报错,但是testObj也不会被扩展。

4. 删除变量、函数或参数

删除 configurable 特性设置为 false 的属性。

"use strict";
var testvar = 15,testObj={};
function testFunc() {};
delete testvar;
delete testFunc;

Object.defineProperty(testObj, "testvar", {
    value: 10,
    configurable: false
    });
delete testObj.testvar;

报错:

Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.

5. 在一个对象文本中多次定义某个属性

严格模式下不允许一个属性有多个定义

"use strict";
var testObj = {
    prop1: 10,
    prop2: 15,
    prop1: 20
};

报错(node控制台)

Duplicate data property in object literal not allowed in strict mode

正常模式中后声明的重复的变量会覆盖前面声明的,而且不会报错。

注:这个问题在ECMAScript6中已被修复。

6. 严格模式下不允许形参参数名称重复

"use strict";
function testFunc(param1, param1) {
    return 1;
};

报错:

Uncaught SyntaxError: Duplicate parameter name not allowed in this context

7. 无法使用标识符的未来保留字,严格模式下将保留标识符名称

一下标识符(ES6中依然没有实现的)在严格模式中是不能使用的,否则也会报错。

用了就是这个下场:

Uncaught SyntaxError: Unexpected strict mode reserved word
implements
interface
package
private
protected
public
static
yield

8. 严格模式下不允许使用八进制数字参数和转义字符

"use strict";
var testoctal = 010;
var testescape = \010;
 

报错:

Uncaught SyntaxError: Unexpected token ILLEGAL(…)

9. 当 this 的值为 nullundefined 时,该值不会转换为全局对象

比如:

"use strict";
function testFunc() {
    return this;
}
var testvar = testFunc();

在非严格模式下,testvar 的值为全局对象window,但在严格模式下,该值为 undefined

10. 字符串"eval"不能用作标识符(变量或函数名、参数名等)

"use strict";
var eval = "hehe";
Uncaught SyntaxError: Unexpected eval or arguments in strict mode

11. 在严格模式下,函数声明无法嵌套在语句或块中。它们只能显示在顶级或直接显示在函数体中

"use strict";
var arr = [1, 2, 3, 4, 5];
var index = null;
for (index in arr) {
    function myFunc() {};
}

node控制台:

SyntaxError: In strict mode code, functions can only be declared at top level or immediately within another function.

但是这个限制已经在ES6中被修复。

12. 严格模式下eval用法无效

如果在 eval 函数内声明变量,则不能在此函数外部使用该变量。

"use strict";
eval("var testvar = 10");
console.log(testvars);
Uncaught ReferenceError: testvar is not defined

13. 严格模式下"arguments"用法无效

字符串"arguments"不能用作标识符(变量或函数名、参数名等)。

"use strict";
var arguments = 1;
Uncaught SyntaxError: Unexpected eval or arguments in strict mode

这个跟上面第10条的限制是差不多的。

14. 函数内的 arguments,无法更改arguments 对象的成员的值

"use strict";
function testArgs(oneArg) {
    arguments[0] = 20;
}

在非严格模式下,可以通过更改 arguments[0] 的值来更改 oneArg 参数的值,从而使 oneArgarguments[0] 的值都为 20。在严格模式下,更改 arguments[0] 的值不会影响 oneArg 的值,因为 arguments 对象只是一个本地副本。

15. 不允许使用arguments.callee

"use strict";
function my(testInt) {
    if (testInt-- == 0)
        return;
    arguments.callee(testInt--);
}
my(100);

用了的下场就是这样:

Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them

16. 不允许使用with

"use strict";
with (Math){
    x = cos(3);
    y = tan(7);
}
Uncaught SyntaxError: Strict mode code may not include a with statement

为什么要使用严格模式

既然这种模式这么多限制,我为什么还要用呢?闲得蛋疼吗?当然8是。

JavaScript作为一门一开始用于浏览器的脚本语言,容错性非常好,即使有时候你的代码写的不标准,也不会报错,但这有时候会变成代码隐患。开启了严格模式之后,JavaScript的一些不合理的不严谨的语法都会得到控制,让你能够更严谨的书写JavaScript代码,成为一个更好的程序员。严格模式是ES5时代的产物,ES2015已经在普及的路上,是时候使用严格模式了!

参考

  1. 严格模式

  2. 严格模式

阅读 4.1k

推荐阅读
Reeoo's Page
用户专栏

Reeoo's Page

8 人关注
5 篇文章
专栏主页