在我的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. 使用JDBC向数据库中插入一条数据

    原谅我是初学者,这个方法写的很烂,以后不会改进,谢谢 /** * 通过JDBC向数据库中插入一条数据 1.Statement 用于执行SQL语句的对象 1.1 通过Connection 的 * cre ...

  2. activiti搭建(二)与Spring集成

    转载请注明源地址:http://www.cnblogs.com/lighten/p/5876773.html 本文主要讲解如何将Activiti和Spring框架集成,再过一段时间将会将一个基础的de ...

  3. activiti源码分析(一)设计模式

    对activiti有基本了解的朋友都知道,activiti暴露了七个接口来提供工作流的相关服务,这些接口具体是如何实现的呢?查看源码发现其实现的形式大体如下: public class Runtime ...

  4. 9.配置postfix空客户端

    将本地邮件服务器配置充当为控客户端,已将所有邮件都转发到中央服务器以进行发送 1.postconf -e "relayhost=[mail.example.com]" 邮件被路由到 ...

  5. 全面解析SQL SERVER 的左右内连接

    SQL SERVER数据库的三种常用连接解析: 这里先给出一个官方的解释: left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右 ...

  6. android Timer and TImerTask

    android Timer and TImerTask Caused by: java.lang.IllegalStateException: TimerTask is scheduled alrea ...

  7. 最初程序员的思维“修炼”之四——Android平台开发的“强制关闭”解决思路

    我和我的朋友参加一个比赛——物联网应用技能大赛,这个大赛所要求的技能有,硬件技术,Android平台开发技术,.NET平台开发技术,所以这是一个团队合作的比赛,基本上没有人能同时掌握这三种技术(在校生 ...

  8. 玄机宝盒v1.6.1.1

    最新版本:玄机宝盒v1.6.1.1 玄机宝盒v1.6.1.1 04-14/2016 给你的将是无与伦比的体验http://bbs.msdn5.com/thread-15-1-1.html(出处: 玄机 ...

  9. silverlight 画图InkPresenter

    <UserControl x:Class="SilverlightTest.PolygonTest" xmlns="http://schemas.microsoft ...

  10. mina socket底层主流程源码实现

    一,mina的架构 mina 架构可以大致分为三部分,ioService ,ioFilterChain , IoHandler   ioService:用于接受服务或者连接服务,例如socket 接收 ...