無標題文檔

Javascript 每日测试 - 第六期

这期的问题是

// 请问如下 alert 语句依次弹出的是什么?
alert('' == '0'); 
alert('' == false); 
alert('0' == 0);
alert('\n' == 0); 
alert(null == false); 
alert(null == undefined); 

此道题目的解释可以参考 《PPK on Javascript》 上的解释 -- form 玉伯:

These are the rules for converting other data types to booleans:

The values null and undefined become false.
The numbers 0 and NaN become false.
An empty string '' becomes false.
All other values become true.

在这里需要注意的是这句

An empty string '' becomes false. 

「empty string」 的含义包括不可见字符(\"\n \t \v\" 等),所以极端上考虑 alert(\"\n \t \v\" == 0) 这个也是 true 。

此道题目的最后答案是 false、true、true、true、false、true 。因此,「在不明确强制类型转换(或者要求判断结果比较高)时,尽量使用 === 替代 == 」 -- form 小马 。

-- Split --

另,外加一道 玉伯 的题目:

var testObj = {
    alert: function() { alert('2'); },
    init: function(el) {
        YAHOO.util.Event.on(el, 'click', function() {
            this.alert('1'); // ?
            (function() { this.alert('1'); })(); // ?
            (function() { this.alert('3'); }).call(this); // ?
        }, null, this);
    }
};

testObj.init(document);
// 问题: 点击 document,alert 依次输出什么?

这道题目需要注意三点:

  1. YAHOO.util.Event.on(el, eventType, fn, obj, override) 最后两个参数的使用
  2. 匿名函数中,this === window
  3. call 和 apply 的使用

最后答案为 「2, 1, 2」,相关参考资料:

再次考虑 Explorer6 的 PNG Alpha 支持

众所周知,由于 Explorer7 以下的版本对于透明 PNG 的支持非常的不完善。这个问题甚至在一定的程度上,影响了 PNG 格式在 Web 中的使用。

所幸的是,已经有部分的解决方案,那就是「以毒攻毒」使用 Microsoft 的私有滤镜详细 )。

用到 PNG 图片通常有两种方式,分别是图片和背景。在插入 PNG 图片方面,hack 的方法就是使用脚本将原图替换成原图,然后将 img 的 src 属性指向透明的 gif 文件(撑位置)。而在使用 PNG 背景中,就会有些许的问题。

根据官方的文档 ,对于 AlphaImageLoader 的描述如下:

AlphaImageLoader Filter

Displays an image within the boundaries of the object and between 
the object background and content, with options to clip or resize 
the image. When loading a Portable Network Graphics (PNG) image, 
tranparency—from zero to 100 percent—is supported. 

是的,我们 hack 时候加入的图片是处于背景(background)和内容(content)之间的一层。所以滤镜代替使用背景,不能完全实现背景的功能,比如 background-position 以及 background-repeat 等(如有解决的方案,请告知)。

综合上面所述,可以查看 DEMO 。jQuery 方面已经有个名叫 ifixpng 的插件

加入滤镜非常耗费系统资源的,尤其是处理大量图片的情况下。目前已知的情况下,可以使用两种方式载入脚本,第一种就是传统的 Javascript,第二种我也是后来才得知,就是使用 Explorer 的私有属性 behavior CSS 方法( 详细 )。

就个人的观点谈下这两种方法。首先使用传统的 Javascript 方法需要更改结构(加入 script 标签),而 behavior 方法则在 CSS 中指定,并不需要更改结构。同时,behavior 能更好的控制需要渲染的节点(使用 CSS 选择器)。

但 behavior 方法与 CSS expression 一样,需要注意效率问题(由于是 Explorer 属性,效率未知)。并在现有的情况下,CSS 的编写人员可能会对 behavior 方法感到迷惑。

总之,个人认为对于视觉效果方面的 Hack ,能不添加无谓的结构就不添加。正如上面的 behavior 属性可能会造成迷惑一样,在结构中加入某条 script 标签同样会使人迷惑,这是种博弈。

参考资料(部分链接已在文中提及)

-- Split --

后记,在实际测试可能性方案中,发现这两种载入方式的效率不尽相同。在使用 behavior 载入时,页面有明显的载入状态提示,如图

https://friable.rocks/_/2009_11_05/339925d94b8e.jpg

但是用 fidder 追踪发现并没有循环请求数据,如图

https://friable.rocks/_/2009_11_05/531065d94b8d.jpg

虽然出现此现象的原因未知,个人认为 Javascript 载入方式为统一循环渲染,而使用 behavior 时为使用 CSS 选择器获得,它是逐步渲染(了解明确原因的兄弟请告知,谢谢)。

而上述的测试可能有点极端 -- 我添加了 200 个节点。在日常的页面中,使用 behavior 属性情况不大(少于 10 个)、但背景要求质量很高(必须是 PNG,且还有透明)的情况下,还是可以考虑 behavior 属性的。

在 Explorer6 还未完全退出市场之前,加入条 CSS 语句就能解决透明 PNG 的问题(再加上针对 Explorer6 的 hack,其他版本的 Explorer 不受影响),也甚为方便。

Javascript 每日测试 - 第五期

今天的问题是

请问以下 alert 弹出值分别是什么?

var f = function f2() {
    return arguments.callee;
}

alert(f === f2);
alert(f === f());
alert(f() === f2());

让我们回顾 callee 的用法, Mozilla 官方的相关描述 如下:

callee is a property of the arguments local variable available
within all function objects; callee as a property of Function.arguments
is no longer used. (Function.arguments itself is also deprecated.)

arguments.callee allows anonymous functions to refer to themselves, 
which is necessary for recursive anonymous functions.

The this keyword does not refer to the currently executing function. 
Use the callee property to refer to a function within the function body. 

在 Javascript 中,一般定义某个函数有两种方式,分别是 function f() {...} 以及 var f = function () {...} 。同时,在 Javascript 中,函数可以当变量使用(Javascript 允许你结合两种方式使用,虽然这样的代码出现较少)。

var f = function f2() {
    return arguments.callee;
}

上面的代码可以分解为

function f2() {
    return arguments.callee;
}

var f = f2;

分解后的代码可以认为 f 与 f2 相同(==),但是进一步的理解他们并不完全相同(===)。调用 f() 与 f2() 执行获得的结果一样,「但 f2 这个变量保存了函数的整个内容,f 是对 f2 函数的引用」 -- form 丁坚。

其实这样的写法很少见,并不推荐在实际的项目中这样编写。说完上面的问题,回到我们的题目中。从上面的 Mozilla 的说明中可得知,arguments.callee 引用的是当前正在执行的函数本身。

所以,由此可以推断 alert(f === f()); 返回的是true;同理 f2 === f2() 返回的也是 true 。f() 返回的就是 f, f2() 返回的就是 f2, 所以第三个 alert() 等同于第一个 alert() 语法, 返回的也是 false 。

所以,本日 Javascript 测试的答案为:false、true、false 。

那么 arguments.callee 有无实际的用途?回答是肯定的。在匿名函数用得越来越多的情况下,很多时候 arguments.callee 能帮上大忙。

比如,希望某事件只执行一次,那么可以这样做(使用 YUI 框架):

YAHOO.util.Event.on(button, 'click', function(ev) {
    // ...
    // 注销自己
    YAHOO.util.Event.removeListener(button, 'click', arguments.callee);
});

YAHOO.util.Event.removeListener 的详细说明 参见这里 。我们给某个按钮注册了一个事件,时间处理器是一个匿名函数,点击一次以后,通过 removeListener 和 arguments.callee,就可以自我注销。

补充 -- form 玉伯

「也可以这样写就用不到 arguments.callee」,但这样代码感觉稍许冗余:

YAHOO.util.Event.on(button, 'click', function fn(ev) {
    // ...
    // 注销自己
    YAHOO.util.Event.removeListener(button, 'click', fn);
});

其次,arguments.callee 还有一个重要的用途,就是在递归,比如:

function factorial(n) {
    if (n <= 0) {
        return 1;
    } else {
        return n * arguments.callee(n - 1);
    }
}

参考资料:

--EOF--

我的照片

嗨!我叫「明城」,八零后、码农、宁波佬,现居杭州。除了这里,同时也欢迎您关注我的 GitHubTwitterInstagram 等。

这个 Blog 原先的名字叫 Gracecode.com 、现在叫 「無標題文檔」 。 要知道作为码农取名是件很难的事情,所以不想在取名这事情上太费心思。

作为八零后,自认为还仅存点点可能不怎么被理解的幽默感,以及对平淡生活的追求和向往。 为了避免不必要的麻烦,声明本站所输出的内容以及观点仅代表个人,不代表自己所服务公司或组织的任何立场。

如果您想联系我,可以发我邮件 `echo bWluZ2NoZW5nQG91dGxvb2suY29tCg== | base64 -d`

分类

搜索

文章