orangeyyy
12/11/2017 - 11:57 AM

JS 严格模式

概述

严格模式(strict mode)是ECMAScript5退出的一套相对正常运行模式的模式,主要是为了让js在更加严格的条件下运行。 增加严格模式的主要目的是:

  • 消除js语法的不合理、不严谨的地方,减少怪异的使用行为;
  • 消除代码运行一些不安全的地方;
  • 提高编译器效率,增加运行速度;
  • 为未来新版本做铺垫;

包括IE10在内的主流浏览器已经支持严格模式,参见支持情况

使用方式

针对整个脚本文件

将“use strict”放在脚本的第一行(前面产生实际运行结果就行),则整个脚本将会在严格模式下运行,如果不在第一行则失效,代码将以正常模式运行,所以做jsbundle的时候要注意这个问题。

'use strict';

function func(){}
<script>
  'use strict';
  function func1(){}
</script>

<script>
function func2(){}
</script>

PS: 上面这段,在第一个script块中会以严格模式运行,后面这个会以正常模式运行。

针对函数

将"use strict"放在函数体的第一行,整个函数会以严格模式运行。

function func() {
  'use strict';
  alert('hello');
}

变通方法

为了解决上面第一种方式js 合并的问题,可以用匿名函数包裹脚本的方式解决。

(function(){
  'use strict';
  function func() {}
})()

主要内容

全局变量显式申明

在正常模式中,如果变量没有申明就赋值,默认为全局变量,严格模式不允许这种赋值;

'use strict';
v = 100; //报错
for (i = 1; i < 10; i++) {} //报错

静态绑定

js允许静态绑定,即属性或方法属于哪个对象,不在编译阶段确定,而是在运行时确定。严格模式对动态绑定做了限制,有些情况下只能用静态绑定,这样可以提高编译效率,提升代码可读性。

  • 禁止使用with语句
'use strict';
var v = 2;
with (o) { //语法错误
  alert(v);
}
  • 创设eval作用域 正常模式下,js有两种作用域,全局作用域和函数作用域,eval的作用域根据它所处的位置是全局作用域还是函数作用域来决定,严格模式新增了一个eval作用域。
'use strict';
var v = 2;
console.log(eval("var v = 5; v")); //5
console.log(v) //2

增强安全措施

  • 禁止this对象指向全局对象

function() {
  return !this; //返回fasle,因为this指向全局对象
}
function() {
  'use strict';
  return !this; //返回true,因为this是undefined
}

因此在使用构造函数时往了加new 会报错

'use strict';
function f() {
  this.name = 'hello'
}

f(); //报错this未定义
  • 禁止在调用内遍历调用栈
function func() {
  'use strict';
  func.caller; //报错
  func.callee; //报错
  func.arguments; //报错
}
func();

禁止删除变量

严格模式下不允许删除变量,只有configurable为true的属性才可以删除。

'use strict';
var i = 10;
delete i; //报错

var obj = Object.create(null, {
  x: {
    value: 1,
    configurable: true
  }
});

delete obj.x //删除成功

显式报错

正常模式下对于只读变量进行复制,不会报错,只会默默失效,在严格模式下回报错。

"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';
var obj = {};
delete obj.prototype; //报错

重名错误

  • 对象不能有重名属性,在正常模式下,后面声明的属性会覆盖前面的属性;
'use strict';
var obj = {
  a: 1,
  a: 2
} //会报语法错误
  • 函数不能有重名参数,在正常模式下,可以通过arguments[i],来获取不同的参数;
'use strict';
function func(a, a, b) {
  
} //会报语法错误

禁止8进制写法

正常模式下数字以0开头表面为八进制数,严格模式禁止这种表达方式,数字前面为0会报错。

'use strict';
var num = 0100; //报错

arguments限制

严格模式对arguments的使用做了很多限制。

  • 不能对arguments赋值;
'use strict';
arguments++; //报错

function arguments() {} //报错

try {} catch(arguments) {} //报错
  • 不能追踪arguments变化;
//正常模式下
function func(a) {
  a = 2;
  return [a, arguments[0]];
}
func(1); //返回[2,2]
//严格模式下
'use strict'
function func(a) {
  a = 2;
  return [a, arguments[0]];
}
func(1); //返回[2,1]
  • 禁止使用arguments.callee;
'use strict';
function func() {
  return arguments.callee;
}
func(); //报错

function.caller也是禁用的;

函数必须声明在顶层

由于当时考虑到js会引入块级作用域,所以在严格模式下,规定,函数声明必须在全局或者函数作用域的顶层进行声明。

'use strict';
if (true) {
  function func() {} //语法错误
}

for(var i = 0; i < 10; i++) {
  function func() {} //语法错误
}

###保留字 严格模式下增加了新的保留字:implements, interface, let, package, private, protected, public, static, yield。此外,ECMAscript第五版本身还规定了另一些保留字(class, enum, export, extends, import, super),以及各大浏览器自行增加的const保留字,也是不能作为变量名的。

参考