源码 | 书库 | 模板 | 特效 | 广告 | 素材 | 工具 | 必备 | ALEXA | 字体
会员投稿 投稿指南 RSS订阅
您当前的位置是:主页>网络编程>Javascript教程>

JavaScript技巧与高级特性

www.jz123.cn  2008-12-31   来源:   中国建站    编辑整理    我要投递新闻

隐式的 eval

除了显式的调用 eval 之外,JavaScript 中的有些 function 能接受字符形式的 JavaScript 代码并执行,这相当于隐式的调用了 eval 。这些 function 的典型代表是setTimeout和setInterval。具体请见代码清单 7。由于 eval 的性能比较差,所以在使用setTimeout和setInterval等 function 的时候,最好传入 function 的引用,而不是字符串。


清单 7. 隐式的 eval 示例

 

var obj = {
    show1 : function() { alert(" 时间到! "); },
    show2 : function() { alert("10 秒一次的提醒! "); };
 };

 setTimeout(obj.show1, 1000);
 setTimeout("obj.show1();", 2000);

 setInterval(obj.show2, 10000);
 setInterval("obj.show2();", 10000);
eval 的潜在危险

在目前的 Ajax 应用中,JSON 是一种流行的浏览器端和服务器端处之间传输数据的格式。服务器端传过来的数据在浏览器端通过 JavaScript 的 eval 方法转换成可以直接使用的对象。然而,在浏览器端执行任意的 JavaScript 会带来潜在的安全风险,恶意的 JavaScript 代码可能会破坏应用。对于这个问题,有两种解决方式:

带注释的 JSON(JSON comments filtering)和带前缀的 JSON(JSON prefixing)
这两种方法都是 Dojo 中用来避免 JSON 劫持(JSON hijacking)的。带注释的 JSON 指的是从服务器端返回的 JSON 数据都是带有注释的,浏览器端的 JavaScript 代码需要先去掉注释的标记,再通过 eval 来获得 JSON 数据。这种方法一度被广泛使用,后来被证明并不安全,还会引入其它的安全漏洞。带前缀的 JSON 是目前推荐使用的方法,这种方法的使用非常简单,只需要在从服务器端的 JSON 字符串之前加上{} &&,再调用 eval 。关于这两种方法的细节,请看参考资料。
对 JSON 字符串进行语法检查
安全的 JSON 应该是不包含赋值和方法调用的。在 JSON 的 RFC 4627 中,给出了判断 JSON 字符串是否安全的方法,是通过两个正则表达式来实现的。具体见代码清单 8。关于 RFC 4627 的细节,请看参考资料。


清单 8. RFC 4627 中给出的检查 JSON 字符串的方法

 

var my_JSON_object = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
             text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
 eval('(' + text + ')');
执行上下文(execution context)和作用域链(scope chain)

执行上下文(execution context)是 ECMAScript 规范(请看参考资料)中用来描述 JavaScript 代码执行的抽象概念。所有的 JavaScript 代码都是在某个执行上下文中运行的。在当前执行上下文中调用 function 的时候,会进入一个新的执行上下文。当该 function 调用结束的时候,会返回到原来的执行上下文中。如果 function 调用过程中抛出异常,并没有被捕获的话,有可能从多个执行上下文中退出。在 function 调用过程,也可能调用其它的 function,从而进入新的执行上下文。由此形成一个执行上下文栈。

每个执行上下文都与一个作用域链(scope chain)关联起来。该作用域链用来在 function 执行时求标识符(Identifier)的值。在该链中包含多个对象。在对标识符进行求值的过程中,会从链首的对象开始,然后依次查找后面的对象,直到在某个对象中找到与标识符名称相同的属性。如”protype 链与继承“中所述,在每个对象中进行属性查找的时候,会使用该对象的 prototype 链。在一个执行上下文中,与其关联的作用域链只会被with语句和 catch 子句影响。

在进入一个新的执行上下文的时候,会按顺序执行下面的操作:

创建激活(Activation)对象
激活对象是在进入新的执行上下文的时候被创建出来的,并与新的执行上下文关联起来。在初始化的时候,该对象包含一个名为arguments的属性。激活对象在变量初始化的时候也会被使用。 JavaScript 代码不能直接访问该对象,但是可以访问该对象里面的成员(如 arguments)。
创建作用域链
接下来的操作是创建作用域链。每个 function 都有一个内部属性[[scope]],它的值是一个包含多个对象的链。该属性的具体值与 function 的创建方式和在代码中的位置有很大关系(见“function 对象的创建方式”)。这个步骤中的主要操作是将上一步中创建的激活对象添加到 function 的[[scope]]属性对应的链的前面。
变量初始化
该步骤对 function 中需要使用的变量进行初始化。初始化时使用的对象是第一步中所创建的激活对象,不过被称之为变量(Variable)对象。会被初始化的变量包括 function 调用时的实际参数、内部 function 和局部变量。在这个步骤中,对于局部变量,只是在变量对象中创建了同名的属性,但是属性的值为 undefined,只有在 function 执行过程中才会被真正赋值。
全局 JavaScript 代码是在全局执行上下文中运行的,该上下文的作用域链只包含一个全局对象。

图 2中给出了 function 执行过程中的作用域链的示意图,其中的虚线表示作用域链。


图 2. 作用域链示意图

 

 

 

 

function a() {}、var a = function() {} 与 var a = new Function()

在 JavaScript 中,function 对象的创建方式有三种:function 声明、function 表达式和使用 Function 构造器。通过这三种方法创建出来的 function 对象的[[scope]]属性的值会有所不同,从而影响 function 执行过程中的作用域链。下面具体讨论这三种情况。

function 声明
function 声明的格式是function funcName() {}。使用 function 声明的 function 对象是在进入执行上下文时的变量初始化过程中创建的。该对象的[[scope]]属性的值是它被创建时的执行上下文对应的作用域链。
function 表达式
function 表达式的格式是var funcName = function() {}。使用 function 表达式的 function 对象是在该表达式被执行的时候创建的。该对象的[[scope]]属性的值与使用 function 声明创建的对象一样。

上一篇:javascript中如何确定undefine 下一篇:JavaScript Throw教程

评论总数:2 [ 查看全部 ] 网友评论


关于我们隐私版权广告服务友情链接联系我们网站地图