JavaScript忍者秘籍——运行时代码求值
1. 代码求值机制
JavaScript中,有很多不同的代码求值机制。
● eval()函数
● 函数构造器
● 定时器
● <script>元素
- 用eval()方法进行求值
作为定义在全局作用域内的eval()方法,该方法将在当前上下文内,执行所传入字符串形式的代码。
基本功能
● 该方法将执行传入代码的字符串
● 在调用eval()方法的作用域内进行代码求值
例如:
eval("5+5") //
(function(){
eval("var ninja = 6");
console.assert(ninja === 6, "evaluated within the current scope.");
})();
求值结果
eval()方法将返回传入字符串中最后一个表达式的执行结果。例如,如果我们调用如下语句:
eval("3+4; 5+6"); // 结果将返回11
应该指出的是,任何不适简单变量、原始值、赋值语句的内容都需要在外面包装一个括号以便返回正确的结果。例如,如果我们想使用eval()创建一个简单的对象,可能会编写如下语句:
var o = eval('({ninja: 1})');
但是,结果不是我们所期望的。我们需要在对象字面量外面包装一个括号,示例如下:
var o = eval('({ninja: 1})');
在IE8或之前的版本,要使用布尔表达式,才能让eval()进行正确的调用,如下代码:
var fn = eval("false||function(){return true;}");
就像我们用普通方式在特定作用域内创建函数一样,eval()创建的函数会继承该作用域的闭包——局部作用域内执行eval()时的衍生结果。
- 用函数构造器进行求值
使用Function构造器来实例化函数,示例如下:
var add = new Function("a", "b", "return a+b;");
Function构造器可变参数列表的最后一个参数,始终是要创建函数的函数体内容。前面的参数则表示函数的形参名称。所以,上述示例代码等价于如下代码:
var add = function(a,b){return a + b}
虽然这些代码在功能上是等同的,但采用Function构造器方式有一个明显的区别,函数体尤运行时的字符串所提供。另外一个极其重要的实现区别是,使用Function构造器创建函数的时候,不会创建闭包。在不想承担任何不相关闭包开销时,这可能是一件好事。
- 用定时器进行求值
还有一种方式,可以让代码字符串进行求值,而且是异步的,那就是通过定时器进行求值。示例如下:
var tick = window.setTimeout("alert("Hi!"), 100")
- 全局作用域内的求值操作
function globalEval(data){
data = data.replace(/^\s|\s*$/g, "");
if(data){
var head = document.getElementsByTagName("head")[0]||document.documentElement, script = document.createElement("script");
script.type = "text/javascript";
script.text = data;
head.appendChild(script);
head.removeChild(script);
}
}
window.onload = function(){
(function(){
globalEval("var test = 5;");
})();
}
在eval()方法中,我们定义了一个名为globalEval()的函数,以便在全局作用域内求值任何想要要求的内容。该函数去除了所传字符串中的所有前导和尾部空白字符,然后定位DOM中的<head>元素或文档本身,并创建一个分离的<script>元素。设置script元素的类型,然后把需要求值的字符串加载到该script元素的body内。将script元素附加到DOM上,作为head元素的一个子节点,将会导致该脚本在全局作用域内进行求值。
这段代码最常见的场景是动态执行从服务器端返回的代码。它几乎总是要求代码在全局作用域内进行执行,从而让新函数的使用变成必然。
2.函数反编译
反编译意味着将程序集或字节码重组成源代码。例如,将函数反编译成字符串:
function test(a){return a+a; }
console.assert(test.toString() === "function test(a){return a+a; }","Function decompiled");
3.代码求值实战
- JSON转化
运行时求值的最广泛使用方式是将JSON字符串转换为JavaScript对象表示法。例:
var json = '{"name":"Ninja"}';
var object = eval("("+ json +")");
assert(object.name === "Ninja", "My name is Ninja!");
- 导入有命名空间的代码
对于将命名空间导入到当前上下文,base2库提供了一个非常有趣的解决方案。因为没有办法将该问题进行自动化操作,因此我们可以利用运行时求值让该实现变得更简单。
每当一个新类或模块添加到base2包的时候,构造可执行代码的字符串,对其进行求值,可以将产生的函数引入到当前上下文中,示例如下:
base2.namespace ==
"var Base = base2.Base; var Package = base2.Package;" +
"var Abstract = base2.Abstract; var Module = base2.Module;" +
"var Enumberable = base2.Enumberable; var Map = base2.Map;" +
"var Collection = base2.Collection; var RegGrp = base2.RegGrp;" +
"var Undefined = base2.Undefined; var Null = base2.Null;" +
"var This = base2.This; var True = base2.True; var False = base2.False;" +
"var assignID = base2.assignID; var detect = base2.detect;" +
"var global = base2.global; var lang = base2.lang;"+
"var JavaScript base2.JavaScript; var JST = base2.JST;" +
"var JSON = base2.JSON; var IO = base2.IO; var MiniWeb = base2.MiniWeb;" +
"var DOM = base2.DOM; var JSB = base2.JSB; var code = base2.code;" +
"var doc = base2.doc;"
JavaScript忍者秘籍——运行时代码求值的更多相关文章
- 《Secrets of the JavaScript Ninja》:JavaScript 之运行时代码
最近,在阅读 jQuery 之父 John Resig 力作:Secrets of the JavaScript Ninja(JavaScript忍者秘籍).关于第九章提及的 JavaScript 之 ...
- JavaScript 对引擎、运行时、调用堆栈的概述理解
JavaScript 对引擎.运行时.调用堆栈的概述理解 随着JavaScript越来越流行,越来越多的团队广泛的把JavaScript应用到前端.后台.hybrid 应用.嵌入式等等领域. 这篇文 ...
- 如何将oc代码转换成运行时代码
// 运行时 其实就是oc的底层 平时写的代码 最终都是转成底层的运行时代码以下面程序为例子: 如果我们想要看我们的main.m文件底层转换成了怎样的运行时代码 ,我们可以这样做. 1.打开终端 ...
- webpack学习:uni运行时代码解读一 (页面初始化加载)
uni的vue代码是如何在微信小程序里面执行的,对此比较感兴趣所以去调试学习了一波. 准备工作 // 在vue.config.js里打开非压缩的代码 module.exports = { config ...
- 解读JavaScript 之引擎、运行时和堆栈调用
转载自开源中国 译者:Tocy, 凉凉_, 亚林瓜子, 离诌 原文链接 英文原文:How JavaScript works: an overview of the engine, the runtim ...
- 解读 JavaScript 之引擎、运行时和堆栈调用
https://www.oschina.net/translate/how-does-javascript-actually-work-part-1 随着 JavaScript 变得越来越流行,很多团 ...
- JavaScript忍者秘籍——驯服线程和定时器
1.定时器和线程 - 设置和清除定时器 JavaScript提供了两种方式,用于创建定时器以及两个相应的清除方法.这些方法都是window对象上的方法. 方法 格式 描述 setTimeout i ...
- JavaScript忍者秘籍——原型
概要:本篇博客主要介绍JavaScript的原型 1.对象实例化 - 初始化的优先级 初始化操作的优先级如下: ● 通过原型给对象实例添加的属性 ● 在构造器函数内给对象实例添加的属性 在构造器内的绑 ...
- JavaScript忍者秘籍——函数(下)
概要:本篇博客主要介绍函数的一些类型以及常见示例 1.匿名函数 使用匿名函数的常见示例: window.onload = function(){ assert(true,'power!'); }; / ...
随机推荐
- YPreLoad
Javascript库 发布我的控件系列:图片预加载控件YPreLoad v1.0 摘要: 介绍大家好!很高兴向大家介绍我的图片预加载控件YPreLoad.它可以帮助您预加载图片,并且能显示加载的 ...
- 什么是DCI
目录 备注什么是DCI?如何将Role注入到Data中?开发期注入字节码增强MixinTraitTemplateT4 + 部分类 + 显式接口实现 + 扩展类型,C#专用运行期注入Mixin动态代理为 ...
- 老鸟都应该注意的git 提交规范
不知道大家有没有看过自己项目的git 提交信息-----我看过好多次 ,不忍直视 然后提醒一起的小伙伴 :大家规范点 信息要详细, 过段时间再看下 ,还是一样. 相信很多猿都有这样的感受,对于垃圾的 ...
- 迷你MVVM框架 avalonjs 0.82发布
迷你MVVM框架 avalonjs 0.82发布 本版本最大的改进是启用全新的parser. parser是用于干什么的?在视图中,我们通过绑定属性实现双向绑定,比如ms-text="fir ...
- 【驱动】USB驱动·入门
[驱动]USB驱动·入门 Preface USB是目前最流行的系统总线之一.随着计算机周围硬件的不断扩展,各种设备使用不同的总线接口,导致计算机外部总线种类繁多,管理困难.USB总线正是因此而诞生的. ...
- 验证视图状态 MAC 失败,解决方法
错误信息 今天调试一个带cookie表单提交的页面时,浏览器中报错提示:验证视图状态 MAC 失败.如果此应用程序由网络场或群集承载,请确保 <machineKey> 配置指定了相同的 v ...
- android应用程序fps meter[帧数显示]的分析 —— 浅谈root的风险 (1)
fps meter是常用的检测帧率的软件,该软件需要root权限才能工作,一直比较好奇它一个apk是如何知道系统当前的帧率情况的,就针对此apk分析了一下其工作原理. Apk组成 首先看一下apk的组 ...
- myeclipse乱码问题和 编码设置
A Myeclipse安装后编码默认是GB18030,外面的人一般推荐用UTF-8.如果在导入项目后发现乱码现象,那是编码设置设置不对. Eclipse 编码设置: 全局编码设置:编码设置的方法 ...
- vim编辑器的简单使用
写这篇文章是因为在更新我的一篇博客 Git的其他用法 的时候,里面的修改已经提交的commit说明这一部分需要用到vim. 在使用git config --global --edit或者git reb ...
- 简介alert()与console.log()的不同
简单的说alert 是弹出提示而console.log是在调试工具里打日志,下面具体给大家列出alert()与console.log()的不同点, [1]alert() [1.1]有阻塞作用,不点击确 ...