JavaScript严格模式
- 初步了解严格模式
- 一个用心良苦的语言模式设计
一、初步了解严格模式
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