1. 程式人生 > >JavaScript嚴格模式

JavaScript嚴格模式

直接 詳解 提前 java ted 開發 name call def

介紹

ECMAscript 5添加了“嚴格模式”,會使得Javascript在更嚴格的條件下運行,設立"嚴格模式"的目的,主要有以下幾個:

  • 消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為;
  • 消除代碼運行的一些不安全之處,保證代碼運行的安全;
  • 提高編譯器效率,增加運行速度;
  • 為未來新版本的Javascript做好鋪墊。

說明
此文參考了阮一峰的Javascript 嚴格模式詳解,做個總結筆記。對於原文中的例子我都一一測試了,但有個別測試結果是不一樣的,後面已做說明。那些我也是比較迷惑的,如果有錯誤,希望指出。

開始

啟用嚴格模式很簡單,只需要一個字符串

"use strict";

但是這個字符串的位置不是隨意放的,有兩種:

  • 全局嚴格模式,放在腳本文件的第一行
  • 局部嚴格模式,放在函數內第一行(推薦)

為什麽推薦使用在函數內的嚴格模式呢?

因為全局嚴格模式不利於代碼的合並,團隊多人開發時,合並代碼可能會使別人某些代碼失效。

所以更好的做法是,借用局部嚴格模式方法,將整個腳本文件放在一個立即執行的匿名函數之中:

(function (){

  "use strict";
  // some code here

})();

思考

為什麽是一個字符串啟用嚴格模式?是為了兼容老舊的瀏覽器,一行字符串不會對不兼容嚴格模式的瀏覽器產生影響。

改變

嚴格模式帶來了很多語法的改變。

變量賦值前必須聲明

通常我們可以直接對一個變量賦值而不需要提前var聲明,此時這個變量就是全局變量。嚴格模式禁止這種用法,全局變量必須顯式聲明。

"use strict"

a = 2;   //報錯

因此,嚴格模式下,變量都必須先用var命令聲明,然後再使用。

禁止使用with

正常模式下,我們可以使用with來改變作用域鏈,如:

var obj = {
   num:1
}
function test(){
   var num = 2;
   with(obj){
    console.log(num);
   }
}
test();  //1

但是在嚴格模式下,禁用了with,報錯:

"use strict";

test();
//Strict mode code may not include a with statement

創建eval作用域

正常模式下,Javascript語言有兩種變量作用域(scope):全局作用域和函數作用域。嚴格模式創設了第三種作用域:eval作用域。

正常模式下,eval語句的作用域,取決於它處於全局作用域,還是處於函數作用域。嚴格模式下,eval語句本身就是一個作用域,不再能夠生成全局變量了,它所生成的變量只能用於eval內部。

"use strict";

var x = 5;

console.log(eval(‘var x = 10;console.log(x)‘)); //10

console.log(x);  //5

局部this必須賦值

正常模式下,函數編譯時,內部this指向的是全局window對象,但是嚴格模式時,this不再指向window,而是undefined。你需要自己手動賦值,賦值是什麽,this就是什麽。

"use strict";

console.log(‘window: ‘,this);  //window

function test(){
    console.log(‘test: ‘,this);  //undefined
}

test();

因此,使用構造函數時,如果忘了加new,this不再指向全局對象,而是報錯。

function fn(){
  "use strict";
  this.a = 1;
};
fn(); // 報錯

arguments對象的限制

arguments是函數的參數對象,嚴格模式對它的使用做了限制。

不允許對arguments賦值

"use strict";

var arguments = 5;  //報錯

function arguments(){   //報錯
    //some code
}

arguments不再追蹤參數的變化

//正常模式
function test(a){
    a = 5;
    console.log([a,arguments[0]])
}

test(2);  //[5,5]



//嚴格模式

"use strict";

function test(a){
    a = 5;
    console.log([a,arguments[0]])
}

test(2);  //[5,2]

禁止使用arguments.callee

arguments.callee可以返回正被執行的函數對象

//正常模式
function test(){
    console.log(arguments.callee);
}

test();
// test(){
//    console.log(arguments.callee);
//}

嚴格模式不允許再使用arguments.callee

禁止使用caller

正常模式下,可以使用caller返回一個函數對象,這個函數調用了當前函數:

function test(){
    demo();
}

function demo(){
    console.log(demo.caller);
}

test();  
// test(){
//    demo();
//}

嚴格模式禁止再使用caller。所以兩個長得很像的callee和caller在嚴格模式下都不能再使用。

函數必須聲明在頂層

什麽意思呢?

我們都只到es6引入了塊級作用域,為了與新版本接軌,嚴格模式只允許在全局作用域或函數作用域的頂層聲明函數。也就是說,不允許在非函數的代碼塊內聲明函數。

//正常模式

if(true){
    function fn(){
        console.log(‘fn‘);
    }

    fn();   // fn
}

fn();   // fn
"use strict";

if(true){
    function fn(){
        console.log(‘fn‘);
    }

    fn();   // fn
}

fn();  // 報錯  fn is not defined

重名錯誤

對象不能有重名屬性

按照 阮一峰的文章,在嚴格模式下,對象是不準有重名屬性的,會報錯。但實際測試中(谷歌瀏覽器),嚴格模式下,對象屬性重名並不會報錯,而是像正常模式一樣,後面的覆蓋前面的。

"use strict";

var obj = {
   a:1,
   a:2
}

console.log(obj.a);  //2

後來了解到,ES6中的嚴格模式已經允許對象有重名的屬性。如果有了解的,可以告訴我下。

函數不能有重名的參數

正常模式下,參數重名,後面的覆蓋前面的:

function test(a,a,b){
    console.log(a,a,b);
}

test(1,2,3); // 2 2 3

但在嚴格模式下,會報錯:

"use strict";

function test(a,a,b){
    console.log(a,a,b);
}

test(1,2,3);
// 報錯 Duplicate parameter name not allowed in this context

禁止刪除變量

按照 阮一峰的文章,嚴格模式下無法刪除變量。只有configurable設置為true的對象屬性,才能被刪除。

但是即使在正常模式下,用var聲明的變量也是無法刪除的,不管是全局聲明還是局部聲明,不過可以刪除對象屬性:

var obj = {
    a:2
}

delete obj.a;   //true

obj //{}

在嚴格模式下,用var聲明的變量也是無法刪除的,但對象的屬性也是可以刪除的:

"use strict";

var obj = {
    a:2
}

delete obj.a;   //true

obj //{}

需要註意的是,在正常模式下,即使變量不可以刪除,你也可以寫入 delete,不會報錯,但是嚴格模式下,刪除不了的變量不可以用delete

"use strict";

var a = 2;

var obj = {
    b:3
}

delete a;  //報錯,不可刪除就不能使用delete

禁止八進制表示法

正常模式下,整數的第一位如果是0,表示這是八進制數,比如0100等於十進制的64。嚴格模式禁止這種表示法,整數第一位為0,將報錯。

"use strict";
var num = 0100;
console.log(num);  // 報錯

但是es6提供了一種八進制數的新表示法,就是在數值前加上0o(第一個是數字0,第二個是字母o)

"use strict";
var num = 0o100;
console.log(num);

保留字

為了向將來Javascript的新版本過渡,嚴格模式新增了一些保留字:implements, interface, let, package, private, protected, public, static, yield。

使用這些詞作為變量名將會報錯。

"use strict";

var let;  //報錯

說到保留字let,我們知道es6已經加入了letconstconst不管是在正常模式還是嚴格模式下都不可作為變量名。因為各大瀏覽器自行增加的const保留字,所以不能作為變量名的。

JavaScript嚴格模式