一、概述
1、什麼是嚴格模式?
除了正常模式意外,ES5(2009年釋出)還添加了一種模式,即“嚴格模式”。這種模式使javascript在更加嚴格的條件下運作。
2、為什麼使用嚴格模式?
- 消除javascript語言中一些不合理、不嚴謹之處,減少怪異現象;
- 消除代碼運作的一些不安全的地方,保證代碼運作的安全;
- 提高編譯器效率,提高運作速度;
- 為未來新版本的javascript打好基礎;
3、怎麼使用嚴格模式?
(1)針對整個腳本調用:
<script>
"use strict";
</script>
将
"use strict"
放在所有可運作代碼之前,則整個腳本将在“嚴格模式”下運作。
這個寫法不利于函數合并,更好的方法:
<script>
(function(){
"use strict";
})();
</script>
(2)針對單個函數:
function fn(){
"use strict";
}
将
"use strict";
放在函數體所有可運作代碼之前則整個函數體将在“嚴格模式”下運作。
二、嚴格模式和普通模式的差別:
1、全局變量必須顯示聲明
"use strict";
a=;
console.log(a);//ReferenceError: a is not defined
2、靜态綁定
javasript語言有一個特點,即允許動态綁定(某些屬性和方法不是在編譯時确定的,而是在運作時确定的)。
嚴格模式對動态綁定做出了一點限制。某些情況下,隻允許靜态綁定(屬性和方法到底歸屬哪個對象,在編譯階段就應該确定)。優點:有利于編譯效率的提高,也使代碼更加容易閱讀,更少出現意外。
(1)禁止使用with語句
"use strict";
var obj={
name:'lwf',
age:
}
with(obj){//SyntaxError: Strict mode code may not include a with statement
var name1=name;
var age1=age;
}
另外,由于使用with語句會導緻性能下降,同時也會給調試代碼帶來困難,是以開發過程中,不建議使用with。
(2) 建立eval作用域
正常模式下有兩種作用域,即全局作用域和函數作用域,eval的作用域取決于其處于全局作用域和函數作用域。
嚴格模式下,會增加eval作用域。eval内生成的變量隻能在eval中通路。
正常模式下:
var a=;
var b=;
eval("console.log(a)");//1
eval("var b=3;console.log(a)");//1
eval("console.log(b)");//3
嚴格模式下:
"use strict";
var a=;
var b=;
eval("console.log(a)");//1
eval("var b=3;console.log(a)");//1
eval("console.log(b)");//2
3、增強安全措施
(1)禁止this關鍵字指向全局變量
function f1(){
console.log(!this);//false,正常模式下,this指向全局變量
}
f1();
function f2(){
"use strict";
console.log(!this);//true,嚴格模式下,this指向undefined,是以!this為true
}
f2();
(2)禁止在函數内部周遊調用棧
function f3(){
console.log(f3.arguments);//{ '0': 1, '1': 2, '2': 3 }
}
f3(,,);
function f4(){
"use strict";
console.log(f4.arguments);//TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context.
}
f4(,,);
4、禁止删除變量
正常模式和嚴格模式下都禁止删除變量
正常模式:
var x=
delete x;//删除變量會直接忽略
console.log(x);//4
删除變量:
"use strict";
var y=;
delete y;//SyntaxError: Delete of an unqualified identifier in strict mode.
console.log(y);
5、顯式報錯
(1)正常模式下,對一個對象的隻讀屬性指派,不會報錯,隻會默默的失敗;
嚴格模式下,将報錯。
正常模式:
var obj3={};
Object.defineProperty(obj3,'name',{value:,writable:false});
obj3.name=;
console.log(obj3.name);//1,沒有報錯
嚴格模式:
"use strict";
var obj4={};
Object.defineProperty(obj4,'name',{value:,writable:false});
obj4.name=;//TypeError: Cannot assign to read only property 'name' of object '#<Object>'
console.log(obj4.name);
(2)正常模式下,對一個使用getter方法讀取的屬性進行指派,不會報錯,隻會默默的失敗;
嚴格模式下,會報錯
var o={
get v(){return }
}
console.log(o.v);//1
o.v=;
console.log(o.v);//1
"use strict";
var o={
get v(){return }
}
console.log(o.v);//1
o.v=;//TypeError: Cannot set property v of #<Object> which has only a getter
console.log(o.v);
(3)正常模式下,對禁止擴充的對象添加屬性,不會報錯,隻會默默失敗;
嚴格模式下,會報錯
var o={};
Object.preventExtensions(o);
o.v=;
console.log(o.v);//undefined
"use strict";
var o={};
Object.preventExtensions(o);
o.v=;//TypeError: Cannot add property v, object is not extensible
console.log(o.v);
6、重名錯誤
(1)函數不能有重名的參數
正常模式下,如果函數有重名參數,可以使用arguments[i]讀取;
嚴格模式下,會報錯。
function fn(a,a,b){
console.log(arguments[]);//1
console.log(arguments[]);//2
return a;
}
console.log(fn(,,));//2
"use strict";
function fn(a,a,b){//SyntaxError: Duplicate parameter name not allowed in this context
console.log(arguments[]);
console.log(arguments[]);
return a;
}
console.log(fn(,,));
7、禁止八進制表示法
var n=;
console.log(n);//64
"use strict";
var n=;//SyntaxError: Octal literals are not allowed in strict mode.
console.log(n);
8、arguments對象的限制
(1)不允許對arguments對象進行指派
function fn1(){
console.log(arguments++);//NaN
}
fn1(,);
"use strict";
function fn1(){
console.log(arguments++);//SyntaxError: Unexpected eval or arguments in strict mode
}
fn1(,);
"use strict";
var obj = { set p(arguments) { } }; // 文法錯誤
try { } catch (arguments) { } // 文法錯誤
function arguments() { } // 文法錯誤
var f = new Function("arguments", "'use strict'; return 17;"); // 文法錯誤
(2)arguments不在追蹤參數的變化
function fn1(a){
a=;
console.log(arguments[],a);//2,2
}
fn1();
"use strict";
function fn1(a){
a=;
console.log(arguments[],a);//1 2
}
fn1();
(3)禁止使用arguments.callee
這意味着無法在匿名函數裡面調用自身
function fn1(){
console.log(arguments.callee);//[Function:fn1]
}
fn1();
"use strict";
function fn1(){
console.log(arguments.callee);//TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
}
fn1();
9、函數聲明必須在頂層
嚴格模式下,隻允許在全局作用域或函數作用域的頂層聲明函數。不允許在非函數的代碼塊中聲明函數。
if(true){
function fn(){
console.log();
}
}
fn();
"use strict";
if(true){
function fn(){
console.log();
}
}
fn();//ReferenceError: fn is not defined
10、保留字
嚴格模式下新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield
使用這些詞作為變量名将報錯。
function fn1(){
var let=;
console.log(let);
}
fn1();//1
"use strict";
function fn1(){
var let=;//SyntaxError: Unexpected strict mode reserved word
console.log(let);
}
fn1();
此外,ECMAscript第五版本身還規定了另一些保留字(class, enum, export, extends, import, super),以及各大浏覽器自行增加的const保留字,也是不能作為變量名的。
參考:阮一峰的JavaScript嚴格模式詳解