IE动态创建带name的iframe跳转问题

在一些前端项目中可能要用到动态创建iframe的需求,例如无刷新ajax上传文件。但是在IE下创建带有name的iframe会有个bug,创建的代码如下:

var iframe = document.createElement('iframe');
iframe.name = 'test';

上面的这段javascript代码在IE下赋不了name属性!!!即iframe.name = 'test';这段代码未执行。

在IE中我们可以使用下面的代码来动态创建带有name的iframe:

var iframe = document.createElement('<iframe name="test">');

但是上面的代码在非IE浏览器下却报错,这时候我们可以使用判断IE,如果是ie则使用第二段方法动态创建iframe,或者我们可以捕获异常,如下面的代码:

addEventListener第二个参数的handleEvent

昨天无意中看到一篇老外的文章,文章提到了addEventListener第二个参数可以传入object,并且对象中handleEvent为事件处理函数。例如下面的javascript代码:

var obj = {
    handleEvent: function() {
        alert('body clicked');
    }
};
document.body.addEventListener('click',obj,false);

测试发现这段代码在IE9+,chrome,FF,opera等浏览器是正确的(测试范围可能不够宽),而且可以成功的绑定click事件。在Qwrap群里一问才知道是DOM2中接口,很有意思的一个发现,@貘大大 也发微博说自己先入为主了,我相信很多人跟@貘大大 一样都先入为主了。

addEventListener的handleEvent应用

发现了这个“新大陆”有什么用法呢?哈哈~首先想到的是对象引用。

看下面的javascript代码:

<script type="text/javascript">
var obj = {
handleEvent: function() {
    alert('body clicked');
}
};
document.body.addEventListener('click',obj,false);
function fn2(){
    obj.handleEvent = function(){
        alert('fn2');
    };
}
</script>
<button onclick="fn2();">change</button>

因为对象的引用关系,点击下button就可以切换绑定事件的处理函数,而不需要remove之前的事件,然后重新绑定一个新的处理函数。

【PPT分享】XSS注入和防范

这是我前些日子准备的关于《XSS注入和防范》的技术分享ppt,现在放出来,之前是做的powderpoint文件,后来网上流传impress.js做ppt,于是自己也整了个impress.js版本的放在了SAE上面,经过测试发现当ppt的内容较多,带有图片等,impress.js效果就会比较卡。不多说其他的,说说ppt的内容:

《XSS注入和防范》主要从xss是什么,xss的危害,xss的类型及其防范的措施,几个方面来讲解xss。希望对大家理解xss有所帮助,另外多说句cookie的httponly方式,在apache下面有个漏洞,当cookie超过4k的时候就会出现泄漏,所以要注意这个漏洞!(具体代码:狂点此处

废话不多说了,上ppt地址:【PPT分享】XSS注入和防范,请使用支持chrome浏览器查看ppt页面
XSS注入和防范

IE6中a标签触发图片和ajax请求被abort

IE6 a标签的请求被abort的原因

最近项目中掉进IE6 a标签abort两次坑,第一次是a标签绑定一个事件,href='javascript:;'这样a标签触发了事件,切换验证码图片,结果验证码图片总是显示不出来,通过抓包显示状态为abort

其实这个的原因可以从IE6中a标签执行顺序说起,IE6中a标签执行onclick在执行默认事件(即href跳转)之前,当触发了绑定的事件之后,那么处理完事件之后,如果不return false或者阻止默认事件,则会继续执行href跳转,IE6会认为页面跳转到其他页面或者页面重新刷新,则abort之前onclick事件中的请求。

javascript contains方法来判断元素包含关系

IE中的contains方法可以判断A元素是否包含B元素,如果包含则返回true,否则返回false,在开发中会在事件代理处理上面用到。W3C的方法是compareDocumentPosition,所以综上来说:JS通过contains和compareDocumentPosition方法来确定DOM节点间的关系,判断一个元素(对象)是否为另一个元素的子元素。
IE的contains方法很简单,但是W3C的DOMElement.contains(DOMNode)方法会返回却是一个数值。

DOMElement.contains(DOMNode)

link:https://developer.mozilla.org/En/DOM/Node.compareDocumentPosition

DOMElement.contains(DOMNode)

返回的不是一个布尔值,而是一个很奇怪的数值,它是通过如下方式累加计算出来的:

Bits Number Meaning
000000 0 元素一致
000001 1 节点在不同的文档(或者一个在文档之外)
000010 2 节点 B 在节点 A 之前
000100 4 节点 A 在节点 B 之前
001000 8 节点 B 包含节点 A
010000 16 节点 A 包含节点 B
100000 32 浏览器的私有使用

非字母javascript

你尝试过写javascript不用字母和数字吗?最近准备个xss的分享,记起了之前看到过老外一篇文章,内容是关于non-alpha javascript的,拿到代码分析下。
先看这段猥琐的javascript代码:

_=+[];$=_++;__=(_<<_);___=(_<<_)+_;____=__+__;_____=__+___;$$=({}+"")[_____]+({}+"")[_]+({}[$]+"")[_]+(($!=$)+"")[___]+(($==$)+"")[$]+(($==$)+"")[_]+(($==$)+"")[__]+({}+"")[_____]+(($==$)+"")[$]+({}+"")[_]+(($==$)+"")[_];$$$=(($!=$)+"")[_]+(($!=$)+"")[__]+(($==$)+"")[___]+(($==$)+"")[_]+(($==$)+"")[$];$_$=({}+"")[_____]+({}+"")[_]+({}+"")[_]+(($!=$)+"")[__]+({}+"")[__+_____]+({}+"")[_____]+ ({}+"")[_]+({}[$]+"")[__]+(($==$)+"")[___]; ($)[$$][$$]($$$+"('"+$_$+"')")();

看到这里你肯定抓狂了,但是这段代码是可以运行的,运行的结果是 alert('cool code');

javascript分析

这段代码能够运行,原因是javascript是弱类型的脚本语言,而且语法相对松散。例如下面的javascript是正确的,而且是有出乎意料结果的:

javascript 位运算符

前几天看到国外人在github总结的javascript的奇巧淫技(http://t.cn/herRcq),里面对位运算提到的很多,所以来科普一下javascript的位运算。于是找到了w3cschool的这篇教程,很好很强大啊,于是就忍不住转载了……

ECMAScript 整数有两种类型,即有符号整数(允许用正数和负数)和无符号整数(只允许用正数)。在 ECMAScript 中,所有整数字面量默认都是有符号整数,这意味着什么呢?

有符号整数使用 31 位表示整数的数值,用第 32 位表示整数的符号,0 表示正数,1 表示负数。数值范围从 -2147483648 到 2147483647。

可以以两种不同的方式存储二进制形式的有符号整数,一种用于存储正数,一种用于存储负数。正数是以真二进制形式存储的,前 31 位中的每一位都表示 2 的幂,从第 1 位(位 0)开始,表示 20,第 2 位(位 1)表示 21。没用到的位用 0 填充,即忽略不计。例如,下图展示的是数 18 的表示法。

32 位二进制表示的有符号整数

18 的二进制版本只用了前 5 位,它们是这个数字的有效位。把数字转换成二进制字符串,就能看到有效位:

var iNum = 18;
alert(iNum.toString(2));    //输出 "10010"

这段代码只输出 “10010”,而不是 18 的 32 位表示。其他的数位并不重要,因为仅使用前 5 位即可确定这个十进制数值。如下图所示:

5 位二进制表示的整数 18

负数也存储为二进制代码,不过采用的形式是二进制补码。计算数字二进制补码的步骤有三步:

  1. 确定该数字的非负版本的二进制表示(例如,要计算 -18的二进制补码,首先要确定 18 的二进制表示)
  2. 求得二进制反码,即要把 0 替换为 1,把 1 替换为 0
  3. 在二进制反码上加 1

要确定 -18 的二进制表示,首先必须得到 18 的二进制表示,如下所示:

0000 0000 0000 0000 0000 0000 0001 0010

接下来,计算二进制反码,如下所示:

1111 1111 1111 1111 1111 1111 1110 1101

最后,在二进制反码上加 1,如下所示:

1111 1111 1111 1111 1111 1111 1110 1101
                                      1
---------------------------------------
1111 1111 1111 1111 1111 1111 1110 1110

因此,-18 的二进制表示即 1111 1111 1111 1111 1111 1111 1110 1110。记住,在处理有符号整数时,开发者不能访问 31 位。

有趣的是,把负整数转换成二进制字符串后,ECMAScript 并不以二进制补码的形式显示,而是用数字绝对值的标准二进制代码前面加负号的形式输出。例如:

var iNum = -18;
alert(iNum.toString(2));    //输出 "-10010"

这段代码输出的是 “-10010”,而非二进制补码,这是为避免访问位 31。为了简便,ECMAScript 用一种简单的方式处理整数,使得开发者不必关心它们的用法。

另一方面,无符号整数把最后一位作为另一个数位处理。在这种模式中,第 32 位不表示数字的符号,而是值 231。由于这个额外的位,无符号整数的数值范围为 0 到 4294967295。对于小于 2147483647 的整数来说,无符号整数看来与有符号整数一样,而大于 2147483647 的整数则要使用位 31(在有符号整数中,这一位总是 0)。

把无符号整数转换成字符串后,只返回它们的有效位。

注意:所有整数字面量都默认存储为有符号整数。只有 ECMAScript 的位运算符才能创建无符号整数。

IE6中javascript文件开启Gzip出现代码不执行情况

今天处理IE6下的一个bug,经过调试才发现是javascript文件文件总是执行不了,

后来中午吃完饭回来才想起以前同事遇见的html中的javascript不可以执行的问题,怀疑是gzip的原因,此次的问题就是因为动态加载javascript文件导致代码不执行,

经过研究发现gzip压缩过的javascript文件,如果header里Cache-Control 数据有no-cache, no-store,就会出现IE6中js代码不执行的问题。下面是转发的文章内容:

IE6下面调用开启了gzip压缩Javascript的时候,时常会碰到无法执行的情况,有可能是src调用,有可能是ajax调用,其它的浏览器工作正常,唯独IE6不能正常工作。
出现这个BUG的状况如下:

  1. 用户使用IE6浏览器
  2. 服务器没有设置 被请求文件(javascript) expires, cache-control.
  3. 服务器端开启了chunked encoding模式
  4. 通过javascrip的src调用方式或者ajax请求javascript文件
  5. 有可能是通过php生成的javascript文件
  6. 服务器端开启了gzip压缩

解决这个问题,我们要在服务器的cache-control和expires 头信息上做点工作。
经过测试,header头信息如下的gzip压缩过的javascript调用可以正常工作。

Cache-Control:maxage=1
Connection:keep-alive
Content-Encoding:gzip
Content-Type:application/x-javascript;charset=GBK
Date:Wed, 01 Dec 2010 01:24:07 GMT
Expires:Wed, 01 Dec 2010 01:24:08 GMT
Pragma:public
Server:nginx
Transfer-Encoding:chunked

分析上面的头信息,我们可以注意到:

  1. cache-control必须要设置成maxage=time的格式,maxage是指定缓存生效时间,1为1秒
  2. Expires必须要设置,它的时间稍大于Date即可,Date是页面请求时间,Expires是过期时间
  3. Pragma设置为public

javascript的String.replace的妙用

作为前端开发人员,总会有点自己的奇技淫巧,毕竟前端开发不同于后端,代码全部暴漏给用户不说,代码冗余了少则影响带宽,多则效率降低。所以今天我也来爆个自己的奇技淫巧。

javascript的String.replace方法应该javascript前端开发工程师都了解,可是你掌握了吗?

replace有接受两个参数,第一个参数可以是字符串,也可以是正则表达式,第二个参数除支持字符串之外,还支持$1形式正则匹配的文本,除此之外还支持传入一个处理函数,这个函数的return值就是要替换成的内容。
了解更多javascript的String.replace用法,访问:http://www.w3school.com.cn/js/jsref_replace.asp

String.replace的妙用

在《javascript获取隐藏dom的宽高》中,我就使用了replace,使用replace做一些重复性的操作,减少不必要的代码。

其实这里说的重复性的工作就是循环!例如,我们要获取假如我要求id为div1和div2的两个元素的宽高,一部分人会一点一点的做,先算完div1的,然后做div2的,这样你是否觉得有部分是充分的操作呢,于是可以将取宽高的函数独立出来,这样多了一个函数,而且函数只用这两次,似乎有点浪费。

于是一部分人想到了使用split切分字符串,然后用Array.forEach做循环。例如下面的代码:

"div1 div2".split(' ').forEach(function(a,i){
    console.log(a);
    //do something
})

正确理解javascript的this关键字

javascript有this关键字,this跟javascript的执行上下文密切相关,很多前端开发工程师至今对this关键字还是模棱两可,本文将结合代码讲解下javascript的this关键字

this和对象的关系

首先来看下面的代码:

var person = {
    name:'Theo Wong',
    gender:'male',
    getName:function(){
        console.log(person.name);
    }
};
person.getName();

定义了一个person对象,对象中包含了name、gender属性,还包括了一个getName的方法,其作用是输出person对象的name。在这种情况下,我们可以使用this来在person对象中代替person对象本身,所以上面的代码跟下面的直接结果是一样的:

var person = {
    name:'Theo Wong',
    gender:'male',
    getName:function(){
        console.log(this.name);
    }
};
person.getName();

请记住一点:this永远指向的是函数对象的所有者!上面的例子中getName的所有者是person对象,所以this指代的是person。

this和全局对象

我们再来看看再全局对象中,this指代的是什么,我们知道javascript是脚本语言,所以javascript的执行需要有一个宿主环境,在浏览器中这个宿主环境就是window对象,所以在全局函数中,this指代的是window对象(除非使用new,call,apply方法来改变this的指代关系)。懂得了这个关键点,下面的代码就好理解了:

var a = 1;
console.log(a);//1
console.log(this.a);//1
console.log(window.a);//1

很多前端开发工程师经常使用在函数名字之前添加个window来调用函数,这是因为在浏览器中全局对象就是window,所有的函数变量都是在window对象之中,所以下面的代码中的this指代window对象就好理解了:

var a = 1;
function foo(){
    var b = 2;
    console.log(this.a+b);//3
}
foo();

所以说,只要记住:this永远指向的是函数对象的所有者,即this的值是由激活执行上下文代码的调用者决定的,就好理解this的指代关系了。