天天看點

Javascript嚴格模式詳解

一、概述

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嚴格模式詳解

繼續閱讀