让JavaScript来扩展思路

By zhujinliang. Filed in 软折腾  |   
标签:
Home  

JavaScript是门很有意思的语言。基于JavaScript的一些语言特性,有一些很有意思的用法。

<1> ||运算符

举例:

var wantFruit = apple || "pear's ok";


意思是,如果apple不存在或不可用(后面详细解释),则取用"pear’s ok"。

这是一个经典的写法,通常用在为参数提供默认值的情况。例如下面这个程序,如果我们不提供unit参数,函数会使用默认的’cm’作为单位:

function showLength(length, unit){
    alert('length is: '+length+(unit||'cm'));
}


我们还可以进行扩展:

var wantFruit = apple || pear || ... || grape;

如果apple存在且可用,则取用apple,否则尝试取用pear,…,grape。通常的使用场景是,比上一个例子多一个配置项的情况,即用户未提供参数时,再检查配置项是否提供,均失败的情况下则使用默认值。

想想在别的语言中,这种操作通常需要一大堆的 if … else if … else 来实现,这样感觉是不是很爽呢。

有意思的是,这样写,在人类语言上表达地也很自然,“苹果或者梨或者…或者葡萄”。

原理:

1. || 是逻辑或运算操作符,即运算符两侧中,有一方为逻辑真,则返回真,两侧均为假时才返回假。

2. 系统在处理逻辑或运算中,如果运算符左侧为真,我们此时可以断定结果肯定为真,而不必去检查运算符右侧是否为真。几乎所有语言都是这样的。

3. 一般的语言,|| 操作返回值为逻辑型,非假即真,而JavaScript的 || 操作返回值为假或参与运算的原值。JavaScript的这个特性起到关键的作用,否则例子中的wantFruit只能是 true 或 false,无法读取到原来的变量值了。

局限性:

整个操作中还利用JavaScript的隐式转换规则,即我们输入的inputVal或valn先是被隐式转换为逻辑型,然后进行判断处理。如果我们需要的值却在隐式转换中被认为是假,则无法得到我们想要的结果。这通常发生在“0或空字符串也是我们允许获得的结果”这样的情况时,因为JavaScript认为0或空字符串也是假的。这即上文中所说的“可用”。

在这种情况时,我们只得老老实实地用 if typeof(inputVal) == ‘undefined’ 这样的写法来处理。或者是数值的话,取巧一下,先对该数字加1,然后进行判断,最后减去1。

<2> &&运算符

举例:

var wantRoom = hotel && hotel.room302;


意思是,如果hotel存在或可用,则取用hotel.room302。通常用在不确定某对象是否存在,且要取出该对象的某个属性时,万一该对象不存在,我们试图读取其属性时将产生错误。

同样可扩展,但明显可读性将变得很差:

var wantRoom = hotel && hotel.floor3 && hotel.floor3.room302;

如果层级很多,使用这样的方法将会很繁琐,简便的办法是使用try … catch。

还有个应用场景,比上面所举的这个例子漂亮很多:

onSomeEvent && onSomeEvent();

通常在写模块或类时,当需要产生一个事件时,我们又不确定使用这个模块或类的用户是否绑定了事件处理函数,需要调用前检查一下,如果用户没有绑定,我们就不进行调用了。等同于 if(onSomeEvent) onSomeEvent();

原理:

1. && 是逻辑与运算操作符,即运算符两侧均为逻辑真,则返回真,否则返回假。

2. 与 || 类似。系统在处理逻辑与运算中,如果运算符左侧为假,我们此时可以断定结果肯定为假。

3. 与 || 类似,JavaScript的&&操作返回值为假或参与运算的原值。

局限性:

与 || 类似,也需要注意JavaScript隐式转换规则。不过在我们通常的使用环境中,几乎不会碰到此种情况。

<3> 类型转换的简便写法

举例:

var valString = anyVal + '';


作用是将任意类型转换为字符串。JavaScript很多情况下可以自动将变量转换为字符串,比如执行alert时,除此之外,几乎所有对象均提供 toString 方法,可以转换为文本。但是相比使用toString,这样写显得较为“节约”,而且类似很多写法很多人在用,不大会产生理解障碍,在JavaScript的世界里,省字就是真理。

var valBool = !!anyVal;

作用是将任意类型转换为逻辑型。这种写法我最早见于jQuery库里,虽然很不常用,但需要时不失为一种好做法。

两个例子的写法可能带来性能影响,但可以说微乎其微,而且可能编译器会对其进行优化,故完全没有必要担心。

原理:

JavaScript隐式转换规则,对于相加运算,如果一侧为字符串,另一侧不是字符串,则将其转换为字符串,再将两个字符串拼接起来。对于逻辑非操作,必定先将其转换为逻辑型再取反。详细参考ECMAS文档。

<4> 使用对象代替switch结构

举例:

var chinese = {one:'一', two:'二', three:'三', four:'四', five:'五', six:'六', seven:'七', eight:'八', nine:'九', zero:'零'}[inputEnglish];

在其他语言中,对于类似输入一个英文数字的单词转换为汉字的操作,因为选项不是很多,我们通常会用switch结构,而选项较多时,我们会考虑使用字典。而在JavaScript中,字典伴随语言特性嵌入其中,我们可以方便地将对象作为字典使用,所以,尽情使用吧。

还可以这样用:

if({apple:1, pear:1, banana:1, grape:1}[inputName]){
    alert(inputName + ' 在列表中');
}

如果我们输入apple,pear,banana或grape,则会提示其在列表中,输入其他的则不会提示。

原理很简单,我们输入的单词作为键名去查询前面创建的这个对象:{apple:1, pear:1, banana:1, grape:1},如果对象中存在对应的键,则取出其值,即1,如果没有对应的键,则返回undefined。在if判断时,根据转换为逻辑型的规则,1被认为是真,undefined被认为是假,故区分出是否在列表中。

这里我们将其设置为 1,是因为 1 较 true 等值都短的原因,还是出于节约的考虑。

如果使用 || 来写,则是:

if(inputName == 'apple' || inputName == 'pear' || inputName == 'banana' || inputName == 'grape'){
    alert(inputName + ' 在列表中');
}

很是繁琐。使用switch也较为繁琐:

switch(inputName){
    case 'apple':
    case 'pear':
    case 'banana':
    case 'grape':
        alert(inputName + ' 在列表中');
}

可见,对于判断某一个输入值,或某一个状态值,是不是在我们所期望的若干值里面时,这样写是很方便的。

<5> 取重复文本

举例:

var repeatString = Array(9).join('abc');

代码会将’abc’重复8此,如果你需要重复n次,将代码里的数字换成n+1即可。

原理:Array(n)用于创建一个数组,数组含有n个元素,每个元素初始都是undefined;join方法用于将该数组中的元素连接在一起,并使用第一个参数提供的文本作为分隔符。

实际输出的是:undefined + ‘abc’ + undefined + ‘abc’ + … + undefined +’abc’ + undefined;

undefined转成文本后为空文本,便得到了重复文本的效果。

———–

待续。以后在使用JavaScript的过程中,如果再遇到有趣的写法时,我会继续在这里与大家分享。

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

*