当前位置:首页 > 网页设计 > javascript > 正文

JavaScript:打破所有规则

来自Twitter的前端工程师Angus Crol,在柏林举办的JSConf会议上,进行了题为"Break all the Rulez"的演讲,主要讲了一些我们通常认为是错误的不该使用的东西,其实是有用的.本文最下面有演讲用的slides.远在美国的JavaScript之父看了slides也说:我同意其中大部分观点(看来还是有问题?).

\

下面我把要点简单翻译一下,不做扩展解释.

with语句

为什么不去使用它?

1.意外的运行结果,可能隐式创建全局变量

2.闭包作用域解析过多消耗

3.后期编译

有人说,ES5的严格模式可以防止隐式创建全局变量(不用var),这样能减少with的一个问题.但是...

严格模式也不能使用with啊.

为什么说它是有用的?

1.构建浏览器开发者工具

?
  1. 		//Chrome?Developer?Tools ?
  2. IS._evaluateOn?= ?
  3. ??function(evalFunction,?obj,?expression)?{ ?
  4. ????IS._ensureCommandLineAPIInstalled(); ?
  5. ????expression?= ?
  6. ??????"with?(window._inspectorCommandLineAPI)?{ ?
  7. ????????with?(window)?{?"?+?expression?+?"?}?}"; ?
  8. ????return?evalFunction.call(obj,?expression); ?
  9. }?

2.模拟块级作用域

?
?
?

?

?

  1. 		//是的,还是这个老掉牙的问题 ?
  2. var?addHandlers?=?function(nodes)?{ ?
  3. ??for?(var?i?=?0;?i?
  4. ????nodes[i].onclick?= ?
  5. ??????function(e)?{alert(i);} ?
  6. ??} ?
  7. };?
  1. 		//你可以通过在外面包一个函数来解决 ?
  2. var?addHandlers?=?function(nodes)?{ ?
  3. ??for?(var?i?=?0;?i?
  4. ????nodes[i].onclick?=?function(i)?{ ?
  5. ??????return?function(e)?{alert(i);}; ?
  6. ????}(i); ?
  7. ??} ?
  8. };?
  1. 		//或者使用'with'来模拟块级作用域 ?
  2. var?addHandlers?=?function(nodes)?{ ?
  3. ??for?(var?i?=?0;?i?
  4. ????with?({i:i})?{ ?
  5. ??????nodes[i].onclick?= ?
  6. ????????function(e)?{alert(i);} ?
  7. ????} ?
  8. ??} ?
  9. };?

eval语句

为什么不去使用它?

1.代码注入

2.无法进行闭包优化

3.后期编译

为什么说它是有用的?

1. JSON.parse不可用的时候

有人在Stack Overflow上说:

“JavaScript的eval是不安全的,使用json.org上的JSON解析器来解析JSON”

还有人说:

“不要使用eval来解析JSON!用道格拉斯写的json2.js!”

可是:

?
  1. 		//?From?JSON2.jsif?(/^[],:{}s]*$/??.test(text.replace(/*regEx*/,?'@')??.replace(/*regEx*/,?']')??.replace(/*regEx*/,?'')))?{??j?=?eval('('?+?text?+?')');}?

2.浏览器的JavaScript控制台都是用eval实现的

在Webkit控制台或JSBin中执行下面的代码

?
  1. 		>(function?()?{????console.log(String(arguments.callee.caller))})()function?eval()?{????[native?code]}?

John Resig说过:

“eval和with是被轻视的,被误用的,被大部分JavaScript程序员公然谴责的,但如果能正确使用的话,可以用它们写出一些奇妙的,无法用其他功能实现的代码”

Function构造函数

为什么说它是有用的?

1.代码运行在可预见的作用域内

2.只能动态创建全局变量

3.不存在闭包优化的问题

用在了什么地方?

1. jQuery的parseJSON

?
  1. 		//?jQuery?parseJSON? ?
  2. ?
  3. //?Logic?borrowed?from?http://json.org/json2.js ?
  4. if?(rvalidchars.test(data.replace(rvalidescape,"@") ?
  5. ??.replace(?rvalidtokens,"]") ?
  6. ??.replace(?rvalidbraces,"")))?{ ?
  7. ?
  8. ??return?(?new?Function(?"return?"?+?data?)?)(); ?
  9. }?

2.Underscore.js的字符串内插

?
  1. 		//from?_.template ?
  2. ?
  3. //?If?a?variable?is?not?specified, ?
  4. //?place?data?values?in?local?scope. ?
  5. if?(!settings.variable)? ?
  6. ??source?=?'with(obj||{}){n'?+?source?+?'}n'; ?
  7. ?
  8. //.. ?
  9. ?
  10. var?render?=?new?Function( ?
  11. ??settings.variable?||?'obj',?'_',?source);?

==运算符

为什么不去使用它?

1.强制将两边的操作数转换为相同类型

为什么说它是有用的?

1.强制将两边的操作数转换为相同类型

2.undefined == null

?
  1. 		//这样写是不是很麻烦 ?
  2. if?((x?===?null)?||?(x?===?undefined)) ?
  3. ?
  4. //完全可以下面这样写 ?
  5. if?(x?==?null)??

3.当两边的操作数类型明显相同时使用

?
  1. 		typeof?thing?==?"function";???//typeof运算符肯定返回字符串 ?
  2. myArray.length?==?2;??????????//length属性肯定返回数字 ?
  3. myString.indexOf('x')?==?0;???//indeOf方法肯定返回数字?

真值不一定==true,假值不一定==false

  1. 		if?("potato")?{ ?
  2. ??"potato"?==?true;??//false ?
  3. }??
?

Array构造函数

为什么不去使用它?

1.new Array()也是evil的?JSLint也推荐使用[].

为什么说它是有用的?

  1. 		//From?prototype.js?extension?of? ?
  2. //String.prototype ?
  3. function?times(count)?{ ?
  4. ??return?count?
  5. ????''?:?new?Array(count?+?1).join(this); ?
  6. } ?
  7. 'me'.times(10);?//"memememememememememe"?
?

其他

不要扩展原生的原型对象 (es 5 shims都这么干) 在for/in遍历时总要使用hasOwnProperty (在没有扩展对象原型的前提下没有必要这么做) 把所有的var语句放在顶部 (for语句还是放在初始化表达式中好) 要在调用函数之前先声明函数 (在优先考虑实现细节时使用)? 不要使用逗号运算符 (在使用多个表达式时的时候可以使用) 使用parseInt时总要把第二个参数指定为10 (除非字符串以‘0’或‘x’开头,否则没必要)

译者注

上面说了这么多,我自己也想到一个被误解的东西,那就是escape.网上有不少人说:"不要使用escape".

为什么说它是有用的?

1.escape转义的字符更多,有时候需要转义后两个函数不转义的字符.

?

ASCII char escape() encodeURI() encodeURIComponent()
! %21 ! !
# %23 # %23
$ %24 $ %24
& %26 & %26
' %27 ' '
( %28 ( (
) %29 ) )
+ + + %2B
, %2C , %2C
/ / / %2F
: %3A : %3A
; %3B ; %3B
= %3D = %3D
? %3F ? %3F
@ @ @ %40
~ %7E ~ ~

?

2.将字符串转换为UTF8编码,通常用在base64的时候.

escape相当于是在utf16编码的字符串上转义,encodeURIComponent相当于是先把utf16的字符串转换成utf8编码后再escape.

encodeURIComponent(str) === escape(UTF16ToUTF8(str))

可以推导出UTF16ToUTF8(str) ===?unescape( encodeURIComponent(?str )

然后就能用在base64编码的时候,比网上看到的那些简单多了吧.注意btoa和atob有兼容问题.

  1. 		function?base64Encode(str)?{ ?
  2. ????return?btoa(unescape(encodeURIComponent(str))); ?
  3. } ?
  4. ?
  5. function?base64Decode(str)?{ ?
  6. ????return?decodeURIComponent(escape(atob(str))); ?
  7. }?
上一篇:JavaScript使用心得汇总:从BOM和DOM谈起 下一篇:最后一页