代碼中經(jīng)吃迦看到使用這樣的聲明,卻一直不知道有什么作用济瓢,直到有一天荠割。。旺矾。
1. 歷史
ES5開始使用Directive Prolog蔑鹦,并據(jù)說直到現(xiàn)在也只有'use strict'
一個實現(xiàn),至于引入Strict Mode的原因箕宙,總的來還是對JS兼容性對處理嚎朽。
第一,為了處理未來即將廢棄或修改的JS方法柬帕,告訴大家別這樣用了(直接拋出異常了)哟忍。
第二狡门,為了未來兼容的JS實現(xiàn),告訴大家以后的JS這樣做是這個效果锅很。
也就是為了JS更好的發(fā)展其馏,作出的一些JS內(nèi)容上的約束。
2. 聲明位置
作為一個Directive Prolog爆安,只需要使用'use strict'
這樣的語法尝偎,就可以聲明為Strict Mode,主要影響范圍會有兩個:
2.1 全局使用
也就是全局都聲明為Strict Mode了鹏控,一般不推薦致扯,因為會對所有的Script引用腳本造成影響,破壞力不可言喻当辐,所以盡量不要這樣使用抖僵。
2.2 方法中使用
這是推薦的方法,只對局部代碼作用缘揪,這樣也不會對其他內(nèi)容產(chǎn)生影響耍群,于是就這樣在方法內(nèi)使用吧。
function f(){
'use strict'
// 大括號內(nèi)都有效了找筝,不影響括號外內(nèi)容
}
x = 1;
f()
當(dāng)然這樣也是可以的
(function(){
'use strict'
})()
3. 使用影響
3.1 對變量的影響
3.1.1 變量聲明
使用不聲明的變量蹈垢,會拋出異常,防止莫名其妙的引入全局變量
'use strict'
x = 1 // 愉快的拋出了異常 Uncaught ReferenceError: x is not defined
3.1.2 變量命名
使用關(guān)鍵字/保留字作為變量名袖裕,拋出異常曹抬,常用的關(guān)鍵字:private
, package
,protected
, interface
, implements
,let
, static
, yield
,當(dāng)然不僅僅局限于這些急鳄,可以自行嘗試
function f(){
'use strict'
var private = 1 // 很友善的異常信息 Uncaught SyntaxError: Unexpected strict mode reserved word
}
f()
3.1.3 變量賦值
只讀/只有get
方法/不可擴展對象屬性賦值谤民,都沒辦法正常賦值,都會拋出異常
function f(){
'use strict'
// 只讀屬性
var obj = {};
Object.defineProperty(obj, 'x', {value:1 , writable: false, configurable: true});
obj.x = 2; // Uncaught TypeError: Cannot assign to read only property 'x' of object '#<Object>'
// 只有g(shù)et方法
var obj = {
get x() {
return 1;
}
}
obj.x = 2; // Uncaught TypeError: Cannot set property x of #<Object> which has only a getter
// 不可擴展對象
var obj = {};
Object.preventExtensions(obj);
obj.x = 2; // Uncaught TypeError: Cannot add property x, object is not extensible
}
f()
3.1.4 方法中形參命名
不能使用相同的形參疾宏,想起來也合理张足,如果兩個參數(shù)名一樣,誰知道指代的哪一個
(function(){
'use strict'
function f(a, a){} // Uncaught SyntaxError: Duplicate parameter name not allowed in this context
})()
3.1.5 八進制
阻止使用以0
開始的八進制表達方式坎藐,可以使用0o
的方式來定義八進制數(shù)據(jù)为牍。當(dāng)然避免010
這樣的數(shù)據(jù)產(chǎn)生莫名其妙的結(jié)果了(根本不會想到非Strict Mode下 010 === 8
)
function f() {
'use strict'
var x = 010; // Uncaught SyntaxError: Octal literals are not allowed in strict mode.
var x = 0o10 // 可以這樣用,x === 8
}
3.1.6 禁止給基本類型擴展屬性
我想正常的我們都不會給一個布爾值岩馍,字符串碉咆,數(shù)字增加屬性吧
function f() {
'use strict'
false.x = 1; // Uncaught TypeError: Cannot create property 'x' on boolean 'false'
'str'.x = 1; // Uncaught TypeError: Cannot create property 'x' on string 'str'
}
f()
3.1.7 (超特殊) 對象屬性
對象中含有兩個相同的屬性名,根據(jù)官方文檔時說要報錯的兼雄,結(jié)果似乎被定義為bug了吟逝,目前并不會報錯,只會覆蓋了
function f() {
'use strict'
var obj = {x: 1, x: 2} // 據(jù)說會報錯赦肋,結(jié)果現(xiàn)在只是后定義的回覆蓋前面的值
console.log(obj.x);
}
f();
3.2 function和arguments
3.2.1 Function中this指代
這里其實涉及到另一個知識點this
的指代块攒,Javascript中this
指代會有一點麻煩励稳,不過這里如果在函數(shù)通常調(diào)用情況下,非Strict Mode返回是window
對象囱井,而Strict Mode定義為undefined
(原因其實就是方法調(diào)用的時候沒有指向任何對象)
function f() {
'use strict'
return this; // undefined
}
f();
window.f(); // 可以自行嘗試驹尼,有很有意思的結(jié)果
3.2.2 callee, caller, function.arguments
在Strict Mode下使用function.caller
,function.arguments
庞呕,arguments.callee
新翎,arguments.caller
,都會拋出異常住练,我想這么做是為了避免無緣無故就引入了循環(huán)引用導(dǎo)致堆棧溢出地啰。
3.2.3 arguments使用
對于非箭頭函數(shù),方法中可以使用arguments
來獲取傳遞參數(shù)讲逛,嚴(yán)格模式下對參數(shù)不會改變aguments對于值的獲取的值亏吝。
(function(){
'use strict'
function f(a){
a = 2;
console.log(arguments[0]); // arguments[0] === 1
}
f(1);
})()
3.2.4 (特例)邏輯語句中定義方法
官方似乎是會產(chǎn)生異常的,但是邏輯語句中是不能定義方法的盏混,但是自己嘗試了蔚鸥,似乎都是可以的,也許新版本定義這是可行的许赃?
3.3. eval函數(shù)
3.2.1 作為變量名止喷,方法名,自增數(shù)
和關(guān)鍵字一樣混聊,不能用做以上內(nèi)容弹谁,否則會拋出異常
3.2.2 對全局變量的影響
Strict Mode下不會對全局變量產(chǎn)生影響,聲明的變量只在eval
自身的作用域范圍內(nèi)有效
'use strict'
var a = 1;
eval('var a = 2'); // 注意 eval('a = 2')是可以對a產(chǎn)生影響的
console.log(a); // a === 1;
3.2.3 直接使用和間接使用的區(qū)別
對于間接使用的時候技羔,不受到Strict Mode的限制
'use strict'
eval('var x = 1');
console.log(x); // undefined
// 間接調(diào)用1
('indirect', eval)('var y = 2;'); // indirect
console.log(y); // 2
// 間接調(diào)用2
var ieval = eval;
ieval('var z = 3');
console.log(z);
3.2.4 this.eval和eval的區(qū)別
this
又一次立功僵闯,這時候也是可以對全局變量產(chǎn)生影響的
'use strict'
var a = 1;
this.eval('var a = 2');
console.log(a); // a === 2;
3.4. with函數(shù)
Strict Mode下使用with
函數(shù)會直接拋出異常
(function(){
// Uncaught SyntaxError: Strict mode code may not include a with statement
'use strict'
var obj = {x: 1};
with(obj){
console.log(x);
}
})()
3.5 delete
3.5.1 刪除對象屬性
當(dāng)對象屬性設(shè)置為configurable: false
的時候,如果刪除對象屬性會拋出異常藤滥,當(dāng)然非Strict Mode也不能刪掉,只是不會拋出異常
(function(){
'use strict'
var obj = {};
Object.defineProperty(obj, 'x', {value: 1, configurable: false});
delete obj.x; // Uncaught TypeError: Cannot delete property 'x' of #<Object>
})()
3.5.2 刪除變量
變量是不能直接刪除的社裆,會拋出異常拙绊,同樣非Strict Mode下雖然不會拋出異常,但是實際上不能刪除的
(function(){
// Uncaught SyntaxError: Delete of an unqualified identifier in strict mode.
'use strict'
var a = 1;
delete a;
})()
3.5.3 刪除this指代的全局變量
這是可以的泳秀,因為this
又一次立功标沪,變成了刪除某個對象的值,所以是可以的
(function(){
'use strict'
delete this.a;
console.log(this);
}).call({a: 1 , b: 2})
4.參考
所有以上內(nèi)容都來自MDN嗜傅,只是對結(jié)構(gòu)按照自己理解做了一下調(diào)整和整合:
MDN strict mode
ECMA-262-5 in detail. Chapter 2. Strict Mode.
MDN Function caller
MDN arguments caller(已淘汰)
MDN arguments callee
5. 練習(xí)
最后來一個練習(xí)吧金句,猜猜結(jié)果:
(function(){
'use strict'
var a = b = 1;
console.log(a);
console.log(b);
})()