Snandy
If you cannot hear the sound of the genuine in you, you will all of your life spend your days on the ends of strings that somebody else pulls.
ES5严格模式(Strict mode)
https://www.cnblogs.com/snandy/p/3428171.html
严格模式(Strict mode)是由ECMA-262规范定义的新兴JavaScript标准,第五版发布于2009年12月。旨在改善错误检查功能并且标识可能不会延续到未来JavaScript版本的脚本。ES5严格模式是限制性更强的JavaScript变体,它与常规JavaScript的语义不同,其分析更为严格。
目前,除了IE6-9,其它浏览器均已支持ES5严格模式。
一、严格模式的使用
严格模式的使用很简单,只有在代码首部加入字符串 "use strict"。有两种应用场景,一种是全局模式,一种是局部模式。
1)全局模式
1
2
3
|
'use strict' var globalVal = 100 console.log(globalVal) |
执行后输出了100,与非严格模式没什么区别。
2)局部模式
将"use strict"放到函数内的第一行,如下
1
2
3
4
5
6
|
function func() { 'use strict' var localVal = 200 console.log(localVal) } func() |
执行后输出了200,与非严格模式也没用什么区别。
3)模块模式
如果你想定义一个模块或者一个小库,自然采用一个匿名函数自执行是不错的选择
1
2
3
4
5
|
~ function () { "use strict" ; // Define your library strictly... }(); |
“use strict” 的位置是很讲究的,必须在首部。首部指其前面没有任何有效js代码。以下都是无效的,将不会触发严格模式。
a)“use strict” 前有代码
1
2
3
|
var width = 10 'use strict' globalVar = 100 |
b)“use strict” 前有个空语句都不行
1
2
3
|
; 'use strict' globalVar = 100 |
或
1
2
3
4
5
|
function func() { ; 'use strict' localVar = 200 } |
或
1
2
3
4
|
function func() { ; 'use strict' localVar = 200 } |
当然,“use strict”前加注释是可以的
1
2
3
|
// strict mode 'use strict' globalVar = 100 |
或
1
2
3
4
5
6
|
function func() { // strict mode 'use strict' localVar = 200 } func() |
二、严格模式下的执行限制
上面举的两个例子,在严格模式中输出与普通模式没用什么区别。下面就不一样了。
1)不使用var声明变量严格模式中将不通过
我们知道JS是弱类型,宽松的语言。不使用var声明的变量默认转为全局变量。但在严格模式中将不允许,会报语法错误。
1
2
|
'use strict' globalVal = 100 |
执行,Firebug提示如下
又如全局的for循环
1
2
3
4
|
'use strict' for (i=0; i<5; i++) { console.log(i) } |
这种写法在非严格模式中很危险,i 会不小心溢出成为全局变量。但在严格模式中会报错
局部模式
1
2
3
4
5
6
|
function func() { 'use strict' localVal = 200 console.log(localVal) } func() |
执行,Firebug报错
因此,严格模式中声明变量务必记得加一个var。
2)任何使用'eval'的操作都会被禁止
1
2
3
4
5
6
7
8
9
|
'use strict' var obj = {} var eval = 3 obj.eval = 1 obj.a = eval for ( var eval in obj) {} function eval() {} function func(eval) {} var func = new Function( 'eval' ) |
Firebug报错
3)eval作用域
JS中作用域有两种,全局作用域和函数作用域。严格模式带来了第三种作用域:eval作用域,如下
1
2
3
4
|
'use strict' var a = 10 eval( 'var a = 20; console.log(a)' ) console.log(a) |
Firebug控制台依次输出了20,10。eval是在全局模式下(非函数内)的,如果不加严格模式,此时修改的是全局的a。即输出20,20。见 eval与window.eval的差别。
4)with被禁用
1
2
3
4
|
'use strict' with ({a:1}) { } |
Firebug报错
5)caller/callee 被禁用
1
2
3
4
5
6
|
function func() { 'use strict' arguments.callee arguments.caller } func() |
Firebug报错
6)对禁止扩展的对象添加新属性会报错
1
2
3
4
|
'use strict' var obj = {} Object.preventExtensions(obj) obj.a = 1 // 报错 |
Firebug报错
7)删除系统内置的属性会报错
1
2
3
|
'use strict' delete Object.prototype // 报错 delete Function.prototype // 报错 |
Firebug 报错
8)delete使用var声明的变量或挂在window上的变量报错
1
2
3
4
5
|
'use strict' var obj = {a:1} window.a = 1 delete obj // 报错 delete a // 报错 |
Firebug报错
9)delete不可删除属性(isSealed或isFrozen)的对象时报错
1
2
3
4
|
'use strict' var obj = {a: 1} Object.seal(obj) delete obj.a |
Firebug报错
10)对一个对象的只读属性进行赋值将报错
1
2
3
4
|
'use strict' var obj = {} Object.defineProperty(obj, 'a' , {value: 1, writable: false }) obj.a = 2 // 报错 |
Firebug报错
11)对象有重名的属性将报错
1
2
3
4
5
|
'use strict' var obj = { a: 1, a: 2 } |
Firebug报错
而在非严格模式中,后面的属性将覆盖前面的属性,即obj.a等于2。
12)函数有重名的参数将报错
1
2
3
4
5
|
'use strict' function func(a, a) { alert(a) } func() |
Firebug报错
而在非严格模式中,后面的同名参数将覆盖前面的。
13)八进制表示法被禁用
1
2
|
'use strict' var num = 022 |
Firebug报错
14)arguments严格定义为参数,不再与形参绑定
先看非严格模式代码
1
2
3
4
5
|
function func(a) { arguments[0] = 2 alert(a) // 2 } func(1) |
func调用时传参为1,函数内部通过arguments修改为2,此时alert的为修改后的2。 而在严格模式中则不能被修改,如下
1
2
3
4
5
6
|
'use strict' function func(a) { arguments[0] = 2 alert(a) // 1 } func(1) |
显示的严格的为传入的1。
其实有点还有点复杂,如果alert的是arguments[0],实际在严格模式中仍然被修改为2了。如下
1
2
3
4
5
6
|
'use strict' function func(a) { arguments[0] = 2 alert(arguments[0]) // 2 } func(1) |
可以参考下 仅Chrome中函数实参与形参发生关联
15)函数必须声明在顶层
我们知道函数声明和函数表达式是两个不同的概念。一般函数声明都在最顶层,ES5前的JS宽松,你可以写在if或for内(强烈鄙视这种写法)。当然Firefox的解析方式与其他浏览器不同,见SJ9002。而在严格模式中这些写法将直接报错
1
2
3
4
5
6
7
|
'use strict' if ( true ) { function func1() { } // 语法错误 } for ( var i = 0; i < 5; i++) { function func2() { } // 语法错误 } |
Firebug报错
16)ES5里新增的关键字不能当做变量标示符使用,如implements, interface, let, package, private, protected, public, static, yield
1
2
3
|
'use strict' var let = 10 var yield = 20 |
Firebug报错
17)call/apply的第一个参数直接传入不包装为对象
1
2
3
4
5
6
|
'use strict' function func() { console.log( typeof this ) } func.call( 'abcd' ) // string func.apply(1) // number |
Firebug输出如下
依次为"string","number"。而在非严格模式中call/apply将对值类型的"abcd",1包装为对象后传入,即两次输出都为"object"。
18)call/apply的第一个参数为null/undefined时,this为null/undefined
这里以call来示例
1
2
3
4
5
6
|
'use strict' function func() { console.log( this ) } func.call(undefined) // undefined func.call( null ) // null |
Firebug输出如下
依次是undefined,null。而非严格模式中则是宿主对象,浏览器里是window,node.js环境则是global。
19)bind的第一个参数为null/undefined时,this为null/undefined
bind是ES5给Function.prototype新增的一个方法,它和call/apply一样在function上直接调用。它返回一个指定了上下文和参数的函数。当它的第一个参数为null/undefined时,情形和call/apply一样,this也为null/undefined。
1
2
3
4
5
6
7
8
|
'use strict' function func() { console.log( this ) } var f1 = func.bind( null ) var f2 = func.bind(undefined) f1() // null f2() // undefined |
而在非严格模式中输出的都是window(或global)。
相关:
http://msdn.microsoft.com/library/br230269.aspx
http://java-script.limewebs.com/strictMode/test_hosted.html
http://dmitrysoshnikov.com/ecmascript/es5-chapter-2-strict-mode/
http://javascriptweblog.wordpress.com/2011/05/03/javascript-strict-mode/
仅Chrome中函数实参与形参发生关联
Chrome中也有不少 Bug ,但更新修复速度极快。下面又发现一个有趣的现象函数实参与形参发生了关联。
1
2
3
4
5
6
|
function func(x,y){ //alert(x); arguments[1] = 5; alert(y); // --> 5 } func(3); |
IE6/7/8/9,Firefox,Safari, Opera中 y 弹出为undefined,Chrome 则为5。
函数func定义了形参x,y;调用时实参为3。func内部修改了实参arguments[1],非Chrome浏览器中形参y不会与arguments[1]关联,即为undefined。Chrome则相反,修改arguments[1]同时即修改了形参y。
修改形参y,实参arguments[1]在Chrome中同样被修改,即相互关联。
1
2
3
4
5
6
|
function func(x,y){ //alert(x); y = 6; alert(arguments[1]); // --> 6 } func(3); |
2012-10-23:Chrome22测试,已不存在这个问题。重新总结如下:
1,调用时实参与定义时形参数量一致时,实参与arguments互相影响,修改其中的一个其对应的也会被修改。
2,实参与形参数量不一致时,不关联,不互相影响。