文章标签 ‘javascript’

javascript 正则表达式 全局修饰符

2011年11月10日 没有评论

在javascript中定义一个正则表达式可以有如下形式:

直接量语法
var re = /pattern/attributes //注意后面不能有分号
创建 RegExp 对象的语法
var re = new RegExp(pattern, attributes);

参数 pattern 是一个字符串,指定了正则表达式的模式或其他正则表达式。

参数 attributes 是一个可选的字符串,包含属性 “g”、”i” 和 “m”,分别用于指定全局匹配、区分大小写的匹配和多行匹配。ECMAScript 标准化之前,不支持 m 属性。如果 pattern 是正则表达式,而不是字符串,则必须省略该参数。

如果用错了attributes中的g修饰符,可能会导致意想不到的结果。例如如下例子中。

var str = "abc123";
var re = /a.c/g
var result1 = re.test(str);
var result2 = re.test(str);
var result3 = re.test(str);

可能第一眼看上去result1、result2、result3都为true吧,但是执行一下,得到的结果有些让人费解,result2为false。即使在var result2 = re.test(str)前对str从新赋值为str = “abctest”,得到结果还是false。为什么会这样呢?其实造成这个结果的原因就是在正则表达式中用全局匹配修饰符(/g),如果去掉/g,即re=/a.c/得到的结果就都为true。现在知道问题出在什么地方,但更深层的原因是什么呢?查看文档,发现RegExp对象有一个lastIndex的属性,如果使用了全局修饰符,那么执行test方法后,lastIndex就会记录匹配的字符串在原始字符串中最后一位的索引加一,例如执行了var result1 = re.test(str)后lastIndex为3,如果没有发现匹配lastIndex置为0。当下次再执行时,对给定的字符串匹配不是从开头位置,而是要依据lastIndex提供的位置,由于这个原因,所以导致上例中result2的值为false。另外也能通过程序重置lastIndex值。不知道这能不能算是javascript引擎的一个Bug。

最后总结一下正则表达式相关的一些操作,RegExp对象本身的方法有exec和test,字符串对象能使用正则的方法有search、match、replace和split。其中真正能用到全局修饰符的只有match和replace,所以在考虑使用正则表达式的时候不要滥用/g。

深入理解JavaScript定时机制

2011年11月7日 没有评论

本文系转载,原文出处http://www.laruence.com/2009/09/23/1089.html

JavaScript的setTimeout与setInterval是两个很容易欺骗别人感情的方法,因为我们开始常常以为调用了就会按既定的方式执行, 我想不少人都深有同感, 例如:

setTimeout(function() {
    alert('你好!');
}, 0);
setInterval(callbackFunction, 100);

认为setTimeout中的问候方法会立即被执行,因为这并不是凭空而说,而是JavaScript API文档明确定义第二个参数意义为隔多少毫秒后,回调方法就会被执行. 这里设成0毫秒,理所当然就立即被执行了.

同理对setInterval的callbackFunction方法每间隔100毫秒就立即被执行深信不疑!

但随着JavaScript应用开发经验不断的增加和丰富,有一天你发现了一段怪异的代码而百思不得其解:

div.onclick = function(){
        setTimeout(function() {
                document.getElementById('inputField').focus();
        }, 0);
};

既然是0毫秒后执行,那么还用setTimeout干什么, 此刻, 坚定的信念已开始动摇.

直到最后某一天 , 你不小心写了一段糟糕的代码:

setTimeout(function() {
        while (true) {
        }
}, 100);
setTimeout(function() {
        alert('你好!');
}, 200);
setInterval(callbackFunction, 200);

第一行代码进入了死循环,但不久你就会发现,第二,第三行并不是预料中的事情,alert问候未见出现,callbacKFunction也杳无音讯!

这时你彻底迷惘了,这种情景是难以接受的,因为改变长久以来既定的认知去接受新思想的过程是痛苦的,但情事实摆在眼前,对JavaScript真理的探求并不会因为痛苦而停止,下面让我们来展开JavaScript线程和定时器探索之旅!

拔开云雾见月明,出现上面所有误区的最主要一个原因是:潜意识中认为,JavaScript引擎有多个线程在执行,JavaScript的定时器回调函数是异步执行的.

而事实上的,JavaScript使用了障眼法,在多数时候骗过了我们的眼睛,这里背光得澄清一个事实:

JavaScript引擎是单线程运行的,浏览器无论在什么时候都只且只有一个线程在运行JavaScript程序.

JavaScript引擎用单线程运行也是有意义的,单线程不必理会线程同步这些复杂的问题,问题得到简化.

那么单线程的JavaScript引擎是怎么配合浏览器内核处理这些定时器和响应浏览器事件的呢?下面结合浏览器内核处理方式简单说明.

浏览器内核实现允许多个线程异步执行,这些线程在内核制控下相互配合以保持同步.假如某一浏览器内核的实现至少有三个常驻线程:javascript引擎线程,界面渲染线程,浏览器事件触发线程,除些以外,也有一些执行完就终止的线程,如Http请求线程,这些异步线程都会产生不同的异步事件,下面通过一个图来阐明单线程的JavaScript引擎与另外那些线程是怎样互动通信的.虽然每个浏览器内核实现细节不同,但这其中的调用原理都是大同小异.

由图可看出,浏览器中的JavaScript引擎是基于事件驱动的,这里的事件可看作是浏览器派给它的各种任务,这些任务可以源自 JavaScript引擎当前执行的代码块,如调用setTimeout添加一个任务,也可来自浏览器内核的其它线程,如界面元素鼠标点击事件,定时触发器时间到达通知,异步请求状态变更通知等.从代码角度看来任务实体就是各种回调函数,JavaScript引擎一直等待着任务队列中任务的到来.由于单线程关系,这些任务得进行排队,一个接着一个被引擎处理.

上图t1-t2..tn表示不同的时间点,tn下面对应的小方块代表该时间点的任务,假设现在是t1时刻,引擎运行在t1对应的任务方块代码内,在这个时间点内,我们来描述一下浏览器内核其它线程的状态.

t1时刻,GUI渲染线程:

该线程负责渲染浏览器界面HTML元素,当界面需要重绘(Repaint)或由于某种操作引发回流(reflow)时,该线程就会执行.本文虽然重点解释JavaScript定时机制,但这时有必要说说渲染线程,因为该线程与JavaScript引擎线程是互斥的,这容易理解,因为 JavaScript脚本是可操纵DOM元素,在修改这些元素属性同时渲染界面,那么渲染线程前后获得的元素数据就可能不一致了.

在JavaScript引擎运行脚本期间,浏览器渲染线程都是处于挂起状态的,也就是说被”冻结”了.

所以,在脚本中执行对界面进行更新操作,如添加结点,删除结点或改变结点的外观等更新并不会立即体现出来,这些操作将保存在一个队列中,待JavaScript引擎空闲时才有机会渲染出来.

GUI事件触发线程:

JavaScript脚本的执行不影响html元素事件的触发,在t1时间段内,首先是用户点击了一个鼠标键,点击被浏览器事件触发线程捕捉后形成一个鼠标点击事件,由图可知,对于JavaScript引擎线程来说,这事件是由其它线程异步传到任务队列尾的,由于引擎正在处理t1时的任务,这个鼠标点击事件正在等待处理.

定时触发线程:

注意这里的浏览器模型定时计数器并不是由JavaScript引擎计数的,因为JavaScript引擎是单线程的,如果处于阻塞线程状态就计不了时,它必须依赖外部来计时并触发定时,所以队列中的定时事件也是异步事件.

由图可知,在这t1的时间段内,继鼠标点击事件触发后,先前已设置的setTimeout定时也到达了,此刻对JavaScript引擎来说,定时触发线程产生了一个异步定时事件并放到任务队列中, 该事件被排到点击事件回调之后,等待处理.
同理, 还是在t1时间段内,接下来某个setInterval定时器也被添加了,由于是间隔定时,在t1段内连续被触发了两次,这两个事件被排到队尾等待处理.

可见,假如时间段t1非常长,远大于setInterval的定时间隔,那么定时触发线程就会源源不断的产生异步定时事件并放到任务队列尾而不管它们是否已被处理,但一旦t1和最先的定时事件前面的任务已处理完,这些排列中的定时事件就依次不间断的被执行,这是因为,对于JavaScript引擎来说,在处理队列中的各任务处理方式都是一样的,只是处理的次序不同而已.

t1过后,也就是说当前处理的任务已返回,JavaScript引擎会检查任务队列,发现当前队列非空,就取出t2下面对应的任务执行,其它时间依此类推,由此看来:

如果队列非空,引擎就从队列头取出一个任务,直到该任务处理完,即返回后引擎接着运行下一个任务,在任务没返回前队列中的其它任务是没法被执行的.

相信您现在已经很清楚JavaScript是否可多线程,也了解理解JavaScript定时器运行机制了,下面我们来对一些案例进行分析:
案例1:setTimeout与setInterval

setTimeout(function() {
        /* 代码块... */
        setTimeout(arguments.callee, 10);
}, 10);

setInterval(function(){
        /*代码块... */
}, 10);

这两段代码看一起效果一样,其实非也,第一段中回调函数内的setTimeout是JavaScript引擎执行后再设置新的setTimeout 定时, 假定上一个回调处理完到下一个回调开始处理为一个时间间隔,理论两个setTimeout回调执行时间间隔>=10ms .第二段自setInterval设置定时后,定时触发线程就会源源不断的每隔十秒产生异步定时事件并放到任务队列尾,理论上两个setInterval 回调执行时间间隔

案例2:ajax异步请求是否真的异步?

很多同学朋友搞不清楚,既然说JavaScript是单线程运行的,那么XMLHttpRequest在连接后是否真的异步?
其实请求确实是异步的,不过这请求是由浏览器新开一个线程请求(参见上图),当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到 JavaScript引擎的处理队列中等待处理,当任务被处理时,JavaScript引擎始终是单线程运行回调函数,具体点即还是单线程运行 onreadystatechange所设置的函数.

分类: web前端 标签: ,

javascript中如何判断某变量是否存在

2011年10月25日 没有评论

如果js代码中用到了某个变量,但是该变量又没有声明,只是script就会报错,大致是“变量xx没有定义”,可以用如下方法来判断一个变量是否已经定义了。

if (typeof(x) == "undefined") {
    alert("未定义");
}

该方法判断一个变量是否未定义,适用于两种情况:

1、x 从来没有出现过。

2、x 只是用 var 声明了,但没有赋值。

javascript中几种连接字符串效率的测试例子

2011年9月27日 没有评论

在javascript对应字符串的连接有三种方法,用的最多可能是”+=“,其次是concat函数,其实还可以借助array的join方法来完成字符串的连接。分别在浏览器IE6,firefox3.0,safari,chorme中测试,发现通过join的方式最快,其次是 +=,最慢的是concat方式。啥也别说了,直接上代码。

重要提示,IE6中可能会把浏览器卡死,如果要测试,请把initData中的100000修改一下,似乎1000就可以看到效果了!效果测试请点击这 里阅读全文…

javascript的repacle方法的用法

2011年9月1日 没有评论

replace是String对象上的一个方法,可以实现把字符串中某些指定的子字符串替换成其他字符串。用法为 “字符串.replace(parm1,parm2)”。其中parm1的老字符串,可以使普通字符串,也可以是一个正则表达式;parm2退换的结果,可以是一个字符串,更重要的是也可以是一个javascript的方法,作为回调函数。下面用几个小例子来分别说明一下。

alert(‘abcabd’.replace(‘ab’,’12′));

这里alert的结果就是12cabd,注意到它只替换到第一次出现的,后面不做替换。如果把子串全部替换,只能用正则表达式的方法来操作。

alert(‘abcabdAbe’.replace(/ab/g,’12′));

这样得到的结果为12c12dAbe,g 表示进行全局替换,同时也可以用 i 来忽略大小写,注意正则表达式不能用引号引起来。

var i = 0;
alert(‘abAabBabC’.replace(/ab/g, function(m) {
i++;
return m + ‘-’ + i + ‘-’;
}));

这里的结果是ab-1-Aab-2-Bab-3-C,当匹配到子字符串时,调用回调方法,并把匹配到的值作为参数传入。另外一个例子,把字符串中小于30的数替换成星号

alert(’10 33 21 18 52′.replace(/\d+/g, function(match) {
return parseInt(match) < 30 ? '*' : match;
}));

javascript读写cookie实例

2011年8月29日 没有评论

Cookie是网站存放在客户端的一小段数据。一般的,网站为了提升用户体验,在客户的客户端中保存用户的历史信息,以备用户再次访问时网站能提供 更方便,更有针对性的服务。比如,网站可以记住你的登录状态,只要登录一次下次访问就不用在登录;购物网能记住你浏览过的产品,保留你购物车中的物品。这 些都有Cookie的功劳。

cookie的存取操作不止局限于服务器段,客户端通过javascript也一样可以进行cookie的存取。利用document.cookie对象就能操作了。下面分别给出读写cookie的方法示例代码。

function getCookie(name){
    var arr = document.cookie.match(new RegExp("(^| )" 
                                   + name + "=([^;]*)(;|$)"));
    if(arr != null) return (arr[2]);
    return null;
}

document.cookie就是以key/value的形式返回所有对于当前页面有权限读取的cookie字符串,然后通过正则表达式查询参数指定cookie名的cookie值。

function setCookie (name, value, expire) {
    var expireStr = '';

    if (expire || expire > 0) {
        var exp  = new Date();
        exp.setTime(exp.getTime() + expire * 1000);

        expireStr = ';expires=' + exp.toGMTString();
    }

    document.cookie = name + '=' + value +  
                      '; path=/;' + expireStr + 
                      'domain=.youdomain.com';
}

注意setCookie中的第三个参数,是指定cookie的过期时间,单位为秒,如果不指定或者值不大于0,那么写入的cookie类型为会话cookie,即浏览器关闭后,cookie就失效,反正就是硬盘cookie,会记录在客户端的电脑上。

IE6 加载动态js不执行的问题

2011年8月25日 没有评论

用户的信息存放在主站上,一个子站也提供用户登录的接口,登陆采用ajax不刷新页面的方式,由于安全原因,ajax不允许跨域执行,所以单纯的ajax是不能直接运行的。但是动态创建script的方式不存在跨域的问题,大致的操作是通过document.createElement创建一个script对象,同时script的src指向主站提供验证用户信息的url,url中参数包括用户输入的用户名和密码,把这个script对象添加到当前页面上。主站的接口根据用户名密码来验证用户是否合法,响应的内容是调用一个js方法。

该方式在IE6下有时不能正常工作,其他主流浏览器都没有问题。IE6的具体症状是第一次能正常工作,如果用户输入用户名和密码不匹配,第一次能提示用户重新输入,但是修改后重新提交了就没有反应,必须要强制刷新才会正常,通过httpwatcher查看,请求是发送,也有响应,就是没有调用成功页面上的js方法。经常反复折腾,终于找到问题的根源,主站接口url是php,所以响应的header中content-type不是text/html,强制设置header中content-type设置为 Content-Type: text/javascript 或者Content-Type: application/x-javascript后,IE6就正常工作了。另外如果服务器启用gzip压缩,可能也会造成IE6不能正常工作,在apache中可以针对某个特定的uri设置成不压缩,如:SetEnvIfNoCase Request_URI /user/vlogin/.* no-gzip dont-vary。

flash与javascript的相互通信的例子

2011年8月24日 没有评论

当前的Web应用中少不了flash,有时候当前页面需要跟flash交互,交互的桥梁是通过javasript来实现,javascript能够调用到flash中定义的方法,同样的flash中也可以调用到javacript的方法。

点这里 查看演示例子 ||  点这里 下载完整代码

flash可以用 ExternalInterface.call(“swfCall” [,arg1[,arg2]]) 的方式来调用javacript中定义的swfCall方法,参数为可选;但是javascript中调用flash的方法,需要flash指定那些方法能调用,例如在flash的代码

ExternalInterface。addCallback("setFlashVal", flashFunction);

function flashFunction(msg) {
	//do something
}

function flashFunction_1(msg) {
	//do something
}

javascript中就可以调用到flashFunction,但调用的方法名是setFlashVal,由于flashFunction_1没有导出,所以页面javascript无法访问到。IE跟Firefox、chrome获取flash对象的方式不同,IE是用window对象,Firefox等则是用document对象。具体参看下面代码:

function getSwfObject(movieName) {
	if (navigator.appName.indexOf("Microsoft") != -1) {
		return window[movieName]
	}else{
		return document[movieName]
	}
}

getSwfObject('swfId').setFlashVal('text');

其中movieName是flash的ID,即<object>标签中定义的ID、或者是embed标签的name属性值,最好这两个值保持一致,否则可能在不同的平台下无法正常工作。

分类: web前端 标签: , , , ,

javascript下动态创建IMG时IE6两次请求指定资源

2011年8月19日 没有评论

众所周知js可以通过document.createElement方法创建DOM对象,并可以把增加到页面上,今天碰到一个怪异的事情,使用如下代码动态创建一个Img

function req() {
	var el = document.createElement('IMG');
	el.src = '资源的WEB地址';                 //line 3
	document.body.appendChild(el);          //line 4
}

在某种特定的调用req方法时,发现在IE6会有两次请求“资源的WEB地址”,其他浏览器都是正常,真是万恶的IE6啊。由于req方法是另一个函数调用的,以后是多次触发了req方法,经过多方的debug,发生确实只调用了一次req,所以产生问题的原因就是在req方法的内部,对于这么简单的代码,唯一可以修改的地方把第3、4行代码换一下位置,调整后,发现IE6正常了,只请求一次了,测试其他浏览器也是正常,唉,再次BS一下IE6。

 

分类: web前端 标签: , ,

iframe中的swf无法调用页面中的js函数

2011年8月19日 没有评论

主页面中存在一个iframe,目的是让iframe在后台处理一些事情,所以把iframe的width,height设置为1个像素,同时设置visibility为hidden,iframe指向的页面中嵌套了一个swf,该swf是flash、as3,as3脚本中是读取flash的SharedObjects中存放的值,并把该值传回给页面的js函数。直接访问这个iframe的页面能够正常工作,即flash能调用到页面上的js函数,但是访问主页面时,FF、safari、chrome也是正常工作,IE6、8就歇菜了,没有反应,经过一番的查找问题,发现根源是iframe不能是隐藏的,即把visibility设置为visible或者去掉visibility的设置就可以了。

分类: web前端 标签: , , , , ,

无觅相关文章插件,快速提升流量