在我的jQuery模板标记语言(JTML)项目中,我需要一种方式将JTML模板编译到JS函数,这样它们就可以如期地在任何时候转换成新的HTML标记。但这是一个严峻的问题,因为JTML代码涉及非作用域(全局)变量,在函数执行的时候,那些变量能够在渲染引擎的上下文中可用。当我编写这个项目的代码时,我能想到的唯一办法就是当一个模板需要被渲染时每次创建一个新的Function()。这样,在一定程度上违背了提前编译渲染引擎的目的。经过深思熟虑,我想是否可以通过JS的apply()功能创建出动态的作用域,预编译函数。

当你使用apply()或者call()方法去改变一个函数的执行上下文时,其实真正做的就是改变“this”的引用。this在非作用域下并没有效果,但会向函数的闭包链往上爬找到this(全局对象)。但是,如果我们有这样一个函数可以在它执行完毕前检查它自己的this上下文?如果我们创建了一个函数,在该函数执行完毕之前在前面插入有“this作用域“变量到它的局部作用域,我们就应该能够通过改变函数的上下文,简单地动态改变可用的非作用域变量了。下面的demo就是我要说的:

<!DOCTYPE HTML>
<html>
<head>
<title>Javascript Function() With Context</title>
<script type="text/javascript" src="jquery-1.4.2.js"></script>
<script type="text/javascript"> // I am a proxy for the Function() constructor that prepends
// code to copy the function's context variables into the
// function local scope so that they may dynamically changed
// at the time of execution.
// Function构造器代理。 在函数代码块头部插入复制函数的上下文变量到函数局部作用域。
function FunctionContext( sourceCode ){ // Call and return the Function() constructor. Notice
// that if the THIS is not Window, we are VAR'ing the
// context variables into the function local scope.
return(Function(
"if (this != window){" +
"for (var __i in this ){" +
"eval( 'var ' + __i + ' = this[ __i ];' );" +
"}" +
"}" +
sourceCode
));
} // -------------------------------------------------- //
// -------------------------------------------------- // // Define a function that uses a variable that is not
// defined as part of the function source code.
var saySomething = FunctionContext(
"console.log( name + ', you\\\'re looking so hot!' );"
); // -------------------------------------------------- //
// -------------------------------------------------- // // Now, execute the saySomething() method in three different
// contexts, each of which changes the name.
saySomething.apply({
name: "Tricia"
}); saySomething.apply({
name: "Vicky"
}); saySomething.apply({
name: "Erika"
}); </script>
</head>
<body>
<!--- Intentionally left blank. --->
</body>
</html>

我已经创造了这个函数FunctionContext(),实质上就是JS的Function()构造器代理。它的工作就是在代码块被传入Function构造器参数中前在头部插入一段逻辑。该逻辑检查函数的”this“上下文。如果函数的上下文不是window对象,说明它被call()或者apply()方法重写了,所有的this作用域值都被编译成函数局部作用域的变量了。任何上下文的变量在函数内部逻辑里都可以当做非作用域值了。

当我们跑上面的代码时,输出:

Tricia, you're looking so hot!
Vicky, you're looking so hot!
Erika, you're looking so hot!

正如所看,通过使用apply(),每次执行编译后的函数时,我都在改变上下文。而且,自从第一次执行复制”this“作用域变量到局部作用域,无作用于变量”name“从来不会报错。

我需要一种方式当一个函数被执行时动态改变变量为可用的。如果我单单用eval()函数,我将会失去预编译的优势。如果我仅用Function()构造器,我不能想到一个办法改变为可用变量,在没有使用已有的参数情况下(我可能甚至不知道该如何提前)。通过两个结合使用,我找到了最优雅的方式转换为可用的局部变量。

原文:http://www.bennadel.com/blog/1927-Faking-Context-In-Javascript-s-Function-Constructor.htm

翻译:用Javascript的Function构造器伪造上下文 by Ben Nadel的更多相关文章

  1. JavaScript之Function函数深入总结

    整理了JavaScript中函数Function的各种,感觉函数就是一大对象啊,各种知识点都能牵扯进来,不单单是 Function 这个本身原生的引用类型的各种用法,还包含执行环境,作用域,闭包,上下 ...

  2. [书籍翻译] 《JavaScript并发编程》第五章 使用Web Workers

    本文是我翻译<JavaScript Concurrency>书籍的第五章 使用Web Workers,该书主要以Promises.Generator.Web workers等技术来讲解Ja ...

  3. [书籍翻译] 《JavaScript并发编程》第七章 抽取并发逻辑

    本文是我翻译<JavaScript Concurrency>书籍的第七章 抽取并发逻辑,该书主要以Promises.Generator.Web workers等技术来讲解JavaScrip ...

  4. [书籍翻译] 《JavaScript并发编程》第四章 使用Generators实现惰性计算

    本文是我翻译<JavaScript Concurrency>书籍的第四章 使用Generators实现惰性计算,该书主要以Promises.Generator.Web workers等技术 ...

  5. [书籍翻译] 《JavaScript并发编程》第三章 使用Promises实现同步

    本文是我翻译<JavaScript Concurrency>书籍的第三章 使用Promises实现同步,该书主要以Promises.Generator.Web workers等技术来讲解J ...

  6. [书籍翻译] 《JavaScript并发编程》 第二章 JavaScript运行模型

    本文是我翻译<JavaScript Concurrency>书籍的第二章 JavaScript运行模型,该书主要以Promises.Generator.Web workers等技术来讲解J ...

  7. 机器指令翻译成 JavaScript —— No.5 指令变化

    上一篇,我们通过内置解释器的方案,解决任意跳转的问题.同时,也提到另一个问题:如果指令发生变化,又该如何应对. 指令自改 如果指令加载到 RAM 中,那就和普通数据一样,也是可以随意修改的.然而,对应 ...

  8. javascript执行环境(执行期上下文)详解

    javascript执行环境(执行期上下文) 当js控制器(control)进入可执行代码时,控制器会进入一个执行环境,活动的多个执行环境构成执行环境栈,最上面的是正在运行的执行环境,当控制器进入一个 ...

  9. JavaScript笔记 Function

    在JavaScript中方法由两部分组成: 方法名和方法体. JavaScript中的方法跟其他传统面向对象语言不同,它跟普通的变量没有区别,唯一不同点是它是Function对象,因此它会有一些Fun ...

随机推荐

  1. Liskov替换原则(LSP)

    OCP中,继承支持了抽象和多态特性. LSP:子类必须能够替换掉其基类. 反例:使用if/else判断类型,以便选择针对特定类型的正确行为. 有效性并非本质属性 模型的有效性,只能通过它的客户程序来表 ...

  2. 济南学习 Day 4 T1 pm

    幸运数字(number)Time Limit:1000ms Memory Limit:64MB题目描述LYK 最近运气很差,例如在 NOIP 初赛中仅仅考了 90 分,刚刚卡进复赛,于是它决定使用一些 ...

  3. [windows phone开发]新生助手的开发过程与体会三

    由于网络原因,新生助手开发介绍的博客近期一直没有更新,请大家见谅.今天向大家介绍一下新生助手中动态磁帖的实现. 在PhoneApplicationPage中添加如下引用 xmlns:toolkit=& ...

  4. windowsphone 瀑布流&ui虚拟化

    瀑布流已经有点年代了吧,不过wp上还真是挺少资料的.今天抽空把自己之前搞过的东西写出来,避免大家重复劳动. 一.简单的瀑布流排版加入ui虚拟化. 最近看了 段博琼  ui虚拟化的一篇博文,链接:htt ...

  5. mount.nfs: access denied by server while mounting localhost:/home/xuwq/minilinux/system

    在执行命令如下: mount -t nfs localhost:/home/xuwq/minilinux/system /mnt 出现的错误: mount.nfs: access denied by ...

  6. 一款jQuery立体感动态下拉导航菜单特效

    一款jQuery立体感动态下拉导航菜单特效,鼠标经过,在菜单栏上方下拉出一个背景图片,效果十分不错的一款jquery特效. 对IE6都是兼容的,希望大家好好研究研究. 适用浏览器:IE6.IE7.IE ...

  7. Linux系统下sendmail发送邮件失败的问题

         问题是:安装完sendmail,启动服务后,发送邮件第一次发送成功,后面再次无论怎么发送都不行,换邮箱也不行.在确认我的邮件发送格式正确无误后,想到查看邮件发送日志: [root@backu ...

  8. 【转】微软MVP攻略 (如何成为MVP?一个SQL Server MVP的经验之谈)

    一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 初衷 什么是微软MVP? 成为微软MVP的条件? 如何成为微软MVP? (一) 申请时间划分 (二) 前期准备 (三) ...

  9. raiserror的用法

    描述:raiserror :是用于抛出一个错误 第一个参数:{ msg_id | msg_str | @local_variable } msg_id:表示可以是一个sys.messages表中定义的 ...

  10. SVN四部曲之SVN命令精通

    SVN 常用命令一览表 命令 功能 使用格式 checkout 检出 svn  co  URL up 更新到当前URL的末端 svn  up switch 更新到某一tag/branch svn  s ...