在我的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. Python深复制浅复制or深拷贝浅拷贝

    1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象.(比深拷贝更加节省内存)2. copy.deepcopy 深拷贝 拷贝对象及其子对象 用一个简单的例子说明如下: >& ...

  2. [javascript|基本概念]学习笔记

    1/语法 a.区分大小写 b.标识符(首字符必须是字母/"_"/"$",其他可为字母/"_"/"$"/数字,不能用关键字 ...

  3. Codevs 1003 电话连线

    时间限制: 1 s   空间限制: 128000 K   题目等级 : 黄金 Gold 题目描述 Description 一个国家有n个城市.若干个城市之间有电话线连接,现在要增加m条电话线(电话线当 ...

  4. [Guava源码分析]Objects 和 ComparisonChain:帮助重写Object方法

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3874194.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  5. ASP.NET MVC局部验证及相关问题

    在上一篇“asp.net mvc常用的数据注解和验证以及entity framework数据映射”话题中,有的博友提到 ‘“同一个实体在3-4个地方会发生修改,每个修改需要验证的方式都不一样,后端就不 ...

  6. Android开发面试题(一)

    1.String和StringBuffer有什么本质区别? 本质区别:String字符串不可变,每次修改字符串必须要重新赋值(生成新的对象)才能修改:StringBuffer字符串可变,可以直接对字符 ...

  7. 杂项一之js,<select>标签

    一.在aspx页面中实现 修改与删除页面的跳转 前台js部分: 在上部的js部分中写,根据传过来的id,来经行页面的跳转,并把id传过去 js部分就是实现了一个页面跳转的功能 (还有确认框confir ...

  8. h5 web模板

    <!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --><html lang="zh-cmn-Hans"> ...

  9. Json(2)-DataContractJsonSerializer

    public static void DataContractSerializeDemo()        {            User user = new User { UserID = 1 ...

  10. Png图片的透明部分穿透测试

           private void Window_MouseMove(object sender, MouseEventArgs e){ NavBtnList.Clear(); Point mou ...