翻译:用Javascript的Function构造器伪造上下文 by Ben Nadel
在我的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的更多相关文章
- JavaScript之Function函数深入总结
整理了JavaScript中函数Function的各种,感觉函数就是一大对象啊,各种知识点都能牵扯进来,不单单是 Function 这个本身原生的引用类型的各种用法,还包含执行环境,作用域,闭包,上下 ...
- [书籍翻译] 《JavaScript并发编程》第五章 使用Web Workers
本文是我翻译<JavaScript Concurrency>书籍的第五章 使用Web Workers,该书主要以Promises.Generator.Web workers等技术来讲解Ja ...
- [书籍翻译] 《JavaScript并发编程》第七章 抽取并发逻辑
本文是我翻译<JavaScript Concurrency>书籍的第七章 抽取并发逻辑,该书主要以Promises.Generator.Web workers等技术来讲解JavaScrip ...
- [书籍翻译] 《JavaScript并发编程》第四章 使用Generators实现惰性计算
本文是我翻译<JavaScript Concurrency>书籍的第四章 使用Generators实现惰性计算,该书主要以Promises.Generator.Web workers等技术 ...
- [书籍翻译] 《JavaScript并发编程》第三章 使用Promises实现同步
本文是我翻译<JavaScript Concurrency>书籍的第三章 使用Promises实现同步,该书主要以Promises.Generator.Web workers等技术来讲解J ...
- [书籍翻译] 《JavaScript并发编程》 第二章 JavaScript运行模型
本文是我翻译<JavaScript Concurrency>书籍的第二章 JavaScript运行模型,该书主要以Promises.Generator.Web workers等技术来讲解J ...
- 机器指令翻译成 JavaScript —— No.5 指令变化
上一篇,我们通过内置解释器的方案,解决任意跳转的问题.同时,也提到另一个问题:如果指令发生变化,又该如何应对. 指令自改 如果指令加载到 RAM 中,那就和普通数据一样,也是可以随意修改的.然而,对应 ...
- javascript执行环境(执行期上下文)详解
javascript执行环境(执行期上下文) 当js控制器(control)进入可执行代码时,控制器会进入一个执行环境,活动的多个执行环境构成执行环境栈,最上面的是正在运行的执行环境,当控制器进入一个 ...
- JavaScript笔记 Function
在JavaScript中方法由两部分组成: 方法名和方法体. JavaScript中的方法跟其他传统面向对象语言不同,它跟普通的变量没有区别,唯一不同点是它是Function对象,因此它会有一些Fun ...
随机推荐
- 《锋利的jQuery》心得笔记--One Sections
第一章 1. $是jQuery的一个简写形式 2. 在jQuery中无法使用DOM对象的任何方法:比如:$ (“#id”).innerHTML.$ (“#id”).checked, 可以使 ...
- SharedSDK微信分享不成功,分享之后没有反应
对于一般来说,使用SharedSDK的时候,分享不成功不外乎下面几个原因: 1.测试没有打包2.打包的keystore跟微信开放平台上面的不一致, 导致MD5码不一致3.分享参数错误4.应用没有审核通 ...
- 网站如何提高PR值
做了站长这些年,积累些经验,记录下来,分享兄弟. 一.商城类型网站 对于商城型的网站站内优化来说,主要是用户咨询和浏览产品时产生的疑问.比如当某用户看到一些自己感兴趣的产品需要咨询的时候,自然就会寻找 ...
- VS2010恢复默认编辑环境的设置
VS2010恢复默认编辑环境的设置 VS2010在安装完成后初次打开的时候可以设置自己常用的环境为默认打开的编辑环境, 也可以在打开IDE以后通过如下步骤设置默认环境: Tools->Impor ...
- 删除 mysql (rpm)
http://blog.csdn.net/love__coder/article/details/6894566 a)查看系统中是否以rpm包安装的mysql [root@linux ~]# rpm ...
- 分享:JS比较两个日期大小
发布:thatboy 来源:Net [大 中 小] 本文介绍下,在javascript代码中,比较两个日期大小的方法,有需要的朋友参考下. 转自:http://www.jbxue.com/ ...
- jquery弹出关闭遮罩层实例
jquery弹出关闭遮罩层实例. 代码如下: <!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" & ...
- php威盾解密的例子分享
例子,批量解密 代码如下 复制代码 <?php/************************************威盾PHP加密专家解密算法 By:zhrt*http://www.111 ...
- Sending Email from mailx Command in Linux Using Gmail’s SMTP
The mailx or mail command in Linux is still providing service for guys like me, especially when we n ...
- ipc telnet 攻击
ping %1 -n 2net use \\%1sc \\%1 config tlntsvr start= autosc \\%1 start tlntsvrtelnet %1