JavaScript隱式類型轉換例子總結
前言
熟練掌握類型轉換,理解其中的規(guī)律。可以讓你的代碼更簡潔更安全。
在編寫代碼的時候,我們通常會有意無意的寫出一些,存在類型轉換的代碼。這些代碼有時的返回值總讓人迷惑,比如下列式子都是我們工作中常見的:
var a = 1; var b = '2'; var c = a + b; // '12'; var d = 43; d == '43'; // true d === '43'; // false
上面都是比較常見的,讓我們再看幾個例子:
// 例子1 const obj = { toString() { return : 'xxx'; } } const obj2 = {}; obj.toString(); // "xxx" 當然,我們還是可以使用Object.prototype.toString.call(obj)的,因為這是調用了Object對象,但是如果改寫了Object的toString方法,那情況就不一樣了。 obj2.toString(); // "[object Object]" // 例子2 const a = [1,2,3]; const b = [4,5]; a + b; // "1,2,34,5" // 例子3 false == []; // true false == ""; // true false == null; // false false == undefined; // false [] == ![]; // true
看到上面的結果,是否你也感覺頭疼?,F(xiàn)在讓我們開始探索,看看這中間都發(fā)生了怎樣的類型轉換。
在講強制類型轉換是我們先思考一個問題,不同的數(shù)據(jù)類型值都會發(fā)生什么類型轉換?在什么情況下會發(fā)生類型轉換?具體是怎么轉換的?
發(fā)生了類型轉換通常都是操作值做了【抽象操作】(ES5規(guī)范第9節(jié)中定義了一些“僅供內部使用的操作”)。這里我們簡單介紹一下ToString
,ToNumber
,ToBoolean
同時還有一個ToPrimitive
。
ToString
ToString
是對非字符串進行強制類型轉換。
- 對于基本數(shù)據(jù)類型,ToString則是進行字符串化,null轉化為"null",undefined轉化為"undefined",true轉化為"true"。對于數(shù)字的ToString,需要注意的是,數(shù)字的極大值跟極小值會轉為指數(shù)形式表示。
var a = 1.07 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000; a.toString(); // "1.07e21";
- 對于引用數(shù)據(jù)類型的ToString,通常會調用引用對象中的 toString()進行轉化,如果對象沒有這個方法則會發(fā)生報錯。(注意:從ES5開始,使用Objest.create(null)創(chuàng)建的對象,因為創(chuàng)建對象的
[[Prototype]]
為null,所以不會有toString()和valueOf()這兩個方法)。
var a = [1,2,3,4]; a.toString(); // "1,2,3,4" var b = { a: 42, foo: 'foo' } b.toString(); // "[object Object]"
ToNumber
- 對基本數(shù)據(jù)類型,ToNumber跟調用Number轉數(shù)字一樣。
Number(true); // 1 Number(false); // 0 Number(null); // 0 Number(undefined); // NaN Number(""); // 0 Number("123"); // 123 Number("123aaa"); // NaN
- 對于引用數(shù)據(jù)類型,會先判斷對象是否有valueOf(),如果有則將返回的值進行類型轉換。如果沒有,則判斷是否有toSrting(),并將其返回值做類型轉換。如果這兩個方法都沒有則報錯TypeError。
var a = { valueOf() { return "42"} }; var b = { toString() { return "42"} }; var c = [1,2]; c.toString = function() { return this.join(""); } Number(a); // 42 Number(b); // 42 Number(c); // 12 Number([]); // 0 Number([1,2]); // NaN
ToBoolean
對于抽象操作ToBoolean
,ES5規(guī)范9.2中列出一些假值,既對這些值進行布爾強制類型轉換時,會轉為false的值。除了這些值以外,所有值進行強制類型轉換時,都會得到true。
undefined null "" // 空字符串 +0, -0, NaN false
ToPrimitive
抽象操作ToPrimitive
,其實在ToSting
,ToNumber
,ToBoolean
獲取對象原始值的時候,就是通過ToPrimitive
來獲取的,獲取完原始值之后,再進行toString(),Number(),Boolean()等類型轉換。
總結,在對值進行類型轉換時,如果是基本數(shù)據(jù)類型,則直接對使用該值進行類型轉換;如果是引用類型,會先通過ToPrimitive
獲取原始值,然后使用獲取的原始值進行類型轉換。
而之前說的【先檢查對象是否包含valueOf()
,如果沒有在檢查toString()
】這個過程就是 ToPrimitive
。
現(xiàn)在我們分析完類型轉換的過程都具體做了什么操作了,現(xiàn)在我們看下,在那些操作下會發(fā)生類型轉換。
運算符 +
如果操作數(shù)中存在字符串,則進行字符串拼接;如果操作數(shù)是對象,則會對對象進行 ToPrimitive
抽象操作以獲取原始值,通常這操作都會獲取到字符串。最后進行 + 操作。
var a = [1,2]; var b = [3,4]; a + b; // "1,23,4"
邏輯判斷相關
- if(..)
- while(..)和do..while(..)
- 三元表達式 ?:
- for(..; ..; ..){}
- 邏輯或|| 和 邏輯與&& 左邊的操作數(shù)
上面的語句中所包含的判斷表達式,都會將非布爾值通過抽象操作ToBoolean
,將值轉為boolean。
== 寬松對等規(guī)則
1. 字符串和數(shù)字之間的相等比較
- 如果Type(x)是數(shù)字,Type(y)是字符串,則返回 x === ToNumber(y)的結果。
- 如果Type(x)是字符串,Type(y)是數(shù)字,則返回 ToNumber(x) === y的結果。
var x = 42; var y = '42'; x === y; // false x == y; // true 這里轉換為: 42 == ToNumber('42') => true
2. 其他類型和布爾類型的相等比較
- 如果Type(x)是布爾類型,則返回 ToNumber(x) === y 的結果。
- 如果Type(y)是布爾類型,則返回 x === ToNumber(y)的結果。
var x = true; var y = '42' x === y; // false x == y; // false // false 這里轉換為:toNumber(true) == toNumber('42') => 1 == 42 => false
3. null 和 undefined 之間的相等比較
- 如果x為null,y為undefined,則結果為true。
- 如果x為undefined,y為true,則結果為true。
注意: 在 == 中null和undefined相等(也與自身相等),除此之外其他值都不和他們相等。 所以可以使用一特性,對值進行判斷是否等于null或undefined
var x = null; var y; x === y; // false x == y; //true
4. 對象和非對象之間的相等比較
- 如果Type(x)是字符串或數(shù)字,Type(y)是對象,則返回 x == ToPrimitive(y)的結果。
- 如果Type(y)是字符串或數(shù)字,Type(x)是對象,則返回 ToPrimitive(x) == y的結果。
var a = 42 var b = [42] a == b; // true // [42]調用ToPrimitive,返回"42",變成 "42" == 42,然后又變成 42 == 42,最后兩者相等。 var a = "abc"; var b = Object(a); // new String( a )一樣 a === b; // false a == b; // true
這里有些值不一樣
var a = null; var b = Object(a); // 和Object()一樣 a == b; // false var c = undefined; var d = Object(c); // 和Object()一樣 c == d; // false var e = NaN; var f = Object(e); // 和new Number(e) 一樣 e == f; // NaN == NaN => false
因為js中,沒有undefined 和 null 對應的封裝對象。所以對他們進行Object封裝跟調用Object()一樣,返回一個常規(guī)對象。
而NaN是因為,NaN本身就不等于自己。
總結
總的來說:在寬松對比中,對比的值具有這樣的轉換優(yōu)先級,對象 > 非對象(非對象中:字符串,布爾都會ToNumber轉為數(shù)字,進行比較)
。同時需要注意 NaN(唯一不等于自己的值),undefined和null這幾個值的轉換。
當然,寬松對等中不同值對比,才會進行類型轉換。如果是相同類型的比較,不會進行類型轉換。"0" == "" 返回false
。因為這是字符串"0"
和""
的對比,不會進行抽象操作ToNumber
。
理解了對象的類型轉換都是ToPrimitive
操作,那么我們需要注意,任何情況下都不要重寫對象的 valueOf()
和toString()
方法。
到此這篇關于JavaScript隱式類型轉換例子總結的文章就介紹到這了,更多相關JS隱式轉換內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
JS實現(xiàn)仿google、百度搜索框輸入信息智能提示的實現(xiàn)方法
這篇文章主要介紹了JS實現(xiàn)仿google、百度搜索框輸入信息智能提示的實現(xiàn)方法,實例分析了javascript實現(xiàn)智能提示功能的技巧,非常具有實用價值,需要的朋友可以參考下2015-04-04