慎用 script 节点的 src 属性来传递参数
在有些使用 javascript 来渲染数据的时候,为了能动态获取不同的数据,并且保持 javascript 代码的可扩展性,会将 javascript 代码中获取数据的部分需要的参数提取出来,做为参数放在 script 节点的外部。
一般来说,传递参数到 javascript 文件内部的方法有两种,一种是将参数写在一个 script 节点中,写成全局变量的方式的传递给紧接着这个 script 节点的外部 javascript 中,Google Analytics 就是使用这样的方式:
<script type="text/javascript"> var p1 = "v1", p2 = "v2"; </script> <script type="text/javascript" src="foo.js"></script>
另外一种是将参数直接写在 script 节点的 src 属性中,相当于一个页面的查询字符串一样:
<script type="text/javascript" src="foo.js?p1=v1&p2=v2"></script>不过,使用 script 节点的 src 属性来传递参数需要注意一个很重要的问题,那就是动态变化的 src 属性会导致缓存失效。
现在,为了网站性能的需要,一般都会将 javascript 文件放在独立的服务器上,并设置一个较长的过期时间,这样客户端只会在第一次访问网站时需要去下载这个 javascript 文件。但是,如果使用 src 来传递参数,就可能会使这种缓存策略失效。特别是 src 中存在动态参数的情况,例如统计脚本中如果有一个 ip 参数,那么访客每次连上线时,可能 ip 都会不同,就会导致 javascript 缓存失效了。
解决这个问题的方法也很简单,简单地的将 src 属性中的参数放到 script 节点的一个自定义属性中就可以了,例如 data-args,而 src 属性只需要保留一个时间戳就可以了。因为使用 src 属性来传递参数本来就需要定位 script 节点,所以改由 data-args 自定义属性来传递参数并不会增加额外的代码。只不过页面会通不过 w3c 的验证罢了 :)
<script type="text/javascript" src="foo.js" data-args="p1=v1&p2=v2"></script>
再次提醒,慎用 script 节点的 src 属性来传递参数 :)

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名Xu Jiwei(包含链接)。
No comments yet.
No trackbacks yet.
使用 arguments.caller 实现自动回调
about 10 months ago - No comments
这是一篇介绍类似于 js hack 的文章,只是说明了一种可行的途径,并且可能会增加代码复杂程度,具体项目中是否可以使用还请自辨:) 在前端开发过程中,有许多业务流程可能是需要用户进行登录的,并且登录过程是放在弹出层中,这样就可以不用刷新页面,增强用户体验。在登录时,用户的操作就会被打断,为了进一步增强用户体验,我们可能需要在登录完成后自动继续进行用户在登录前想进行的操作。 假设有这样一个场景,用户需要发表一个留言,但是发表留言是需要登录的,而发表留言的输入框是一直显示的,这也就要求在用户点击了发表按钮时对用户登录状态进行验证,传统的做法是将在用户登录状态检查封装在一个函数之中,这个函数接收一个回调参数,如果登录验证通过,则执行回调函数。这样的逻辑可以用以下代码表示: 程序代码:[ 复制代码到剪贴板 ] function doAction() { checkLogin(function() { // 处理业务逻辑 }); } function checkLogin(callback) { if (isLogin) { callback(); } else { showLogin(callback); } } function showLogin(callback) { document.getElementById(“login-btn”).onclick = function() { isLogin = true; callback(); }; } 总觉得这样的方式会将业务逻辑放到一个匿名函数中,而不是放在了按钮的事件响应函数中,感觉上不是那么好。这对整个事件响应函数的改动比较大,主要的业务逻辑都放在了登录验证函数的回调中。而希望可以是下面这样: 程序代码:[ 复制代码到剪贴板 ] function doAction() { // 直接在函数开始进行登录验证,将业务逻辑独立出来 if (!doLogin()) { return; } // 处理业务逻辑 } function doLogin() { if (isLogin) { return true; } else { var callback = function() {}; // 自动组装 callback showLogin(callback); return false; } } function showLogin(callback) { document.getElementById(“login-btn”).onclick = function() { isLogin = true; callback(); }; } 这里的关键在于怎么“自动组装 callback”,很幸运的是,JavaScript 的 Function 提供了一个属性 caller 可以用来获取调用当前函数的函数是什么。并且还可以用 caller 的 arguments 属性来获取 caller 执行时的参数是什么,这也就使我们自动组装 callback 并恢复 caller 的原参数成为可能。 <div id=”result”></div> <input type=”button” More >
YUI学习笔记(4)
about 1 year ago - No comments
YUI学习笔记(4) by xujiwei (http://www.xujiwei.com/) YAHOO.util.Subscriber 与 YAHOO.util.CustomEvent。 1. YAHOO.util.Subscriber (event.js) 这 应该算是设计模式中的观察者模式了,Subscriber 订阅一个事件,在 Publisher 触发那个事件后,会逐个通知 Subscriber。 对 于一般开发者来说,并不需要去关心 Subscriber 的实现,因为 Subscriber 主要是 CustomEvent 用来分发动作以及删 除 Subscriber 的。 Subscriber 类只定义了 3 个属性:fn、obj 以及 override,3 个方 法:getScope、contains、toString,其中 fn 为订阅者的回调函数,obj 为要传递给回调函数的一个额外参 数,override 如果是布尔型的 true 值,那么表示使用 obj 属性为回调函数执行时的上下文,或者直接使用一个对象来作为回调函数执行的 上下文。 Subscriber 的 3 个方法中比较有用的是 getScope 和 contains,toString 只是简单的 将 Subscriber 对象转换成一个字符串。getScope 会根据 Subscriber 对象的 override 属性来获取回调函数执行 的上下文,contains 用来判断 Subscriber 对象与指定的回调函数和 obj 是否一致。 2. YAHOO.util.CustomEvent (event.js) CustomEvent 的 作用相当在观察者模式中发布者的身份,可以通过它来实现一个自己的事件发布者。 CustomEvent 构造函数的定义如下: CustomEvent = function(type, oScope, silent, signature) 在 创建 CustomEvent 对象时,几个参数的用途如下: type 是自定义事件的名称,在使用回调函数的参数格式 为 YAHOO.util.Event.LIST 时,回调函数的第一个参数就是 CustomEvent 对象的名称; oScope 是 执行回调函数时的上下文对象,也就是在回调函数中可以用 this 来引用这个对象; silent 参数是用指示是否 在 YUI 为 debug 版本时禁用调试信息; signature 用来指示回调函数参数的格式,可以为 YAHOO.util.Event.FLAT 或 YAHOO.util.Event.LIST, 默认是 YAHOO.util.Event.LIST。 在使用 CustomEvent 之前,先要了解一下 CustomEvent 中 回调函数参数的格式,CustomEvent 的回调函数可以有两种格式,一种为 YAHOO.util.Event.LIST,这种格式的回调函数具有 三个参数,分别是事件名称、参数数组和附加对象参数;另外一种回调函数参数格式为 YAHOO.util.Event.FLAT,这个时候回调函数只有两 个参数,一个为 CustomEvent 对象调用 fire 方法时的第一个参数,另外一个是订阅时的额外对象参数。 在创 建 CustomEvent 对象时,CustomEvent 构造函数还会首先创建一个内部的自定义事件,用来处理该自定义事件被订阅的事件,这 在 EventProvider 中用到,这里暂且不提。 CustomEvent 对象使用一个名为 subscribers 的数组来保 存所有订阅者的列表,并且通过维护这个列表来维护该自定义事件的订阅者。 CustomEvent 对象提供了 subscribe、 unsubscribe、unsubscribeAll、fire 这几个方法来处理自定义事件的订阅、退订以及触发等动作,而这几个就是观察者模式中的 主要动作了。 subscribe 的签名为 subscribe: function(fn, obj, override), 三个参数分别对应了 Subscriber 类构造函数的三个参数,分别对应了回调函数、额外对象参数以及是否使用额外对象参数作为执行上下文。 subscribe 只是简单的判断参数 fn 是否有定义,然后会触发自定义事件订阅事件,最后使用这三个参数创建一个 Subscriber 对象添 加到 CustomEvent 对象的 subscribers 属性中。 unsubscribe 方法用来取消事件的订阅,它的函数签名 为 unsubscribe: function(fn, obj),两个参数分别是回调函数和额外对象参数,如果使用无参数调 用 unsubscribe 方法,那么会直接调用 unsubscribeAll 来删除所有订阅者,否则会逐一判断 subscribers 中的每 个对象,通过使用 Subscriber 对象的 contains 方法来判断给定的 fn 和 obj 与其是否一致,如果一致,就使用一个私有方 法 _delete 来删除这个 Subscriber。 unsubscribeAll 方法没有参数,它只是简单的直接删除自定义事件的 所有订阅者,最后直接给 subscribers 赋值一个空数组来避免有可能出现漏删订阅者的情况。 More >
YUI学习笔记(3)
about 1 year ago - No comments
YUI学习笔记(3) by xujiwei (http://www.xujiwei.com/) YAHOO.lang.later,YAHOO.lang.trim,YAHOO.lang.isXXX 以及 YAHOO.lang.hasOwnProperty。 1. YAHOO.lang.later(yahoo/yahoo.js) later 方法用来延迟执行方法,是对 setInterval 和 setTimeout 的封装,并且可以传递参数到延迟执行的函数或者使用参数数组批量执行指定的函数。 later 方法的签名为: later: function(when, o, fn, data, periodic) when 是用来指定在多长时间后执行指定的函数,以毫秒计算; o 是上下文对象,即在要执行的函数里使用 this 是会引用这个 o 对象; fn 就是要延迟执行的函数了,可以传递一个函数引用,也可以传递一个字符串,later 方法会在 o 对象中查找对应名称的属性来做为要执行的方法; data 就是传递给延迟执行的函数的参数了,可以为一个参数,或者是一个参数数组,那么如果我们要传递的参数本身就是一个数组的话,就要自己先把这个参数数组包装成一个数组; peridoic 参数是一个布尔值,用来表示延迟执行的函数是否需要周期执行而不是只执行一次。 later 方法执行后会返回一个对象,包含了一个名 interval 的属性用来表示函数是以 setInterval 来执行的还是以 setTimeout 来执行的,以及一个方法 cancel 用来取消执行被延迟执行的函数。嗯,不过只有在 peridoic 为 true 时这个 cancel 方法比较有用,毕竟如果 peridoic 为 false 时函数执行一次就不会再执行了,cancel 也没有什么意义。 { interval: periodic, cancel: function() { if (this.interval) { clearInterval(r); } else { clearTimeout(r); } } }; 2. YAHOO.lang.trim (yahoo/yahoo.js) trim 方法用来去除字符串两边的空白字符,其实也就用了一个正则来匹配字符串两端的空白字符并替换成空白字符串。 不过在 YAHOO.lang.trim 中,它使用了一个 try … catch 来在调用的参数不为字符串时直接返回原来的对象。 3. 对象类型判断 YAHOO.lang.isXXX (yahoo/yahoo.js) YAHOO.lang 中包含了一堆用于判断对象是否为某个类型的方法,例如 isObject、isString、isNumber 等。 YAHOO.lang.isArray 用来判断一个对象是否为数组,YUI 中并不是使用的 obj instanceof Array 或者 obj.constructor == Array,而是判断指定的对象是否有两个数组应该具有的经典属性和方法 length 和 splice,这是因为如果要判断的对象是属于另外一个 frame 中时,除非你能获得另外一个 frame 中 Array 定义的费用,否则 instanceof 和 constructor == Array 都是返回 false 的,我们可以使用以下代码来测试一下: test.html <iframe id=”frame” src=”iframe.html”></iframe> <script type=”text/javascript”> <!– var f = document.getElementById(‘frame’); setTimeout(function() { alert(f.contentWindow.arr.constructor == Array); }, 1000); //–> </script> iframe.html <script type=”text/javascript”> <!– var arr = [1, 2, 3]; //–> </script> 而如果把 Array 换成 arr 所在 frame 中 Array 的引用,结果就是为 true 了: test.html <iframe id=”frame” src=”iframe.html”></iframe> <script type=”text/javascript”> <!– var f = document.getElementById(‘frame’); setTimeout(function() { // 这里将 Array 换成 f.contentWindow.Array alert(f.contentWindow.arr.constructor == f.contentWindow.Array); More >
YUI学习笔记(2)
about 1 year ago - No comments
YUI学习笔记(2) by xujiwei (http://www.xujiwei.com/) YAHOO.lang.dump 与 YAHOO.lang.substitute。 1. YAHOO.lang.dump(yahoo.js) dump 方法用来将一个对象转储为一个字符串,并且可以指定转储的深度。 在 dump 过程中,对于基础类型例如 Number、String、Boolean,是直接返回字符串的,对 HTMLElement 对象是返回 HTMLElement 本身,也就是不做处理,对于函数 Function 则是返回字符串“f(){…}”。 对于数组,dump 返回的格式就如我们定义时一样“[item1, item2 item3, ...]”,对于对象 Object,则是使用键值对的形式“key => value”,与 PHP 里面的数组定义方式相似。 例如一个对象定义如下: var obj = { num: 1, str: ”string”, bool: true, date: new Date(), obj: { obj_num: 1, obj_str: ”obj_string” }, foo: function() { } } dump 之后的字符串如下: {num => 1, str => string, bool => true, date => Wed Jan 7 15:57:52 UTC+0800 2009,obj => {obj_num => 1, obj_str => obj_string}, foo => f(){…}} 字符串没有被引号引起来,这个方法只适合用来展示对象的结构,与 JSON 序列化差得有点远了。 2. YAHOO.lang.substitute(yahoo.js) substitute 实现的功能与 C# 中的 String.Format 方法类似,用来格式化一个字符串,但是它是一个字符串来代表一个占位符,而不像 C# 中是使用数字,或许这个用法和 python 中的字符串格式化更像。 substitute 调用的格式为:substitute(formatString, valueObject [,formatCallback]),其中 formatString 是作为格式化字符串的字符串,其中包含着一些格式为 {key} 这样的占位符,valueObject 是包含要取代占位符的值的对象,它的结构为 { key1 : value1, key2 : value2 },最后的 formatCallback 参数则是额外的格式化处理函数,用来在格式化字符串进行一些额外的处理。 substitute 格式化字符串的占位符格式为“{key [meta]}”,其中 meta 是可选的,用来表示额外的格式化属性,而要替换的数据则是 valueObject 中名称为占位符 key 的属性,例如,使用 { name : ”xujiwei” } 做为数据,那么“{name}”将被替换为“xujiwei”。 基本数据类型例如 String、Number 在 substitute 中是直接替换的,但是如果要替换的值为一个数组,那么 subtitute 会先使用 YAHOO.lang.dump 方法将对象转储为一个字符串再进行替换,深度为 10,而在替换的值为一个对象时,则会先检测 meta 数据中是否包含了 dump 关键字,或者这个对象的 toString 方法是否与 Object 对象原型的 toString 方法一样,如果是的话就使用 YAHOO.lang.dump 方法来将对象转储为字符串进行替换,否则就调用对象的 toString 方法得到字符串进行格式化。 如果替换的数据类型不是 Object、Array、String、Number 中的一种的话,那么这个占位符就不进行替换。 一个覆盖了所有类型数据的例子如下: YAHOO.lang.substitute( “String : {key1}\nNumber : {key2}\nObject : {key3}\nArray : {key4}”, { key1 : ”xujiwei”, // String key2 : 123456, // Number key3 : { firstName : ”Jiwei”, lastName : ”Xu” }, // Object key4 : [1, 2, 3] // Array }); 它的输出如下: String : xujiwei Number : 123456 Object : {firstName => Jiwei, lastName => Xu} Array : [1, 2, 3] 对于不支持的类型,substitute 则会在先将占位符替换成 ~-id-~ 的格式,将占位符保存,在进行完所有占位符的处理后再使用正则表达式将 ~-id-~ 替换成原来的占位符。 substitute 没有对 Boolean 类型的数据进行处理,所以如果要替换的数据为 Boolean 时,那么就不能正确格式化字符串了,不知道为什么 YUI 的开发工程师为什么没有去处理 Boolean 类型的数据。而对于 Function 类型的数据,不加 meta 的情况则是直接替换成了 Function 的定义字符串,这是因为 Function 的 toString 方法与 Object 原型的 toString 不一样,但是又没有 meta 指定格式化方式为 dump。 占位符中还可以使用 meta 来附加一个额外的格式化属性,例如在替换的值为对象时可以指定转储的深度,又或者值为 Function 时指定格式化方法为 dump 而不是使用 Function 的定义字符串来进行替换。预定义中可以使用的 meta 只有 dump 一个,表示使用 YAHOO.lang.dump 方法将对象或函数转换成字符串,并且 dump 后可以跟一个数字表示转储的深度,例如: YAHOO.lang.substitute( “Function without dump : {key1}\nFunction with dump : {key1 dump}\nObject without dump0 : {key2}\nObject with dump0 : {key2 dump0}”, { key1 : function() { return ’key1′; }, key2 : { name : { More >
YUI学习笔记(1)
about 1 year ago - No comments
YUI学习笔记(1) by xujiwei (http://www.xujiwei.com/) 今天开始学习 YUI,加强一下对 JavaScript 的理解。 1. 命名空间 YAHOO.namespace(yahoo.js) YUI 中使用了命名空间的概念,在 JS 中使用命名空间是为了模块以及代码组织清晰的需要,通过使用命名空间可以将功能相似或同一模块中的函数、变量等放到同一个命名空间下。 其实 JS 中的命名空间就是一个嵌套的对象而已,即子命名空间相当于父命名空间中的一个属性,它本身也是一个对象,这样子命名空间也可以有自己的子命名空间。 在 YUI 中,命名空间的格式与 C# 中类似,是以点号分隔的字符串,可以使用 YAHOO 对象的静态方法 namespace 来创建命名空间,需要注意的是,以 namespace 方法创建命名空间时,所有的对象都是附加在 YAHOO 这个对象上的,如果调用 namespace 方法创建一个“com.xujiwei.ajax”这样的命名空间,其中 ajax 的完整路径将是 YAHOO.com.xujiwei.ajax,而不是 com.xujiwei.ajax,也就是说 namespace 不会产生新的顶层对象,一切以 YAHOO 对象为基础。 namespace 方法接受一个或多个字符串来生成命名空间,但是它只返回最后一个参数所代表的命名空间的最后一个域的对象,例如使用 namespace(“com.xujiwei.js”, ”com.xujiwei.ajax”) 时它的返回值是代表 js 这个模块的的对象: YAHOO.namespace(“com.xujiwei.js”, ”com.xujiwei.ajax”).get = function() { alert(“get method of com.xujiwei.ajax”); } YAHOO.com.xujiwei.ajax.get(); 2. YAHOO.lang.extend(yahoo.js) YAHOO.lang.extend 负责扩展一个现在的函数对象,相当于面向对象中的继承,并且可以附加一个参数重写继承的方法,它的函数声明是: extend: function(subc, superc, overrides) 其中 subc 为要扩展的函数对象,superc 是要继续的函数对象,overrides 中包含着要重写父类的方法。 YAHOO.lang.extend 是通过原型链的方式来扩展对象,即创建一个父类的实例做为子类的原型对象,在 extend 方法中,首先构造了一个空函数,将空函数的 prototype 指向父类的 prototype,以免在父类的构造函数需要参数时创建父类实例时会出错,然后创建这个空函数的实例赋值给子类的 prototype 对象,并且给子类添加一个 superclass 属性指定它的父类,另外还指定了子类 prototype 的 constructor 属性为子类构造函数,以免创建子类实例时会丢失 constructor 属性,这个问题我在《慎用 somefunction.prototype》有提到。 var F = function() {}; F.prototype = superc.prototype; subc.prototype = new F(); subc.prototype.constructor = subc; subc.superclass = superc.prototype; 接着处理的是要重写的函数,首先遍历 overrides 参数,并且使用 hasOwnProperty 方法判断属性是否为 overrides 自身的属性,而不是从 Object 对象的 prototype 继承过来的,如果是 overrides 自身的属性,那么就覆盖子类 prototype 的相同成员。 在处理 overrides 的最后,还修复了 IE 中不枚举与内部函数同名的函数的 bug,即例如 overrides 中包含了 toString 或 valueOf 的定义,但是这两个函数也是 Object 对象所具有的,在 IE 中使用 for(p in overrides) 就不会得到这两个函数,因此需要修复,这是 YAHOO.lang 中 _IEEnumFix 函数所做的工作。 if (overrides) { for (var i in overrides) { if (L.hasOwnProperty(overrides, i)) { subc.prototype[ i ]=overrides[ i ]; } } L._IEEnumFix(subc.prototype, overrides); } _IEEnumFix 只是简单的判断当前浏览器是否为 IE,如果为 IE 则从一个已经定义的列表中获取在 IE 中枚举不到的函数名列表,逐一判断是否为源对象自身的属性并且与 Object 原型中的同名函数不一样,如果是则添加到目标对象。如果浏览器不是 IE 则 _IEEnumFix 直接就是一个空函数,直接不处理。 _IEEnumFix: (YAHOO.env.ua.ie) ? function(r, s) { for (var i=0;i<ADD.length;i=i+1) { var fname=ADD[ i ],f=s[fname]; if (L.isFunction(f) && f!=Object.prototype[fname]) { r[fname]=f; } } } : function(){}, 3. YAHOO.lang.augmentObject(yahoo.js) augmentObject 方法用来引入目标对象的属性,并且处理重写,通常用于合并配置对象与默认配置对象。 augmentObject 有三种调用方法,分别是: augmentObject(result, source),一般情况下用些方法,从 source 引入 result 中没有的属性; augmentObject(result, source, override),override 设置是否覆盖,如果是 true 的话,那么 source 中所有属性会覆盖 result 中已有的属性; augmentObject(result, source, ovrride_name, …),指定要覆盖属性的列表,source 参数后为要覆盖属性名称的列表,例如覆盖 result 中的 toString 和 valueOf,那么可以调用 augmentObject(result, source, ”toString”, ”valueOf”)来实现。 合并对象的最后同样调用了 _IEEnumFix 方法来修正 IE 中不枚举与内部属性同名属性的 bug。 augmentProto 与 augmentObject 功能基本相同,只不过后者是处理对象,而前者是处理函数的 prototype,它是通过使用两个参数的 prototype 来构造一个参数列表,传递给 augmentObject 对象来实现 augmentProto 的功能。 var a=[r.prototype,s.prototype]; for (var i=2;i<arguments.length;i=i+1) { a.push(arguments[ i ]); } L.augmentObject.apply(this, a); More >
[JavaScript] 慎用 somefunction.prototype
about 1 year ago - No comments
在写 JavaScript 脚本的时候,为了创建一个类,如果不使用框架,一般情况我们都会使用 prototype 来给要创建的类增加公有方法,例如: 程序代码:[ 复制代码到剪贴板 ] // code from xujiwei.cn function Person(name) { this.Name = name; } Person.prototype.SayHello = function() { alert(‘Hello, ’ + this.Name); } Person.prototype.SayBye = function() { alert(‘Goodbye, ’ + this.Name); } 不过,有的时候,为了书写以及维护的方便,我们会把公有方法的声明写到一个对象里,然后赋值给 Person.prototype,例如: 程序代码:[ 复制代码到剪贴板 ] // code from xujiwei.cn function Person(name) { this.Name = name; } Person.prototype = { SayHello: function() { alert(‘Hello, ’ + this.Name); }, SayBye: function() { alert(‘Goodbye, ’ + this.Name); } } 使用这种方式,在这个类具有大量公有方法的时候,就不需要维护许多的 Person 标识符,如果某一天这个类的名字需要改变,那么要改的地方只有两个,一个是 function 的声明,一个是 prototype 前面的标识符,如果是使用前一种方式的话,那么有多少个公有方法,就需要维护 N+1 个标识符了,虽然可以使用查找替换,但是从稳定上来说,查找替换可能会引起一些错误,这增加了维护的成本。 这种方式虽然给我们的维护增加了便利,但也引发了另外一个隐藏的问题,就是类的 constructor 属性丢失的问题。 程序代码:[ 复制代码到剪贴板 ] // code from xujiwei.cn function Person1(name) { this.Name = name; } Person1.prototype.SayHello = function() { alert(‘Hello, ’ + this.Name); } Person1.prototype.SayBye = function() { alert(‘Goodbye, ’ + this.Name); } // code from xujiwei.cn function Person2(name) { this.Name = name; } Person2.prototype = { SayHello: function() { alert(‘Hello, ’ + this.Name); }, SayBye: function() { alert(‘Goodbye, ’ + this.Name); More >
ASP中使用FileSystemObject时提高性能的一个小技巧
about 2 years ago - No comments
在封装自己的FileSystemObject库的时候,测试的时候发现在文件夹或文件很多的时候,效率很低,显示一个文件夹需要2秒甚至更多,这让我很是奇怪,因为显示文件夹及文件信息的时候直接都是使用Folder及File对象的属性,这应该不会引起性能上的问题,但是事实却说明我的想法过于简单了。 按个测试了一下可能会是哪些属性引起的性能问题,在去掉Type也就是类型属性显示的时候,性能有了很大提高,之后的测试也证明了是Type属性的使用导致了性能问题。 仔细想了一下,Type引起性能低的原因应该是,引用Type属性所得到的是文件的具体类型信息,也就是我们在资源浏览器里看到的那样,比如TXT文件的类型就是显示为“文本文档”,但是这个类型信息却是存储在系统中,通过文件扩展名进行关联的。在FSO中使用Type属性的时候,对于每个File对象,FSO都需要根据扩展名去系统中检索这个扩展名对应的类型名称,这样,就极大的降低了性能。 因此,在使用FileSystemObject时,如果可以不使用File或者Folder对象的Type属性,就尽量不使用。 希望此文对你有所帮助。 by Xu Jiwei
提高Vista开始菜单文件夹展开速度的小技巧
about 2 years ago - No comments
用了Vista一段时间,总是觉得Vista的开始菜单里的文件夹展开速度很慢,以前配置不是很好,可以理解为配置的原因,但是现在配置应该也不差了吧,怎么会还是这样呢。 某天玩电脑的时候突然想到,会不会是那个“高亮显示新安装的程序”的原因,试了一下,开始菜单里的文件夹展开速度果然快了很多。 如果你的Vista在进入开始菜单,展开文件夹的时候速度也是很慢的话,不妨试试禁止“高亮显示新安装的程序”,步骤是:在开始的微软徽标上右击,选择属性,然后进入“开始”菜单选项卡,点击“自定义”,打开“自定义’开始’菜单”对话框,在列表中找到“突出显示新安装的程序”,取消选中这个项目,然后确定两遍即可。
JavaScript 中为 Date 类实现 DateAdd 方法
about 2 years ago - No comments
JavaScript 中的并没有提供像 VBScript 里的 DateAdd 方法用于日期的操作,像加一年,减一个月什么的,这在服务端经常用到,比如设置 Cookie 的到期时间为现在时间的后一年,那么就需要使用这个方法了。 虽然 JavaScript 中没有 DateAdd 方法,但是 Date 类却有设置年月日时分秒的方法,比如 setFullYear、setMonth 之类的,而且,这些个方法的参数是可以为负的,在设置之后, Date 类会自行进行调整,每个月是30天还是31天,年份是不是闰年都不用我们来管了,只管设置值就是。 有了这个特性之后,我们就可以很方便的来为 Date 类添加 add 方法了。之所以不添加一个 DateAdd 方法而是给 Date 类添加一个 add 方法是因为我觉得那样更加方便,当然你也可以将 Date 类的 add 方法转换成为一个全局函数 DateAdd。 为了对每一个 Date 类的实例都有效,这里用到了 prototype 对象。 在 VBScript 里的 DateAdd 方法是用一个字符串来控制所加的量是年还是月还是其他的,所以在这里我也模仿 VBScript 里的 DateAdd 方法,使用一个字符串来控制所加量对应的部分,比如 y 代表年,m 代表月。 最后得到的代码如下: 程序代码:[ 复制代码到剪贴板 ] Date.prototype.add = function(part, value) { value *= 1; if(isNaN(value)) { value = 0; } switch(part) { case ”y”: this.setUTCFullYear(this.getUTCFullYear() + value); break; case ”m”: this.setUTCMonth(this.getUTCMonth() + value); break; case ”d”: this.setUTCDate(this.getUTCDate() + value); break; case ”h”: this.setUTCHours(this.getUTCHours() + value); break; case ”n”: this.setUTCMinutes(this.getUTCMinutes() + value); break; case ”s”: this.setUTCSeconds(this.getUTCSeconds() + value); break; default: } } 代码里的 getUTCFullYear 等等也可以换成通常用的 getFullYear,因为是相对调整,所以用哪一个是没有区别的。 希望此文对你有所帮助。 xujiwei
Firefox与IE兼容性:getAttribute的返回值类型
about 3 years ago - No comments
在改AJAXRequest的过程中,碰到了个问题,应该算是Firefox和IE之间的兼容性问题。 提交表单时,往往需要先对表单进行验证,而这个验证的过程一般是放在form标签的onsubmit属性中。 onsubmit一般是由浏览器在form的submit动作发生时自动触发,但是如果表单由我们自己来提交,比如在AJAX应用中,就是由我们自己写程序将表单转换成请求字符串,再通过XMLHttpRequest发送到服务器,那么如果在此同时不丢掉表单验证的话,就需要我们自己来获取onsubmit属性,并去处理它。 在获取属性时,为了保证兼容性,我用getAttribute来获取标签的属性值,但是发获取了onsubmit属性之后,发现在Firefox和IE中使用getAttribute(“onsubmit”)所返回的返回值类型是不同的。 测试代码如下: // code by xujiwei from www.xujiwei.cn<br /><br /> // Firefox中提示框内容为string,IE中为function<br /><br /> <form id=”test” onsubmit=”return validform();”><br /> Name: <input type=”text” id=”name” /><br /><br /> <input type=”button” onclick=”validate();” value=”Validate” /><br /> </form><br /> <script type=”text/javascript”><br /> <!–<br /> function validform() {<br /> return (document.getElementById(“name”).value!=””);<br /> }<br /> alert(typeof(document.getElementById(“test”).getAttribute(“onsubmit”)));<br /> //–><br /> </script> [Ctrl+A 全部选择 提示:你可先修改部分代码,再按运行] 在Firefox中使用getAttribute(“onsubmit”)返回值的是一个字符串,而在IE中的返回值类型则是function,也就是一个函数,因此如果在IE中处理onsubmit,我们可以直接调用这个函数: // code by xujiwei from www.xujiwei.cn<br /><br /> // 注意,下面这段代码只能在IE中正常运行<br /><br /> <form id=”test” onsubmit=”return validform();”><br /> Name: <input type=”text” id=”name” /><br /><br /> <input type=”button” onclick=”validate();” value=”Validate” /><br /> </form><br /> <script type=”text/javascript”><br /> <!–<br /> function validform() {<br /> return (document.getElementById(“name”).value!=””);<br More >