介绍
o(╯□╰)o
严谨模式的特性
o(╯□╰)o
严谨模式下的限制
未来保留字
新增了一些保留字,它们不能在严谨模式下作为变量名使用,包括:implements,interface,let,package,private,protected,public,static,yield。
八进制扩展
o(╯□╰)o
o(╯□╰)o
给未声明的变量赋值
ES3里有个问题,就是给未声明的变量赋值会导致在全局对象上创建一个变量。下面这有个例子:
// non-strict mode
(function foo() {
// local vars
var x = y = 20;
})();
// unfortunately, "y" wasn't local
// for "foo" function
alert(y); // 20
alert(x); // "x" is not defined
截图是在JS Bin里执行这段代码,Chrome的版本是:Version 59.0.3071.115 (Official Build) (64-bit),今天是2017-07-31。
这个执行结果证实了y被创建在了全局对象上面。但是在严谨模式下,这个问题就不存在了:
这段代码是直接在Chrome里执行的(相同版本),没有通过JS Bin,可见在严谨模式下,由于y不存在解释器抛出异常。
接着作者指出在一个貌似合理的情景下,也是会抛出异常,就是用分组符号把右边的表达式包起来:
按照执行的优先级和顺序,你或许会以为undeclared应该在执行赋值操作之前被创建了,所以这个写法应该可行。作者说它其实会抛出异常,我在Chrome里执行没有见到。甚至下面的代码运行起来感觉一切正常:
"use strict";
undeclared = (this.undeclared = 10, alert(undeclared), 10);
console.log(undeclared); // 10
至于作者的观点,作者也是有依据的,那就是ECMA官方对于赋值操作的规范:http://www.ecma262-5.com/ELS5_Section_11.htm#Section_11.13.1
重点就是,在赋值操作一开始,先对等号左边与右边的表达式分别进行估值,然后才进行赋值操作,这个时候对左边表达式估值得出的结果已经不会再被影响了,所以如果它不存在,赋值操作就会抛出索引异常。
给只读属性赋值
ES5里面的只读属性就有两种情况了:
一种是数据属性,它的[[Writable]]是false;
另一种是访问器属性,它没有[[Set]]。
更多细节参见同系列第一篇,在严谨模式下给这两类属性赋值都会导致异常。
但是,有个特殊情况,如果属性的[[configurable]]是true,那么通过defineProperty()修改它没有问题,可是通过赋值操作修改却会抛出异常。
遮蔽继承的只读属性
直接从代码讲好了:
按照图中代码所示,foo上面定义了一个只读属性x,bar又继承了foo。在bar上尝试直接重写x的值,这个操作在非严禁模式下不会报错,但是也不会成功,如图所示,赋值操作之后bar.x的值还是10。
但是,在严谨模式下,这个操作会导致异常被抛出:
可是如果通过defineProperty()来修改,就不会有问题:
在不可扩展对象上创建一个新属性
eval和arguments的限制
callee和caller的限制
从作者的示例代码的运行情况来看,至少在Chrome里,这个非严谨模式下的行为已经改变了,从我得到的执行结果来看,赋值bar.caller.arguments[0]没有效果,等于没有执行。
关于caller的讨论就这么多,下面就是callee了。
先来验证下作者的第一个观点:在非严禁模式下,可以通过callee在一个匿名函数内调用其自身。
看来这一点依然是成立的。作者的下一个观点是:arguments.callee在严谨模式下将不能用,如果想要在函数表达式里调用自身,只能给它命名:
callee果然不能在严谨模式下使用。
所以,在严禁模式下,只能使用命名函数表达式。
o(╯□╰)o
结论
o(╯□╰)o