• [译]JavaScript:打破所有规则


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

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

    with语句

    为什么不去使用它?

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

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

    3.后期编译

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

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

    为什么说它是有用的?

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

    //Chrome Developer Tools
    IS._evaluateOn =
      function(evalFunction, obj, expression) {
        IS._ensureCommandLineAPIInstalled();
        expression =
          "with (window._inspectorCommandLineAPI) {\
            with (window) { " + expression + " } }";
        return evalFunction.call(obj, expression);
    }

    2.模拟块级作用域

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

    eval语句

    为什么不去使用它?

    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))
    })()

    function eval() {
    [native code]
    }

    John Resig说过:

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

    Function构造函数

    为什么说它是有用的?

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

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

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

    用在了什么地方?

    1. jQuery的parseJSON

    // jQuery parseJSON 
    
    // Logic borrowed from http://json.org/json2.js
    if (rvalidchars.test(data.replace(rvalidescape,"@")
      .replace( rvalidtokens,"]")
      .replace( rvalidbraces,""))) {
    
      return ( new Function( "return " + data ) )();
    }

    2.Underscore.js的字符串内插

    //from _.template
    
    // If a variable is not specified,
    // place data values in local scope.
    if (!settings.variable) 
      source = 'with(obj||{}){\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;          //length属性肯定返回数字
    myString.indexOf('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 < 1 ?
        '' : new Array(count + 1).join(this);
    }
    'me'.times(10); //"memememememememememe"

    其他

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

    译者注

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

    为什么说它是有用的?

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

    ASCII charescape()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有兼容问题.

    function base64Encode(str) {
        return btoa(unescape(encodeURIComponent(str)));
    }
    
    function base64Decode(str) {
        return decodeURIComponent(escape(atob(str)));
    }

  • 相关阅读:
    上传按钮样式优化 <input type="file" />
    javascript多重继承
    javascript prototype和__proto__
    Android开发之通过Intent启动其他App的Service
    Android开发之bindService()侦听service内部状态
    Android 开发之 bindService() 通信
    Android开发之异步消息处理机制AsyncTask
    Android开发之异步消息处理机制Handler
    Android开发UI之在子线程中更新UI
    Android开发之在子线程中使用Toast
  • 原文地址:https://www.cnblogs.com/ziyunfei/p/2713505.html
Copyright © 2020-2023  润新知