原文: http://pij.robinqu.me/JavaScript_Core/JavaScript_Basics/Strict_Mode.htmlphp
本文上一個版本盜用了別人的文章,經讀者指出後我就刪掉了。因爲起草的時間在去年,我也不太清楚當初是怎麼把別人的文章複製進來的。本文除了介紹所謂的Strict Mode以外,還會介紹其餘關聯內容。node
JavaScript並非一個完美的語言。事實上,第一個版本的Brendan Eich1花費十天的時間創造的,你不能對它指望太多。以後,JavaScript在瀏覽器大戰中,成爲各方角逐的主要戰場。各大廠商各顯神通,其反作用是各類奇奇怪怪的行爲和各式不一的API。在以後,W3C和其餘社區團體花費了大量的精力來經過標準化來「淨化」全部Web開發相關的技術標準。git
但尷尬的是,瀏覽器廠商並非那麼徹底的實現了W3C和ECMAScript的各類標準。最後,經驗豐富的Javascript程序員,經過約束自身對Javascript的使用方法,來達到讓Javascript更高的可擁度。可能大部分人都讀過《JavaScript語言精粹》2這本書,其講述的就是如何在JavaScript語言中,取其精華,而後去其糟粕。程序員
而JavaScript的嚴格模式,則是另外一種緊箍咒,它的約束力來自運行時自己,而不是用戶的主觀行爲。也就是說,有不少模棱兩可,或是錯誤卻被容許的操做,被完全禁止了。目前支持嚴格模式的支持範圍3從IE10起跳,其餘常青瀏覽器也都是支持的。github
開啓全局模式只需在全部語句以前放置"use strict"
字符串常量。web
全局開啓嚴格模式:瀏覽器
"use strict" var v = "Hello world";
但注意,這樣會致使整個腳本內的代碼都在嚴格模式中執行。假如以前有些代碼並無考慮嚴格模式,這可能讓你的整個應用程序忽然失效。app
咱們更爲推薦的是,在某個函數內開啓嚴格模式:ecmascript
function mySuperMethod() { "use strict"; var v = "Hello world"; } function mySuckingMethod { //not in strict mode }
你們有須要記住一堆語言特性了。可是,還好這些內容是把「歪」的掰「直」了。有少數代碼例子來自於MDC4。
ReferenceError
試圖隱式建立全局變量
``` "use strict" hello = "world"//throw ```
TypeError
試圖修改已經被定義爲不可寫的屬性
``` "use strict"; var o = {}; Object.defineProperty(o, "hello", {value:"world", wrtiable:false}); o.hello = "bad boy";//throw ```
其餘相似的還有:
試圖刪除不可刪除的屬性
``` "use strict"; delete Object.prototype; //throw ```
arguments.callee
不能被返回、刪除、修改;
``` "use strict"; var fun = function() { return arugments.callee;//throw }; ```
SyntaxError
重複定義屬性名
``` "use strict"; var o = {hello: 1, hello: 2};//throw ```
禁用八進制字面量
``` "use strict"; var hello = 015;//throw ```
不容許重複參數名
``` function myMethod(a, b, b) {//throw "use strict"; } ```
不能使用with
``` "use strict"; var obj = {}; with (obj) {};//throw ```
不容許對eval
或arguments
賦值
``` var fun = function(){ "use strict"; eval=16 }(); ```
不可將eval
或arguments
做爲參數名、變量名
``` var fun = function(){ "use strict"; var obj = { set p(arguments) {} }; }(); ```
eval
被限制在臨時的本地做用域eval再也不有權限直接修改其所在做用於,而只能影響自身建立的做用域。
var hello = "world"; var evalHello = eval("'use strict'; var hello = "girl"; hello"); // hello === "world" // evalHello === "girl"
arguments
再也不追蹤實際參數值變化function f(hello) { "use strict"; hello = "girl"; return [hello, arguments[0]]; } var pair = f("world"); // pair[0] === "girl" // pair[1] === "world";
this
不作任何修改null
或undefined
,引擎也不會從新指定全局對象做爲this
"use strict"; function fun() { return this; } // fun() === undefined // fun.call(2) === 2 // fun.apply(null) === null // fun.call(undefined) === undefined // fun.bind(true)() === true
以往,咱們能夠經過函數的caller
和arguments
來投影整個調用堆棧。可是,在嚴格模式中咱們作不到。
function restricted() { "use strict"; restricted.caller; // throws a TypeError restricted.arguments; // throws a TypeError }
implements, interface, let, package, private, protected, public, static, yield
不少開發者喜歡以下代碼風格,這在嚴格模式中會報錯。
function foo() { "use strict"; return g; function g() { }//throw SyntaxError }
這個改變的緣由是,JavaScript的Hoisting
特性會讓不少人迷惑:
function g() { } function foo() { if (true) function g() { } return g; }
ES6 Draft中引入了一個新的概念5,叫Extend Mode
,而後又被撤銷了6。但不幸的是,V8中已經支持了這個新模式。因此,做爲事實標準,目前依賴V8的全部Javascript運行環境都有以下三個模式:
這個模式是備受爭議的。這個模式的產生,也體會出製做一個標準的困難之處——你總要考慮新標準對老標準的兼容,尤爲是Web技術。
有稍微瞭解ES6的同窗都應該清楚,module
、class
這些東西已經徹底顛覆了傳統JavaScript的不少嘗試。但也有很多東西,開發者是能夠接受,並立馬去嘗試的。因而乎,關於如何讓代碼部分進入extended mode
也就成了最初討論的重點7。
實際表現上,node的0.11.x的版本,有些特性,僅僅使用--harmony
並不能徹底使用,還需加上--use_strict
。在這裏,已經能夠看出V8團隊有多糾結了8。他們也沒有想清楚,該如何進入extended mode
,索性,也叫strict
吧。
目前僅在extended mode
下可用的ES6特性:
關於ES6的特性,請參考本書的相關章節。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Strict_mode ↩
http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts ↩
http://wiki.ecmascript.org/lib/exe/fetch.php?id=harmony%3Aspecification_drafts&cache=cache&media=harmony:working_draft_ecma-262_edition_6_11-7-11.pdf ↩
https://lists.webkit.org/pipermail/webkit-dev/2011-December/018903.html ↩