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

JavaScript技巧与高级特性

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


Function 构造器
对于 Function 构造器,大家可能比较陌生。声明一个 function 时,通常使用前两种方式。该方式的格式是var funcName = new Function(p1, p2,..., pn, body),其中 p1、p2 到 pn 表示的是该 function 的形式参数,body 是 function 的内容。使用该方式的 function 对象是在构造器被调用的时候创建的。该对象的[[scope]]属性的值总是一个只包含全局对象的作用域链。
function 对象的 length 属性可以用来获取声明 function 时候指定的形式参数的个数。如前所述,function 对象被调用时的实际参数是通过 arguments 来获取的。

 

 

with

with 语句的语法是with ( Expression ) Statement。 with 会把由 Expression 计算出来的对象添加到当前执行上下文的作用域链的前面,然后使用这个扩大的作用域链来执行语句 Statement,最后恢复作用域链。不管里面的语句是否正常退出,作用域链都会被恢复。

由于 with 语言会把额外的对象添加到作用域链的前面,使用 with 可能会影响性能并造成难以发现的错误。由于额外的对象在作用域链的前面,当执行到 with 里面的语句,需要对一个标识符求值的时候,会首先沿着该对象的 prototype 链查找。如果找不到,才会依次查找作用域链中原来的对象。因此,如果在 with 里面的语句中频繁引用不在额外对象的 prototype 链中的变量的话,查找的速度会比不使用 with 慢。具体见代码清单 9。


清单 9. with 的用法示例

 

function A() {
    this.a = "A";
 }

 function B() {
    this.b = "B";
 }

 B.prototype = new A();

 function C() {
    this.c = "C";
 }

 C.prototype = new B();

 (function () {
    var myVar = "Hello World";
    alert(typeof a);    // 结果是 "undefined"
    var a = 1;
    var obj = new C();
    with (obj) {
        alert(typeof a); // 结果是 "string"
        alert(myVar);    // 查找速度比较慢
    }
    alert(typeof a);     // 结果是 "number"
 })();
在代码中,首先通过 prototype 的方式实现了继承。在 with 中,执行alert(typeof a)需要查找变量 a,由于 obj 在作用域链的前面,而 obj 中也存在名为 a 的属性,因此 obj 中的 a 被找到。执行alert(myVar)需要查找变量 myVal,而 obj 中不存在名为 myVal 的属性,会继续查找作用域链中后面的对象,因此比不使用 with 的速度慢。需要注意的是最后一条语句alert(typeof a),它不在 with 里面,因此查找到的 a 是之前声明的 number 型的变量。

 


闭包

闭包(closure)是 JavaScript 中一个非常强大的功能。如果使用得当的话,可以使得代码更简洁,并实现在其它语言中很难实现的功能;而如果使用不当的话,则会导致难以调试的错误,也可能造成内存泄露。只有在充分理解闭包的基础上,才能正确的使用它。理解闭包需要首先理解 JavaScript 中的prototype 链、执行上下文和作用域链等概念。

闭包指的是一个表达式(通常是一个 function),该表达式可以有自由的变量,并且运行环境能够正确的获取这些变量的值。 JavaScript 中闭包的产生是由于 JavaScript 中允许内部 function,也就是在一个 function 内部声明的 function 。内部 function 可以访问外部 function 中的局部变量、传入的参数和其它内部 function 。当内部 function 可以在包含它的外部 function 之外被引用时,就形成了一个闭包。这个时候,即便外部 function 已经执行完成,该内部 function 仍然可以被执行,并且其中所用到的外部 function 的局部变量、传入的参数等仍然保留外部 function 执行结束时的值。

下面通过一个例子来说明闭包的形成,见代码清单 10。


清单 10. JavaScript 闭包示例代码

 

function addBy(first) {
  function add(second) {
    return first + second;
  }
  return add;
 }

 var func = addBy(10);
 func(20);  // 结果为 30
 var newFunc = addBy(30);
 newFunc(20); // 结果为 50
在代码清单 10中,外部 functionaddBy的内部 functionadd的引用被返回给addBy的调用者,同时add在方法体中使用了addBy的参数first。这样就形成了一个闭包。通过调用addBy(10)得到的 functionfunc,在其之后的执行过程中,都会保留创建的时候使用的first参数的值10。

下面分析代码清单 10中执行的细节。首先addBy(10)被调用。由于addBy是在全局代码中声明的,因此被调用时候的执行上下文对应的作用域链只包含全局对象。在addBy的方法体中,声明了一个内部 functionadd。add的[[scope]]属性会在作用域链之前加上 functionaddBy的激活对象。该对象中包含了经过初始化的参数first,其值为10。至此,functionfunc的[[scope]]属性的值是包含两个对象。当func被调用的时候,会进入一个新的执行上下文,而此时的作用域链的前面加上了 functionadd调用时的激活对象。该对象中包含了经过初始化的参数second,其值为20。在func的执行过程中,需要对两个标识符first和second求值的时候,会使用之前提到的包含三个对象的作用域链。从而可以正确的求值。

在 JavaScript 中,正确的使用闭包可以简化代码。下面举几个例子来说明。

 


避免名称空间冲突

在多人协作开发应用,或是使用第三方开发的 JavaScript 库的时候,一个通常会遇到的问题是名称空间冲突。比如第三方的 JavaScript 库在全局对象中声明了一个属性叫test,如果在自己的代码中也会声明同样名称的属性的话,当两者一同使用的时候,后加载的属性值会替换之前的值,从而造成错误。

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

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


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