JS逻辑运算 xxx = xxx || ''

1 常规例子

众所周知,逻辑运算符最常用于条件判断的if语句,下面是一个JavaScript的例子

var person = {
    name: '张三',
    language: 'JS',
}
if(person.language == 'JS' || person.language == 'C#'){
    console.log('录取了');
}else{
    console.log('不要');
}

输出结果:录取了


2 例外情况

直到有一天我看了前端同事的代码,发现在JavaScript里逻辑运算符竟然还可以这样用:

var person = {
    name: '张三',
    language: '',
}
var language = person.language || '什么都不会';
console.log(language);

输出结果:什么都不会


3 问题分析

什么情况,”||”运算返回的难道不应该是”true”或者”false”吗,怎么会返回一个字符串?其实我这是受了C#的影响。
C#作为一门强类型语言,逻辑运算只能用于布尔值,非布尔值必须转换为布尔值才能进行逻辑运算。而JS作为一门弱类型语言,任何类型的数据都能参与逻辑运算,在运算时会隐式转化为布尔值进行判断。

3.1 C#逻辑运算规则

&& :同真为真,只要有一个为假就返回假。
|| :同假为假,只要一个为真就返回真。

都是布尔值参与运算,结果一定返回布尔值,我下意识把这个规则也带入了JS。然而不同的是,JS非布尔值也可以参与逻辑运算,结果并不总是返回一个布尔值,所以运算规则是不能完全这么记的。

3.2 JS逻辑运算规则

&& :如果左操作数为假值则返回左操作数,如果左操作数为真值则返回右操作数。
|| :如果左操作数为真值返回左操作数,如果左操作数为假值则返回右操作数。

为什么可以用这个规则,下面引用由David Flanagan著淘宝前端团队翻译的《JavaScript权威指南》这本书的一段话:

3.2.1 解释

“&&”:
运算符返回一个“真值”或者“假值”,但并没有说明这个“真值”或者“假值”到底是什么值。运算符首先计算左操作数的值,即首先计算“&&”左侧的表达式。如果计算结果是假值,那么整个表达式的结果也一定是假值,因此”&&”这时简单地返回左操作数的值,而并不会对右操作数进行计算。

反过来讲,如果左操作数是真值,那么整个表达式的结果则依赖于右操作数的值。如果右操作数是真值,那么真个表达式的值一定是真值;如果右操作数是假值,那么整个表达式的值一定是假值。因此,当左操作数是真值时,”&&”运算符将计算右操作数的值并将其返回作为整个表达式的结果。

“||”:
它会首先计算第一个操作数的值,也就是说会首先计算左侧的表达式。如果计算结果为真值,那么返回这个真值。否则,再计算第二个操作数的值,即计算右侧的表达式。并返回这个表达式的计算结果。

这里的真值/假值并不是布尔值的意思,再次引用《JavaScript权威指南》的内容进行解释

任意JavaScript值都可以转换成为布尔值。下面这些值会被转换成false:
undefined
null
0
-0
NaN
“” // 双引号表示的空字符串
” // 单引号表示的空字符串
所有其他值,包括所有对象(数组)都会转换成true。false和上面7个可以转换成false的值有时被称作“假值”(falsy value),其他值称作“真值”(truthy value)。JavaScript期望使用一个布尔值的时候,假值会被当成false,真值会被当成true。

3.2.2 验证

简单来说,如果是非布尔值参与逻辑运算,会判断这个值转换布尔值的时候是true还是false,true表示真值,false表示假值。最后返回的并不是布尔值而是这个原始值。
我们来验证一下规则是否正确:


// && :如果左操作数为假值则返回左操作数
console.log(null && ({}));  // null 为假值,{}为真值,输出 null 
console.log(NaN && 0);      // NaN为假值,0为假值,输出 NaN

// && :如果左操作数为真值则返回右操作数
console.log(1 && undefined);    // 1为真值,undefined为假值,输出 undefined
console.log([] && 'hello'); //  []为真值,'hello'为真值,输出 'hello'

// || :如果左操作数为真值返回左操作数
console.log(1 || undefined);    // 1为真值,undefined为假值,输出 1
console.log([] || 'hello');     // []为真值,'hello'为真值,输出 []

// || :如果左操作数为假值则返回右操作数
console.log(null || ({}));  // null 为假值,{}为真值,输出 {}
console.log(NaN || 0);      // NaN为假值,0为假值,输出 0

通过验证,发现这些规则确实适用。


4 结论

4.1 与三目运算的关系

现在再去看最初的那个例子,var language = person.language || '什么都不会';其实是三目运算符的简写形式。

var person = {
    name: '张三',
    language: '',
}
var l0 = person.language || '什么都不会';
var l1 = person.language ? person.language : '什么都不会';
console.log(l0);
console.log(l1);

输出结果:

什么都不会
什么都不会


C#里也有类似的”??”写法,只不过只能用于判断字符串为null时赋予默认值。


    class Program
    {
        static void Main(string[] args)
        {
            var p = new Person
            {
                name = "张三",
                language = null,
            };
            var l0 = p.language ?? "什么都不会";
            var l1 = p.language != null ? p.language : "什么都不会";
            Console.WriteLine(l0);
            Console.WriteLine(l1);
            Console.ReadKey();
        }
    }
    public class Person
    {
        public string name { get; set; }
        public string language { get; set; }
    }

输出结果:

什么都不会
什么都不会

4.2 实际运用

“||”:通常用于给假值指定一个默认值,例如前端通过ajax向后端请求数据,返回的数据有可能是null,也有可能是”(空字符串),前端同一处理成”空字符串。
后端返回的数据为


// 后端返回数据
var result = {
    "code": 0,
    "data": [
        {
            "name": "张三",
            "language": null,
            "description": "很懒惰"
        },
        {
            "name": "李四",
            "language": "",
            "description": null
        },
        {
            "name": "王五",
            "language": "JS",
            "description": ""
        }
    ]
}
// 处理
var persons = result.data;
console.log(JSON.stringify(persons));
for (var i = 0; i < persons.length - 1; i++) {
    var person = persons[i];
    person.language = person.language || '';
    person.description = person.description || '';
}
console.log(JSON.stringify(persons));

输出结果:

[
    {
        "name": "张三",
        "language": null,
        "description": "很懒惰"
    },
    {
        "name": "李四",
        "language": "",
        "description": null
    },
    {
        "name": "王五",
        "language": "JS",
        "description": ""
    }
]
[
    {
        "name": "张三",
        "language": "",
        "description": "很懒惰"
    },
    {
        "name": "李四",
        "language": "",
        "description": ""
    },
    {
        "name": "王五",
        "language": "JS",
        "description": ""
    }
]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值