标签: JavaScript

  • 把JavaScript中的伪数组转换为真数组

    在 JavaScript 中, 函数中的隐藏变量 arguments 和用 getElementsByTagName 获得的元素集合(NodeList)都不是真正的数组,不能使用 push 等方法,在有这种需要的时候只能先转换为真正的数组。

    对于 arguments,可以使用 Array.prototype.slice.call(arguments); 来达到转换的目的,但对于 NodeList 则不行了,其在 IE8 及以下将会报错,只能说其 JS 引擎有所限制。

    因此,如果需要把 NodeList 转换为真正的数组,则需要做下兼容处理。

    function realArray(c) {
        try {
            return Array.prototype.slice.call(c);
        } catch (e) {
            var ret = [], i = 0, len = c.length;
            for (; i < len; i++) {
                ret[i] = (c[i]);
            }
            return ret;
        }
    }
    

    References

    1. javascript Array.prototype.slice使用说明
    2. Advanced Javascript: Objects, Arrays, and Array-Like objects
  • 代价的选择

    对于语言来说,如果想减少跨平台开发的消耗,那么就要付出语言运行效率的代价。比如java等依赖于虚拟机的语言,很大程度上是一次编译处处运行的,但效率上就远远哪不上c这种可以直接和硬件打交道的语言。

    javascript这种解释性的语言则更是跨平台,只要浏览器依照了规范,那么就处处可以运行,但效率上就更慢上一些了。再加上其天然的单线程特征,在处理复杂运动上就更加劣势了。

    touchpad 的概念不说不好,但由于采用语言本身的问题,比采用 java 的android慢上很多,更不用说是采用object-c的ios了。

  • JavaScript保留字

    JavaScript 除了语言规范本身的关键字、保留字外,在和浏览器结合的过程中产生了更多的保留字,有一次就踩中了status这个雷区,故特意找来一下这方面的资料[1]以备忘。

    JavaScript Reserved Words
    break continue do for import new this void
    case default else function in return typeof while
    comment delete export if label switch var with

    (更多…)

  • 连续赋值与求值顺序

    看到一个2010 年的帖子[1],里面讨论了一段 JavaScript 代码:

    var a = {n:1};
    a.x = a = {n:2};  
    alert(a.x);     // --> undefined 
    

    帖子里有很多的讨论来分析为何 a.xundefined,下面是我的一些思考。

    首先,在JavaScript中,有以下几点需要明确的:

    1. 可以说一切都是对象
    2. 赋值运算符(=)是除逗号运算符(,)外优先级最低的,并且是右结合的。[2]
    3. 求值顺序[3]是从左向右的[4]

    (更多…)

  • 鼠标滚轮缩放图片

    浏览网页的时候,有时候图片局限于网站而很小,即便原来是一张大图。为了偷懒不想新标签页打开图片,于是写了个小小的 bookmarklet 来直接在图片上通过鼠标滚轮来进行缩放。

    javascript:(function(){var imgs=document.getElementsByTagName('img');var rate=rate||0.1;for(var j=0,l=imgs.length;j<l;j++){(function(i){var item=imgs[i];item.onmousewheel=function(e){e=e||window.event;zoom(imgs[i],mouseWheelRes(e),rate);};if(item.addEventListener){item.addEventListener('DOMMouseScroll',function(e){zoom(imgs[i],mouseWheelRes(e),-rate);},false);}})(j);}function zoom(img,inOut,rate){if(inOut>0){img.width=img.width*(1+rate);img.height=img.height*(1+rate);}else{img.width=img.width*(1-rate);img.height=img.height*(1-rate);}}function mouseWheelRes(e){e.preventDefault?e.preventDefault():e.returnValue=false;e.stopPropagation?e.stopPropagation():e.cancelBubble=true;return e.wheelDelta||e.detail;}})();
    

    可读性良好一些的代码如下:
    (更多…)

  • 小心Dom元素的name属性

    对于一个用 JavaScript 获取到一个 DOM 节点的后,在说到属性的时候需要注意的是指 DOM 节点的属性还是 JavaScript 对象的属性(或说字段名)。一般来说,前者用 getAttribute/setAttribute 来访问/修改,后者用 object.field 来访问。然而,对于像 id、className 这些却属于 DOM 节点的 Attribute 范围。在说到 name 属性的时候,就更加复杂一点了,因为牵涉到 IE 的特殊处理。

    当想用 setAttribute 给一个已有的(或动态创建的) DOM 元素设置 name 属性时,将会发现 IE6/7 跟 form 及相关表单元素合不来,根本就没有设置成功。

    微软的文档,在 IE6/7 中,form 表单时的 name 属性是有些特殊的,用来标志提交的数据,跟平常的用途有些不一样。

    var createNamedElement = function (type, name) {
        var element = null;
        // Try the IE way; this fails on standards-compliant browsers
        try {
            element = document.createElement('<'+type+' name="'+name+'">');
        } catch (e) {
        }
        if (!element || element.nodeName != type.toUpperCase()) {
            // Non-IE browser; use canonical method to create named element
            element = document.createElement(type);
            element.name = name;
        }
        return element;
    };
    
    // create an input element with name
    var aInput = createNamedElement('input', 'aInp');
    

    如果只是需要创建一个节点而不需要后续引用继续修改的话,我会更加倾向于直接用 innerHTML 来创建,比如:

    someNode.innerHTML = someNode.innerHTML + '<input type="button" name="aButton" value="This is a button" />';
    

    需要注意的是,对于 name 属性,在表单类中 attribute 和 field 是相同的,但在非表单中, attribute 中的才是 HTML 代码中可见的 name 属性。

    See more demo


    References:

    1. Weird behaviour of iframe `name` attribute set by jQuery in IE
    2. NAME Attribute | name Property
    3. Setting the “name” attribute in Internet Explorer
  • 于悄无声息中获取你的访问记录

    当访问某个网站时,不经意中,就被别人猜测到你是否访问过某个网站,而这却没有什么技术性的东西,也不算是违法的行为。

    奥秘在于浏览器对于访问过的链接会用伪类 :visited 来标识。

    那么很容易想到的一个方法就是,用 a:visited 来设定一个特定的颜色值,比如 red。然后从一个 URL 列表中来动态创建一个链接,然后获取其颜色(各浏览器返回的结果不完全一致,可能是 rgb 值,也可能是 hex 值),如果跟设定的颜色一致,那么就可以确定用户在当前浏览器访问过该链接。

    实际测试中会发现,新版本的浏览器(如Chrome 14, IE9, FF5)对于 a:visited 的样式是成功应用的,但获取到的颜色却不是对应的设定,而是 a:link、a 甚至是默认的颜色,从而无法判断用户是否访问过该链接。这是现代浏览器在这方面的安全保护,一方面使样式可以正常生效,另一方面却防止了 JS 窃听。然而,在一些旧版本的浏览器(比如IE6~8, FF3)上面却没有这个保护措施,因而可以判断出是否在该浏览器上访问过该链接。

    对于以上依赖于 JavaScript 的窃听,很容易想到的一个防止方法就是禁止 JavaScript 的运行。没错,抛开种种不便来说,的确可以达到防止以上窃听的目的,即便是 IE6 等老一代浏览器。但是,却防止不了 CSS 的窃听方式。

    又是如何利用 CSS 来进行判断窃听的吗? (更多…)

  • jQuery tmpl

    动态请求数据来更新页面是现在非常常用的方法,比如博客评论的分页动态加载,微博的滚动加载和定时请求加载等。

    这些情况下,动态请求返回的数据一般不是已拼好的 HTML 就是 JSON 或 XML,总之不在浏览器端拼数据就在服务器端拼数据。不过,从传输量方面来看,返回 HTML 不划算,而在 web 传输方面,现在更多的是使用 JSON 而不是 XML。

    浏览器端根据 JSON 生成 HTML 有个很苦恼的地方就是,结构不复杂的时候还好,结构一复杂,就想死了,需要很小心很小心地写出几乎无法维护的 JavaScript 代码。

    如同为解决 PHP 拼数据这方面的问题而有了 Smarty 这些模版,JavaScript 也可以利用模版来解决这些问题,比如基于 jQuery 的 jquery.tmpl,现在已经被接受为官方的模版插件了。详细的 API 在 jQuery 的 Templates 里,内置的 demo 也尽情地演示了各种用法。

    就我自己的几次使用,感觉很不错,用更加直观方面的 HTML 写法而不是 JavaScript 拼凑 来写结构,然后用 JSON 变量来占位的方式来填充数据,代码看起来好多了。

    Update

    需要说明的是,由于我相对熟悉的是 PHP,尽管是使用 作为变量开始符号,但与 tmpl 的{} 标识没有冲突;而 JSP 本身使用 ${} 来作为变量内容输出,所以在 JSP 会导致模版无法正常工作,这里是一些相关问答

    解决方法:

    1. 禁用(本项目) JSP 的 ${} 标签功能, 方法见相关问答;但明显代价太大。
    2. 对 tmpl 中的 ${} 进行转义,即使用 \${}的方式;这样将静态 demo 转为 开发版本需要细心更正一下。
    3. 不想用模版的就依然手动拼字符串;仍想用模版的就切换到别的不是使用 ${} 来解析的模版。
  • 退出或刷新页面时提示

    先看代码

    // as my test, Opera do not fire the event
    window.onbeforeunload = function (e) {
        e = e || window.event;
    
        // For IE and Firefox prior to version 4
        if (e) {
            e.returnValue = 'Sure to quit?';
        }
    
        // For Safari and Chrome
        return 'Sure to quit? Data might not be saved.';
    };
    

    (更多…)