來自Twitter的前端工程師Angus Croll,在柏林舉辦的JSConf會議上,進行了題為”Break all the Rulez“的演講。主要講了一些我們通常認為是錯誤的不該使用的東西,其實是有用的。 Angus Croll 演講用的講稿(連結),遠在美國的JavaScript之父看後也說同意其中大部分觀點(看來還是有問題?)。
下面我把要點簡單翻譯一下,不做擴展解釋.
with語句
為什麼不去使用它?
1.意外的運行結果,可能隱式創建全局變數
2.閉包作用域解析過多消耗
3.後期編譯
有人說,ES5的嚴格模式可以防止隱式創建全域變數(不用var),這樣能減少with的一個問題.但是…
嚴格模式也不能使用with啊.
為什麼說它是有用的?
1.構建瀏覽器開發者工具
// Chrome Developer Tools
IS._evaluateOn =
function(evalFunction, obj, expression) {
IS._ensureCommandLineAPIInstalled(); with (window) { " + expression + " } } ";
return evalFunction.call(obj, expression);
}
2.模擬塊級作用域
//是的,還是這個老掉牙的問題 (var addHandlers = function(nodes) for
0; i nodes[i].onclick =
function(e) {alert(i);}
}
};
var addHandlers = function(nodes) {
for (var i = 0; i nodes[i].onclick = function(i) {
};
}(i);
}
};
//或使用'with'來模擬區塊級作用域
var addHandlers = function(nodes) {
for (var i = 0. ; i++) {
with ({i:i}) {
nodes[i].onclick =
function(e) {alert(i);}語句🎠 ?
1.程式碼注入
2.無法進行閉包最佳化
3.後期編譯
為什麼說它是有用的?
1. JSON.parse不可用的時候
有人在Stack Overflow上說:
「JavaScript的eval是不安全的,使用json.org上的JSON解析器來解析JSON”
還有人說:
“不要使用eval來解析JSON!用道格拉斯寫的json2.js!”
可是:
// From JSON2 .js
if (/^[],:{}s]*$/
.test(text.replace(/*regEx*/, '@')
.replace(/*regEx*/, ']' )
.replace(/*regEx*/, ''))) {
j = eval('(' + text + ')');
}
2.瀏覽器的JavaScript控制台都是用eval實現的
在Webkit控制台或JSBin中執行下面的程式碼
>(function () {
console.log(String(arguments.callee.caller))
})()
ative ]
}
John Resig說過:
「eval和with是被輕視的,被誤用的,被大部分JavaScript程式設計師公然譴責的,但如果能正確使用的話,可以用它們寫出一些奇妙的,無法用其他功能實現的程式碼」
Function建構子
為什麼說它是有用的?
1.程式碼運行在可預見的作用域內
2.只能動態建立全域變數
3.不存在閉包最佳化的問題
用在什麼地方?
1. jQuery的parseJSON
// jQuery parseJSON
// Logic borrowed from http://json.org/json2.jso.testif (rdataidplaces.testif(rdata.charot( "@")
.replace( rvalidtokens,"]")
.replace( rvalidbraces,""))) {
return ( new Function( "return " + data ) )();
return ( new Function( "return " + data ) )(); js的字串內插
//from _.template
// If a variable is not specified,
// place data values in local scope.
if (!sperings.variable)_obings. ||{}){n' + source + '}n';
//..
var render = new Function(
settings.variable || 'obj', '_', source);
==運算子
為什麼不去使用它?
1.強制將兩邊的操作數轉換為相同類型
為什麼說它是有用的?
1.強制將兩邊的操作數轉換為相同類型
2.undefined == null
//這樣寫是不是很麻煩
if ((x === null) || (x === undefined))
//完全可以下面這樣寫
if (x == null)
3.當兩邊的操作數類型明顯相同時使用
typeof thing == "function"; //typeof運算子肯定回傳字串
myArray.length == 2; x') == 0; //indeOf方法肯定回傳數字
真值不一定==true,假值不一定==false
if ("potato") {
"potato" == true; //false
}
Array建構子
為什麼不使用它?
1.new Array()也是evil的?JSLint也推薦使用[].
為什麼說它是有用的?
//From prototype.js extension of
//String.prototype
function times(count) {
return count '' : new Array(count + 1).join(this);
}
'me'.times(10); //"mememememememememe}
'me'.times(10); //"mememememememememeemeeme"
原生的原型物件
(es 5 shims都這樣乾)
在for/in遍歷時總要使用hasOwnProperty
(在沒有擴展對象原型的前提下沒有必要這麼做)
把所有的var語句放在頂部
( for語句還是放在初始化表達式中好)
要在呼叫函數之前先宣告函數
(在優先考慮實作細節時使用)
不要使用逗號運算子
(在使用多個表達式時的時候可以使用)
使用parseInt時總是要把第二個參數指定為10
(除非字串以'0'或'x'開頭,否則沒必要)
譯者註
上面說了這麼多,我自己也想到一個被誤解的東西,那就是escape.網上有不少人說:“不要使用escape”.
為什麼說它是有用的?
1.escape轉義的字符更多,有時候需要轉義後兩個函數不轉義的字元.
ASCII char escape() encodeURI() encodeURIComponent()
! %21 ! !
# %23 # '
( %28 ( (
) %29 ) )
+ + + %2B
, %2C , %2C
/ / / %2F3%F%2C
= %3D = %3D
? %3F ? %3F
@ @ @ %40
~ %7E ~ ~
2.將字串轉換為UTF8編碼,通常用在base64的時候.
escape轉義,encodeURIComponent相當於是先把utf16的字串轉換成utf8編碼後再escape.
encodeURIComponent(str) === escape(UTF16ToUTF8(str))
可以推導出UTF16ToUTF8(str) === RIscape(str. str )
接著就能用在base64編碼的時候,比網上看到的那些簡單多了吧.注意btoa和atob有兼容問題.
function base64Encode(str) {
return btoa(strscape(encodeURIon(strscape(encodeU) ));
}
function base64Decode(str) {
return decodeURIComponent(escape(atob(str)));
}