博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码
阅读量:4650 次
发布时间:2019-06-09

本文共 1647 字,大约阅读时间需要 5 分钟。

函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行。这使得富有表现力的高阶函数抽象如map和forEach成为可能。它也是js异步I/O方法的核心。与此同时,也可以将代码表示为字符串的形式传递给eval函数以达到同样的功能。

程序员面临一个选择:应该将代码表示为函数还是字符串?
毫无疑问,应该将代码表示为函数。字符串表示代码不够灵活的一个重要原因是:它们不是闭包。

闭包回顾

看下面这个图

js的函数值包含了比调用它们时执行所需要的代码还要多的信息。而且js函数值还在内部存储它们可能会引用的定义在其封闭作用域的变量。那些在其所涵盖的作用域内跟踪变量的函数被称为闭包。

详细的信息到之前《》查看

字符串封装代码

假设有一个简单的多次重复用户提供的动作的函数。

function repeat(n,action){   for(var i=0;i

该函数在全局作用域会不作得很好,因为eval函数会将出现的字符串中的所有变量引用作为全局变量来解释。例如,一个测试函数基准执行速度的脚本可能恰好使用全局的start和end变量来存储时间。

var start=[],end=[],timings=[];repeat(1000,"start.push(Date.now());f();end.push(Date.now())");for(var i=0,n=start.length;i

但脚本很脆弱。如果我们简单地将代码移动到一个函数中,那么start和end变量将不再是全局变量。

function benchmark(){    var start=[],end=[],timings=[];    repeat(1000,"start.push(Date.now());f();end.push(Date.now())");    for(var i=0,n=start.length;i

这个时候repeat函数并不能访问benchmark函数的内部变量start,end。还是在全局空间查找start,end变量,如果没有还是较好的情况,可以根据错误提示,完成错误定位。如果这个时候全局中恰好有start,end变量,这个时候就会对全局变量进行修改,产生的行为无法进行预测。

闭包封装代码

还是使用上面的例子,但这一些我们使用闭包来对代码进行处理。

改写repeat函数,参数action是一个函数,而不是字符串

function repeat(n,action){   for(var i=0;i

改写benchmark函数,脚本能安全地引用闭包中的局部变量start,end,该闭包以repeat函数的回调函数传递进来。

function benchmark(){    var start=[],end=[],timings=[];    repeat(1000,function(){        start.push(Date.now());        f();        end.push(Date.now());    });    for(var i=0,n=start.length;i

eval函数的另一个问题是,通常一些高性能的引擎难优化字符串中的代码,因为编译器能不能尽可能早地获得源代码来及时 优化代码。函数表达式在其代码出现的同时就能被编译,这使得它更适合标准化编译。

其它eval相关内容可查看:
《》
《》

提示

  • 当将字符串传递给eval函数以执行它们的API时,绝不要在字符串中包含局部变量引用

  • 接受函数调用的API优于使用eval函数执行字符串的API

附录:代码完整版

把上面的代码整理一下,生成一个可以测试任何函数执行时间的代码

function repeat(n,action){   for(var i=0;i

转载于:https://www.cnblogs.com/wengxuesong/p/5563369.html

你可能感兴趣的文章