JS 代码执行题( == 与 隐式转化)
我们先来看个例子:
var a = [0];
if (a) {
console.log(a == true);
} else {
console.log(a);
}
// 写出执行结果,并解释原因
大家猜想结果会是什么呢?
- 答案是:
false
;
为什么呢?
解析
(1) 当 a
出现在 if
的条件中时,被转成布尔值,而 Boolean([0])
为 true
,所以就进行下一步判断 a == true
,在进行比较时,[0]
被转换成了 0
,所以 0==true
为 false
数组从非primitive
转为primitive
的时候会先隐式调用 join
变成0
,string
和 boolean
比较的时候,两个都先转为number
类型再比较,最后就是 0==1
的比较了,至于为什么会调用 join
在后面剖析。
深度剖析
ToBoolean
我们先看看 ToBoolean
转化规则
当我们进行 if
判断时 会进行 Boolean([0])
转化得到的结果是 true
在进行 ==
判断
!![] //true 空数组转换为布尔值是 true,
Boolean([]) // 空数组转换为布尔值是 true
!![0]//true 数组转换为布尔值是 true
[0] == true;//false 数组与布尔值比较时却变成了 false
Number([])//0 当 Number 中 为 Object 时还会调用 ToPrimitive
Number(false)//0
Number(['1'])//1 当 Number 中 为 Object 时还会调用 ToPrimitive
我们看看 ==
判断得隐式转化规则
== 判断规则
我们先看看几个简单的例子
console.log(1 == 1);
// expected output: true
console.log('hello' == 'hello');
// expected output: true
console.log('1' == 1);
// expected output: true
console.log(0 == false);
// expected output: true
比较x
== y
,其中x
和y
是值,产生true或 false。如下进行这样的比较:
-
如果x和y引用同一个对象,则返回true 。 否则,返回false。********
-
如果x为null且y 未定义,则返回true。
-
如果x 未定义且y为null ,则返回true。
-
如果Type ( x ) 是 Number 并且Type ( y ) 是 String,则
返回比较结果x == ToNumber ( y )。 -
如果Type ( x ) 是 String 并且Type ( y ) 是 Number ,则
返回比较结果ToNumber ( x ) == y。 -
如果Type ( x ) 是 String 或 Number 并且Type ( y ) 是 Object,则
返回比较结果x == ToPrimitive ( y )。 -
如果Type ( x ) 是 Object 并且Type ( y ) 是 String 或 Number ,
则返回比较ToPrimitive ( x ) == y的结果。 -
返回假。
我们看看下面几个例子
"1" == 1; // true
1 == "1"; // true
0 == false; // true
0 == null; // false
0 == undefined; // false
null == undefined; // true
const number1 = new Number(3);
const number2 = new Number(3);
number1 == 3; // true
number1 == number2; // false
注意:
- 等式运算符并不总是可传递的。例如,可能有两个不同的 String 对象,每个对象代表相同的 String 值;操作员会认为每个 String 对象都等于 String 值
==
,但两个 String 对象不会彼此相等。例如:new String("a")
==
"a"
并且"a"
==
new String("a")
都是true
。new String("a")
==
new String("a")
是false
的。
ToPrimitive
当使用提示String调用O
的[[DefaultValue]]内部方法时,采取以下步骤:
-
令toString为使用参数 " " 调用对象O的 [[Get]] 内部方法的结果
toString
。 -
如果IsCallable ( toString) 为真,则
- 令str为调用toString的 [[Call]] 内部方法的结果,其中O作为 this值和一个空参数列表。
- 如果str是原始值,则返回str。
-
令valueOf为使用参数 " " 调用对象O的 [[Get]] 内部方法的结果
valueOf
。 -
如果IsCallable ( valueOf) 为真,则
- 令val为调用valueOf的 [[Call]] 内部方法的结果,其中O作为 this 值和一个空参数列表。
- 如果val是原始值,则返回val。
-
抛出TypeError异常。
当O
的 [[DefaultValue]] 内部方法用提示 Number 调用时,采取以下步骤:
-
令valueOf为使用参数 " " 调用对象O的 [[Get]] 内部方法的结果
valueOf
。 -
如果IsCallable ( valueOf) 为真,则
- 令val为调用valueOf的 [[Call]] 内部方法的结果,其中O作为 this值和一个空参数列表。
- 如果val是原始值,则返回val。
-
令toString为使用参数 " " 调用对象O的 [[Get]] 内部方法的结果
toString
。 -
如果IsCallable ( toString) 为真,则
- 令str为调用toString的 [[Call]] 内部方法的结果,其中O作为 this 值和一个空参数列表。
- 如果str是原始值,则返回str。
-
抛出TypeError异常。
当O
的 [[DefaultValue]] 内部方法在没有提示的情况下被调用时,它的行为就像提示是数字一样,除非O
是 Date 对象(参见 15.9.6),在这种情况下,它的行为就像提示是细绳。
本机对象的上述 [[DefaultValue]] 规范只能返回原始值。如果宿主对象实现了自己的 [[DefaultValue]] 内部方法,它必须确保其 [[DefaultValue]] 内部方法只能返回原始值。
数组中的toString
当数组调用toString
方法的时候 ,会调用内部的join
方法, 所以 [0].join("")
时变成 "0"
当我们进行 ==
判断是 此时 的 "0" == 1
对比时会遵循规则
此时又会将 "0"
转化成 0
在与1
对比 , 所以最终 返回的结果为false
解释一下Number(['1'])
执行过程
剖析Number([1]) 转化
当我们使用Number(['1'])
时调用的是valueOf 方法 、toString 、join
我们来重写valueOf
,toString
,join
看看
const orginValueOf = Array.prototype.valueOf // 保留原来的valueOf 方法
Array.prototype.valueOf = function () {
console.log("调用 valueOf")
return orginValueOf.call(this)
}
const orginTostring = Array.prototype.toString // 保留原来的 toString 方法
Array.prototype.toString = function () {
console.log("调用 toString")
return orginTostring.call(this)
}
const orginJoin = Array.prototype.join; // 保留原来的join 方法
Array.prototype.join = function () {
console.log("调用 Array.join() ")
return orginJoin.call(this)
}
const res = Number([1])
console.log(typeof res, res)// number 1
从上述例子中我们可以看出 Number([1])
依次执行 valueOf
、toString
、 join
我们看看 valueOf
的返回值
JavaScript调用valueOf
方法将对象转换为原始值。你很少需要自己调用valueOf
方法;当遇到要预期的原始值的对象时,JavaScript会自动调用它。
默认情况下,valueOf
方法由Object
后面的每个对象继承。 每个内置的核心对象都会覆盖此方法以返回适当的值。如果对象没有原始值,则valueOf
将返回对象本身。
JavaScript
的许多内置对象都重写了该函数,以实现更适合自身的功能需要。因此,不同类型对象的valueOf()
方法的返回值和返回值类型均可能不同。
对象 | 返回值 |
---|---|
Array | 返回数组对象本身。 |
Boolean | 布尔值。 |
Date | 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。 |
Function | 函数本身。 |
Number | 数字值。 |
Object | 对象本身。这是默认情况。 |
String | 字符串值。 |
Math 和 Error 对象没有 valueOf 方法。 |
你可以在自己的代码中使用valueOf
将内置对象转换为原始值。 创建自定义对象时,可以覆盖Object.prototype.valueOf()
来调用自定义方法,而不是默认Object
方法。
剖析 [1] == 1 转化规则
const orginValueOf = Array.prototype.valueOf // 保留原来的valueOf 方法
Array.prototype.valueOf = function () {
console.log("调用 valueOf")
return orginValueOf.call(this)
}
const orginTostring = Array.prototype.toString // 保留原来的 toString 方法
Array.prototype.toString = function () {
console.log("调用 toString")
return orginTostring.call(this)
}
const orginJoin = Array.prototype.join; // 保留原来的join 方法
Array.prototype.join = function () {
const result = orginJoin.call(this)
console.log("调用 Array.join() = ",typeof result ,result)
return result
}
const orginToNumber = Number; // 保留全局的 Number
window.Number = function (...arg) {
console.log("调用 Number ")
return orginToNumber(arg)
}
console.log([1] == 1) // true
从上面的结果我们可以看出[1] == 1
的过程 也会 依次执行 valueOf
、toString
、 join
最终变成 "1"
在执行内部的 ToNumber
方法 最终将 [1] ==> 1
"true" == true 的结果
肯定很多小伙伴都会觉得这个的答案是 true
然而结果并不是我们想的那样, 我们来看看他是如何转化的呢?
true
==>Number(true)
==>1
If Type(y) is Boolean, return the result of the comparison x == ToNumber(y). 2.
1
=="true"
==> 将"true"
=>Number("true")
==>NAN
If Type(x) is String and Type(y) is Number,
return the result of the comparison ToNumber(x) == y.
1
==NAN
==>false
所以最终的结果为 false
剖析 Number(1) == 1
const n = new Number(2)
const orginValueOf = Number.prototype.valueOf // 保留原来的valueOf 方法
Number.prototype.valueOf = function () {
const value = orginValueOf.call(this)
console.log("调用 valueOf","value = "+value,"typeof: "+typeof value)
return value
}
const orginTostring = Number.prototype.toString // 保留原来的 toString 方法
Number.prototype.toString = function () {
console.log("调用 toString")
return orginTostring.call(this)
}
const orginJoin = Number.prototype.join; // 保留原来的join 方法
console.log(n == 2)
我们可以 发现和前面的 Array
不同的是 Number
重写了 valueOf 方法
所以不会调用 内部的 Tostring
方法,
我们可以试着修改 Number
的valueOf
改成原来的 Object.prototype.valueOf
看看结果如何?
所以我们可以看到 Number
中是重写了valueOf
方法,所以不会调用 ToString
,直接讲 number
类型的数据返回
总结
我们在进行 ==
判断 转化式遵循以下规则即可,其实我们可以从中发现,类型不同时,最终主要都还是进行Number
转化
喜欢我的小伙伴可以 关注我的博客哦: 白鹤之家