跳到主要内容

操作符和表达式✅

== 和 === 区别

答案
  1. == 内部调用 IsLooselyEqual 宽松比较 将不同类型的值转换为为同类型后再进行比较,
  2. === 内部调用 IsStrictlyEqual 严格比较 如果类型不同直接返回 false,类型相同再进行值比较!

宽松比较的核心类型转换规则为

  1. 原始类型比对时中 String、Boolean 都会调用 ToNumber 转换为数值后比较
  2. 对象比对时会调用 ToPrimitive 转换为原始值后在回退到规则 1 进行比较
  3. 注意一个特殊的细节,是 document.all == false 返回 ture,stackoverflow Why is document.all falsy? 了解细节
提示

这里我们以 [] == false 为例,基于规范详细说明为什么会返回 true

  1. == 比较触发内部 IsLooselyEqual 宽松比较
  2. [] 是一个对象,调用 ToPrimitive 转换为原始值
  3. ToPrimitive 首先尝试调用对象实例内部 valueOf 方法,返回 [],然后尝试调用 toString 方法,返回空字符串 ""
  4. 然后变为 "" == false 比较
  5. false 进一步调用 ToNumber 转换为数值 0
  6. "" == 0"" 调用 ToNumber 转换为数值 0
  7. 数值 0 == 0 返回 true

注意宽松比较不会抛出错误,所以规范中会递归调用直到返回一个结果,但是引擎实现时,会根据具体情况进行优化,可能会提前返回结果。

typeof 和 instanceof 的区别

答案
特性typeofinstanceof
用途判断数据类型判断实例归属关系
返回值字符串布尔值
适用范围基本类型/引用类型引用类型(对象)
局限性/注意点null 返回 "object",无法区分数组/对象不能判断基本类型,依赖原型链

总结

  • typeof 适合判断基本类型,部分引用类型(如函数),但无法区分数组和对象,null 返回 "object"
  • instanceof 用于判断对象是否为某构造函数的实例,适合引用类型,无法判断基本类型。

操作符优先级

答案

操作符优先级(Operator Precedence)决定了在表达式中多个操作符同时出现时,谁先参与运算。优先级高的操作符会比优先级低的操作符先执行。 如果没有优先级,表达式如 2 + 3 * 4 就无法确定是先加还是先乘。优先级规则保证了表达式的计算顺序符合数学和语言设计的直觉。

核心规则

  • 括号 () 拥有最高优先级,可强制改变默认顺序。
  • 一元操作符(如 !, typeof, ++, --)优先级高于二元操作符(如 +, -, *, /)。
  • 乘除(*, /, %)高于加减(+, -)。
  • 赋值操作符(=, +=, -= 等)优先级较低,通常最后执行。
  • 逻辑与(&&)高于逻辑或(||)。

常见错误

  • 忽略括号导致运算顺序错误,如 a + b * c 实际为 a + (b * c)
  • 连续赋值时,a = b = c 实际为 a = (b = c),右侧先执行。
  • 混用逻辑与或时,a || b && c 实际为 a || (b && c)

优先级表,数字越大优先级越高:

优先级(高→低)操作符说明
20()圆括号
17++, --, !, typeof一元操作符
15*, /, %乘、除、取余
14+, -加、减
13<<, >>, >>>位移
12<, >, <=, >=比较
11==, !=, ===, !==相等/不等
6&&逻辑与
5`
3=, +=, -=赋值

建议:表达式复杂时,优先使用括号明确运算顺序,避免歧义和潜在 bug。

延伸阅读

说明下面的代码运行结果

(function () {
const a = b = 3
})()

console.log('a defined? ' + (typeof a !== 'undefined'))
console.log('b defined? ' + (typeof b !== 'undefined'))
答案

运行结果是:

a defined? false
b defined? true

详细解释:

  1. const a = b = 3 这行代码其实等价于:

    • b = 3:由于没有用 var/let/const 声明,b 变成了全局变量(在浏览器环境下会挂载到 window 上)。
    • const a = ba 只是当前函数作用域内的常量。
  2. 由于整个赋值语句在一个自执行函数 (function () { ... })() 内部,a 只在函数作用域内有效,外部访问不到。

  3. b 虽然在函数内部赋值,但由于没有用 var/let/const 声明,实际上是给全局对象添加了一个属性,所以函数外部也能访问到。

  4. console.log('a defined? ' + (typeof a !== 'undefined'))

    • a 在全局作用域未定义,typeof a 返回 'undefined',所以结果是 false
  5. console.log('b defined? ' + (typeof b !== 'undefined'))

    • b 已经变成全局变量,typeof b 返回 'number',所以结果是 true

易错点提示:

  • 赋值表达式 const a = b = 3b 没有声明关键字,容易误以为 b 只在函数内有效,实际是全局变量。
  • 推荐始终使用 letconst 显式声明变量,避免污染全局作用域。

Object.is() 与比较操作符 “===”、“==” 有什么区别

答案
特性/比较方式=====Object.is()
类型转换
NaNNaN不相等不相等相等
+0-0相等相等不相等
对象比较引用地址引用地址引用地址
备注宽松相等,自动类型转换严格相等,类型和值都需相同区分 +0/-0NaN

总结

  • Object.is()=== 类似,但能区分 +0-0,且 NaN 与自身相等。
  • == 存在类型转换,通常不推荐用于判断相等性。
48%