JavaScript严格模式

2019-08-13
  • 初步了解严格模式
  • 一个用心良苦的语言模式设计

 一、初步了解严格模式

ECMAScript 5的严格模式是采用具有限制性JavaScript变体的一种方式,从而使代码显示地“脱离马虎模式/稀松模式/懒散“模式。

为什么这么说呢?有时候忘记在作用域链上是否存在某个变量了,或者忘记在那一层作用域,但是当前作用域需要对这个似乎存在的变量赋值,在非严格模式下可以直接在当前作用域给这个变量赋值,如果在作用域链上不存在这个变量,最终这个变量会被定义到全局。

这种不严谨的代码在非严格模式下可能看起来不会有什么问题,但是对于全局变量命名会造成非常大的困扰,而且程序性能也会受到很大的挑战。

往好的方向说非严格模式对这种错误行为的静默是一种容错行为,但是这必然会带来另一种情况就是:可能在编程中写错一个变量名的赋值行为,这时候程序不能正确修改变量的值,还错误的在全局添加了一个变量,若说这是一种容错行为,显然不是一个很好的编程思想。

随着前端程序的复杂性越来越高,JavaScript这种不严谨的编码方式给代码的编写和管理带来了很大的挑战,在ES6的一些语法中就为了摒弃这种不严谨的行为出现了新的语法模式,语言设计者为了从ES5到ES6的过渡,以及为了JS语言能承担其未来的前端发展,在ES5中提出了严格模式。

严格模式的具体内容:

1.不允许使用为申明的变量:

1 "use strict"
2 a = 10; // 报错
3 function fun(){
4     b = {                //报错
5         name:"他乡踏雪" 
6     };
7 }

2.不允许删除变量:

1 "use strict"
2 var x = 3.14;
3 function fun(){
4     return 123;
5 }
6 delete x;         //报错
7 delete fun;        //报错

3.不允许变量重命名:

1 "use strict"
2 function fun(a, a){};//报错:准确说是不允许形参重命名
3 function foo(a){
4     var a = 10; //不报错
5 }

4.不允许八进制的数值:

1 "use strict";
2 var x = 010; //报错

5.不允许转义字符:

1 "use strict";
2 var x = \010;  //报错

6.不允许对只读属性赋值:

1 "use strict";
2 var obj = {};
3 Object.defineProperty(obj, "x", {value:0, writable:false});
4 obj.x = 3.14; //报错

6.0这种也算是不允许只读属性赋值:

1 "use strict";
2 var obj = {get x() {return 0} };
3 obj.x = 3.14;  //报错

7.不允许删除不允许删除的属性:

1 "use strict";
2 delete Object.prototype; //报错,虽然这种删除在非严格模式下也没有实际意义

8.不能使用with语句:(如果需要了解with的实现原理:https://www.cnblogs.com/ZheOneAndOnly/p/11333635.html)

1 "use strict";
2 with (Math){x = cos(2)}; //报错:因为严格模式不能使用未定义变量直接赋值

9.严格模式下全局eval()会创建自己的作用域(意味着在严格模式下全局eval语句没有实际意义):

1 "use strict"
2 eval("var a = 10");
3 console.log(a); //a is not defined

10.不能使用arguments作为变量名,作为一个非关键字,在严格模式下也不能使用其作为变量名:

1 "use strict";
2 var arguments = 3.14; //报错

11.禁止this指向全局对象:

1 "use strict"
2 function fun(){
3     console.log(this); //undefined ,可以说直接执行函数没有this指向(未定义),不能说他指向undefined
4 }
5 fun();

11.0所以如果在严格模式下方法内使用this就必须是被对象调用执行,未定义的this返回undefined,undefined不能有属性和方法。所以如果在严格模式下使用方法来构建对象忘了写new关键字,构造方法内使用this来定义对象属性和方法就必然会报错,而不再是之前的函数执行时this指向window全局对象。

1 function f(){
2     "use strict";
3     this.a = 1;
4 };
5 f();// 报错,this未定义

12.严格模式下原始值类型不会发生隐式类型转换:

1 "use strict"
2 var a = 10;
3 a.text = "10"; //报错

13.严格模式新增关键字:

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

声明严格模式:
1 "use strict" //全局声明严格模式:在全局的顶端声明,前面可以出现注释。
2 
3 function fun(){
4     "use strict" //函数内部声明严格模式:在函数的作用域内的第一行声明,同样前面只可以出现注释5 }

 严格模式的兼容性:

IE 10、Firefox 4、Chrome 13、 Safari、Opera 12。

在不支持严格模式的浏览器也不用担心,根据严格模式编写的代码相比非严格模式的代码具备更好的可靠性,非严格模式的声明只是一个字符串赋值空执行。

 二、一个用心良苦的语言模式设计

 2.1严格模式对正常的JavaScript做的一些更改:
  • 严格模式下通过抛出错误来消除原有静默的错误。
  • 严格模式修复了一些导致JavaScript引擎难以执行的缺陷:有时候相同的代码,严格模式可以比非严格模式运行得更快。
  • 严格模式禁用了在ECMAScript得未来版本中可能会定义得一些语法。
2.2将过失错误转换成异常:
  • 严格模式下不会在意外情况下创建全局变量。(第一部分中情况1)
  • 严格模式下会使引起静默失败不报错抛出异常,比如NaN是不可写得全局变量,正常模式下给NaN赋值不会产生任何作用也不会反馈错误信息。(第一部分情况6)
  • 在严格模式下删除不可删除得属性时会抛出异常。(第一部分情况7)
  • 严格模式下对象属性不能重命名(ES6中已经修复,不抛出错误)
  • 严格模式下参数名唯一。(第一部分情况3)
  • 严格模式下ECMAScript中包含八进制语法。(第一部分情况4)
  • 严格模式下原始值(primitive)类型不会发生隐式类型转换。(第一部分情况12)
2.3简化变量得使用:

很多编译器得优化是依赖追踪变量位置得能力,但是在正常模式下有几种情况没法正确得追踪到变量得位置,比如with中的变量、eval中生成得变量都是动态生成得结构,没办法正确定位,这种情况下就没办法做代码优化。

2.3.1在严格模式禁用了with,限定了eval在全局作用下创建独立作用域,这时候变量也不会影响到全局上变量了。(第一部分情况8,9)

2.3.2严格模式下还禁止了删除变量。(第一部分情况7)

2.3.3arguments不能作为变量名。(第一部分情况10)

简化变量使用后,能让编译器更好的优化代码(具体内部原理还不清楚,只是在MDN手册上阅读到这些操作有利于编译器优化代码)。

2.4安全的JavaScript

 1.4.1严格模式下this不会被强制转换成一个对象,原始值类型不会被隐式转换。

 1.4.2严格模式下不能删除函数的caller和arguments属性,并且读写都会报错。

 1.4.3严格模式下不能使用arguments访问和调用这个函数的相关变量。

这些处理过后会让JavaScript变得更安全。

 

更多相关内容可以访问MDN手册:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode