{JS} Javascript 打破所有规则Wed Oct 18 2017

来自Twitter的前端工程师Angus Croll,在柏林举办的2012JSConf会议上,进行了题为”Break all the Rulez“的演讲。主要讲了一些我们通常认为是错误的不该使用的东西,其实是有用的。远在美国的JavaScript之父看后也说同意其中大部分观点(看来还是有问题?)其中包括许多书籍中指出是不该使用的语法, 如 with , eval , Function , Array 等原生构造函数

BrendanEich Twitter

with 语句

为什么不使用它
  • 意外等运行结果,可能隐式的创建全局变量
  • 闭包内解析过多的消耗
  • 后期编译

ES5 严格模式限制了变量声明,防止隐式创建全局变量,也不允许使用with, 为什么说它有用?

浏览器构建工具
//Chrome Developer Tools
IS._evaluateOn =
  function(evalFunction, obj, expression) {
    IS._ensureCommandLineAPIInstalled();
    expression =
      "with (window._inspectorCommandLineAPI) {\
        with (window) { " + expression + " } }";
    return evalFunction.call(obj, expression);
}
块级作用域的问题
//是的,还是这个老掉牙的问题
var addHandlers = function(nodes) {
  for (var i = 0; i < nodes.length; i++) {
    nodes[i].onclick =
      function(e) {alert(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 语句

为什么不使用它?
  • 代码注入
  • 无法进行闭包优化
  • 后期编译

有人说使用eval不安全, 严格模式下无法直接使用eval (可以间接引用), 但是?

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

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

>(function () {
    console.log(String(arguments.callee.caller))
})()

function eval() {
    [native code]
}

灵活使用 with 和 eval

我们知道,严格模式中,闭包中this不会指向全局Window对象(当然可以使用call. apply. bind来改变this指向),但是有时候我们需要直接获取.

在doT 中我们可以看到如下代码:

// 巧妙的在严格模式下解析全局this
var root = (function(){ return this || (0,eval)("this"); }());

我们还可以使用eval创建动态指定参数名的函数

var args = [...someargsname];
var fn = (0,eval)("(function("+
    args.toString() + "){"+
 " //dosomething })");

当然 with 和 eval 还有许多应用,比如Javascript模板引擎, JSON pollyfill 解析, 解析代码块等等. 当然我自己的框架 Ax 和 Struct 也使用了 eval 和 with, 我认为这两个函数还有许多可以探索的东西,并不是书本上告诉我们的不去使用它们.


jQuery 的作者 John Resig说过:

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