rou 2014-10-08
严格模式(Strict mode)是由ECMA-262规范定义的新兴JavaScript标准,第五版发布于2009年12月。旨在改善错误检查功能并且标识可能不会延续到未来JavaScript版本的脚本。ES5严格模式是限制性更强的JavaScript变体,它与常规JavaScript的语义不同,其分析更为严格。
目前,除了IE6-9,其它浏览器均已支持ES5严格模式。
严格模式的使用很简单,只有在代码首部加入字符串 "use strict"。有两种应用场景,一种是全局模式,一种是局部模式。
'use strict' var globalVal = 100 console.log(globalVal)
执行后输出了100,与非严格模式没什么区别。
将"use strict"放到函数内的第一行,如下
function func() {
'use strict'
var localVal = 200
console.log(localVal)
}
func()执行后输出了200,与非严格模式也没用什么区别。
如果你想定义一个模块或者一个小库,自然采用一个匿名函数自执行是不错的选择
~function() {
"use strict";
// Define your library strictly...
}();“use strict” 的位置是很讲究的,必须在首部。首部指其前面没有任何有效js代码。以下都是无效的,将不会触发严格模式。
a)“use strict” 前有代码
var width = 10 'use strict' globalVar = 100
b)“use strict” 前有个空语句都不行
; 'use strict' globalVar = 100
或
function func() {
;
'use strict'
localVar = 200
}或
function func() {
;'use strict'
localVar = 200
}当然,“use strict”前加注释是可以的
// strict mode 'use strict' globalVar = 100
或
function func() {
// strict mode
'use strict'
localVar = 200
}
func()上面举的两个例子,在严格模式中输出与普通模式没用什么区别。下面就不一样了。
我们知道JS是弱类型,宽松的语言。不使用var声明的变量默认转为全局变量。但在严格模式中将不允许,会报语法错误。
'use strict' globalVal = 100
执行,Firebug提示如下

又如全局的for循环
'use strict'
for (i=0; i<5; i++) {
console.log(i)
}这种写法在非严格模式中很危险,i 会不小心溢出成为全局变量。但在严格模式中会报错

局部模式
function func() {
'use strict'
localVal = 200
console.log(localVal)
}
func()执行,Firebug报错

因此,严格模式中声明变量务必记得加一个var。
'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报错

JS中作用域有两种,全局作用域和函数作用域。严格模式带来了第三种作用域:eval作用域,如下
'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的差别。
'use strict'
with({a:1}) {
}Firebug报错

function func() {
'use strict'
arguments.callee
arguments.caller
}
func()Firebug报错

'use strict'
var obj = {}
Object.preventExtensions(obj)
obj.a = 1 // 报错Firebug报错
'use strict' delete Object.prototype // 报错 delete Function.prototype // 报错
Firebug报错

'use strict'
var obj = {a:1}
window.a = 1
delete obj // 报错
delete a // 报错Firebug报错如下

'use strict'
var obj = {a: 1}
Object.seal(obj)
delete obj.aFirebug报错如下

'use strict'
var obj = {}
Object.defineProperty(obj, 'a', {value: 1, writable: false})
obj.a = 2 // 报错Firebug报错如下

'use strict'
var obj = {
a: 1,
a: 2
}Firebug报错如下

而在非严格模式中,后面的属性将覆盖前面的属性,即obj.a等于2。
'use strict'
function func(a, a) {
alert(a)
}
func()Firebug报错

而在非严格模式中,后面的同名参数将覆盖前面的。
'use strict' var num = 022
Firebug报错如下

先看非严格模式代码
function func(a) {
arguments[0] = 2
alert(a) // 2
}
func(1)func调用时传参为1,函数内部通过arguments修改为2,此时alert的为修改后的2。 而在严格模式中则不能被修改,如下
'use strict'
function func(a) {
arguments[0] = 2
alert(a) // 1
}
func(1)显示的严格的为传入的1。
其实有点还有点复杂,如果alert的是arguments[0],实际在严格模式中仍然被修改为2了。如下
'use strict'
function func(a) {
arguments[0] = 2
alert(arguments[0]) // 2
}
func(1)可以参考下 仅Chrome中函数实参与形参发生关联
我们知道函数声明和函数表达式是两个不同的概念。一般函数声明都在最顶层,ES5前的JS宽松,你可以写在if或for内(强烈鄙视这种写法)。当然Firefox的解析方式与其他浏览器不同,见SJ9002。而在严格模式中这些写法将直接报错
'use strict'
if (true) {
function func1() { } // 语法错误
}
for (var i = 0; i < 5; i++) {
function func2() { } // 语法错误
}Firebug报错

'use strict' var let = 10 var yield = 20
Firebug报错

'use strict'
function func() {
console.log(typeof this)
}
func.call('abcd') // string
func.apply(1) // numberFirebug输出如下

依次为"string","number"。而在非严格模式中call/apply将对值类型的"abcd",1包装为对象后传入,即两次输出都为"object"。
这里以call来示例
'use strict'
function func() {
console.log(this)
}
func.call(undefined) // undefined
func.call(null) // nullFirebug输出了undefined和null,而非严格模式中则是宿主对象,浏览器里是window,node.js环境则是global。
bind是ES5给Function.prototype新增的一个方法,它和call/apply一样在function上直接调用。它返回一个指定了上下文和参数的函数。当它的第一个参数为null/undefined时,情形和call/apply一样,this也为null/undefined。
'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/