數據類型的轉換/判斷/比較

這篇博客主要包括數據類型深拷貝&淺拷貝數據類型的轉換toString()方法判斷數據相等與全等的區別。若有錯誤,歡迎指正。javascript

由於上次金山面試問了巨多這一塊的內容,因此作個總結,零碎的知識點不少。這篇原本是上週先發在掘金的,可是掘金的排版器沒有思否用着順手,之後仍是在這裏更。。。(唉出場順序過重要了,我愛思否)html

數據類型

null是對象類型仍是基本數據類java

1.基本數據類型有 numberstringbooleannullundefinedsymbol(ES6新增的),也稱原始數據類型面試

2.JS有原始值類型引用值類型
2.1 原始值類型裏面存儲的都是值,原始值類型是沒法改變的。
2.2 引用值類型指的是由多個值構成的對象。segmentfault

let str = "hello";
str[0] = "z"; //沒法修改
通常狀況下聲明的變量是對象類型的話,會在棧內存中存放着引用地址,該地址會指向堆內存中的內容。

3.JS內存分爲堆內存和棧內存,棧內存保存的都是有固定大小、空間的內容。堆內存中存儲的都是不固定的內容。數組

  • 字符串是個特例,字符串具備不變性,字符串存儲在棧內存中

4.兩者區別
4.1 原始值類型保存在棧內存中,能夠按值直接訪問。
值與值之間是獨立存在的,修改一個變量不會影響到其餘變量app

var a = 10;
var b = a; //將a的值賦給b
b = 20;
console.log(a); // 10
console.log(b); // 20

① 基本數據類型賦值過程:
函數

4.2 引用值類型存放在堆內存中,按照引用訪問。spa

  • 每新建一個新的對象,就會在堆內存中開闢一塊新的空間
  • 若是兩個變量保存的是同一個對象引用,當經過一個變量修改屬性時,另一個也會受到影響.net

    var obj = new Object();
    obj.name = "孫悟空";
    var obj2 = obj;
    obj2.name = "豬八戒";
    console.log(obj.name); //豬八戒
    console.log(obj2.name); //豬八戒

② 引用數據類型賦值過程:

5.若是兩個對象如出一轍,但也仍是兩個對象

  • 當比較兩個基本數據類型的值時,就是比較數值
  • 比較兩個引用數據類型時,比較的是對象的內存地址,對象相同,但地址不一樣,會返回false

6.null不是引用數據類型,是基本數據類型。

深拷貝、淺拷貝

1.深拷貝: 修改新變量的值不會影響原有變量的值,默認狀況下基本數據類型都是深拷貝

let num1 = 123;
let num2 = num1;
num2 = 666; // 修改新變量的值
console.log(num1); //123
console.log(num2); /666

2.淺拷貝:修改新變量的值會影響原有的變量的值,默認狀況下引用類型都是淺拷貝。

class Person{
   name = "jjj";
   age = 23;
}
let p1 = new Person();
let p2 = p1;
p2.name = "wdhj";   //修改p2的值影響了p1的值
console.log(p2.name);   //wdhj
console.log(p1.name);   //wdhj

如何實現引用數據類型的深拷貝(上)

當引用數據類型中保存的都是基本數據類型時

如下三種方法並不能實現真正意義上的深拷貝,由於對象中保存的都是基本數據類型

1.方法一(很差)
淺拷貝的緣由:多個變量指向了同一塊存儲空間,想要實現深拷貝,可讓每一個變量分別指向本身的存儲空間

class Person{
    name = "mss";
    age = 18;
 }
 let p1 = new Person();
 let p2 = new Person();
 //由於p1裏面的屬性都是基本數據類型,因此能夠取出p1的name賦值給p2
 p2.name = p1.name; 
 p2.age = p1.age;
 p2.name = "mhf";
 p2.age = 20;
 console.log(p1.name); //mss
 console.log(p2.name); //mhf

2.方法二(很差)
利用循環來遍歷每一個屬性

class Person{
    name = "mss";
    age = 18;
 }
 let p1 = new Person();
 let p2 = new Person();
 for(let key in p1){ //利用遍從來賦值每一個屬性
        p2[key] = p1[key];
    }
 p2.name = "mhf";
 console.log(p1.name);//mss
 console.log(p2.name);//mhf

3.方法三(重點)
Object的assign()方法接收兩個參數,表明含義是將p1中的全部屬性拷貝到p2中

class Person{
    name = "mss";
    age = 18;
 }
 let p1 = new Person();
 let p2 = new Person();
 Object.assign(p2,p1);
 p2.name = "mhf";
 console.log(p1.name);//mss
 console.log(p2.name);//mhf

如何實現引用數據類型的深拷貝(下)

當引用數據類型中保存的都是引用數據類型時

1.方法一:JSON.parse(JSON.stringify(obj))
2.方法二:手寫深拷貝

數據類型轉換

其餘類型 ---> 數值類型

1.Number(常量或者變量)
1.1 注意:

  • Number()沒法轉換「數字+字母」組合,會轉換爲NaN,
  • undefined也轉換爲NaN
let str = Number('123');
console.log(str); //123
console.log(typeof str); //number

1.2 轉換規則

  • 純數字字符串 --> 數字
  • 字符串中有非數字內容 --> NaN
  • undefined --> NaN
  • 空字符串/空格 --> 0
  • false --> 0
  • Null --> 0
  • true --> 1

2.數學運算符中的「+」、「-」
2.1 注意:

  • 「+」、「-」均可以將其餘類型轉換爲數值類型,可是「-」會改變數值的正負性
  • 「+」、「-」底層上調用了Number()函數
  • 「+」、「-」沒法轉換「數字+字母」組合
  • 任何值作「-」、「*」、「/」運算都會自動轉換爲Number類型
let str = "123";
let num = +str;
console.log(num); //123
console.log(typeof num); //number

3.parseInt(字符串)和parseFloat(字符串)
3.1 注意:

  • parseInt()和parseFloat()都會從左至右提取數值,一旦遇到非數值就會中止,返回NaN
  • parseInt()和parseFloat()都會將傳入的數據先轉爲string類型,再操做
let res = true;
// let res = "true";
let num = parseInt(res); //把true當作字符串處理,沒有遇到數字因此返回NaN
console.log(num); //NaN

其餘類型 ---> 字符串類型

1.toString()
Number、Boolean類型可調用toString()轉換爲String類型

格式:變量名稱.toString()
注意:

  • toString()是對拷貝的數據進行轉換,所以不會影響原有的數據
  • 不能使用常量直接調用toString()方法
  • null和undefined不能夠調用toString()方法
let value = 123;
let str = value.toString();
console.log(str); //123
console.log(typeof str); //string

console.log((3).toString()); //影響原有的數據

2.String()方法

格式: String(常量or變量)
注意:

  • String(變量or常量)能夠轉換常量,由於是根據傳入的值從新生成一個新的值,並不會修改原有的值
  • 常量能夠直接使用String()方法
  • String()能夠用來轉換null,undefined
let res = String(3);
console.log(res); //3
console.log(typeof res); //string

let str = String(undefined);
console.log(str); //undefined
console.log(typeof str); //string

3.常量/變量 + 「」

利用 常量/變量 加上一個空字符串來轉換,本質上是調用了String()函數, 不會修改原有的值

let value = 123;
let str = value + '';
console.log(str); //123
console.log(typeof str); //string

其餘類型 ---> 布爾類型

Boolean(變量or常量)

注意:

  • 只要字符串中有內容就會轉換爲true,只要字符串的沒有內容纔會轉換false
  • NaN、0會轉換爲false
  • undefined、null會轉換爲false

總結:
空字符串/0/NaN/undefined/null會轉換成false


toString方法判斷數據類型

1.undefinednull沒有toString()方法

console.log(undefined.toString()); //報錯
console.log(null.toString()); //報錯

2.NumberBooleanString等包裝對象的toString()方法;本地對象的toString()方法

console.log(Number.toString()); //function Number() { [native code] }
console.log(Boolean.toString()); //function Boolean() { [native code] }
console.log(String.toString()); //function String() { [native code] }

console.log(Function.toString()); //function Function() { [native code] }
console.log(Array.toString()); //function Array() { [native code] }
console.log(Object.toString()); //function Object() { [native code] }
console.log(RegExp.toString()); //function RegExp() { [native code] }
console.log(Date.toString()); //function Date() { [native code] }

3.整數直接跟上.toString()形式會報錯,提示無效標記,由於整數後的點會被識別爲小數點

  • 解決:
    ①用括號將整數括起來
    ② 或者使用兩個..
    ③ 若是僅僅是數據轉換,能夠利用String()方法
console.log(3.toString()); //報錯
console.log((3).toString()); //3
console.log(3..toString()); //3
let res = String(3);
console.log(res); //3

4.Object.prototype.toString()來進行類型識別,返回表明該對象的[object Type]字符串表示

  • 注意:雖然每一個對象都繼承了toString()方法,可是不能直接使用,由於對象有可能直接重寫了此方法,必須使用call()或者apply()調用
console.log(Object.prototype.toString.call("abc")); //[object String]
console.log(Object.prototype.toString.call(1)); //[object Number]
console.log(Object.prototype.toString.call(true)); //[object Boolean]
console.log(Object.prototype.toString.call(null)); //[object Null]
console.log(Object.prototype.toString.call(undefined)); //[object Undefined]
console.log(Object.prototype.toString.call({})); //[object Object]


console.log(Object.prototype.toString.call(function(){}));//[object Function]
console.log(Object.prototype.toString.call([]));//[object Array]
console.log(Object.prototype.toString.call(/\s/)); //[object RegExp]
console.log(Object.prototype.toString.call(new Date));//[object Date]
function Person(){}
console.log(Object.prototype.toString.call(new Person));//[object Object]

5.除了類型識別以外,還能夠進行其餘識別,例如識別arguments或DOM元素

(function(){
    console.log(Object.prototype.toString.call(arguments));//[object Arguments]
})();
console.log(Object.prototype.toString.call(document));//[object HTMLDocument]

6.數組Array類型調用toString()方法,返回由數組中每一個值的字符串形式拼接而成的一個以逗號分隔的字符串

console.log([1, 2, 3, 4].toString()); //1,2,3,4
console.log([].toString()); // 輸出空

這時咱們能夠用這個思路來將多維數組轉爲一維數組,注意數組中的每一項變爲字符串了

let arr = [1,[2,[3,4],5],6];
// console.log(arr.join(",").split(","));
console.log(arr.toString().split(","));

"==" VS "==="比較數據

"=="相等運算符

1.兩個值類型相同
若是兩個值類型相同,再進行三個等號(===)的比較, 與嚴格相等運算符徹底同樣。

2.兩個值類型不一樣
在比較不一樣類型的數據時,相等運算符會先將數據進行類型轉換,而後再用嚴格相等運算符比較。類型轉換規則以下:
(1) 原始類型值比較
原始類型的數據會轉換成數值類型再進行比較
① 若是有一個操做數是布爾值,則在比較相等性以前先將其轉換爲數值; false轉換爲0,而true轉換爲1
console.log(true == 1); //true
② 若是一個操做數是字符串,另外一個操做數是數值,在比較相等性以前先將字符串轉換爲數值
console.log('123' == 123);//true
(2) 對象與原始類型值比較
若是一個操做數是對象,另外一個操做數不是,則調用對象的toString()方法,用獲得的基本類型值按照前面的規則進行比較

console.log([] == 0); //true
console.log([].toString()); //空

console.log({} == 0); //false
console.log( {}.toString()); //[object Object]

(3) undefined和null的比較
undefined和null與其餘類型的值比較時,結果都爲false,它們互相比較時結果爲true。

console.log(null == undefined); //true

console.log(undefined == 0); //false
console.log(null == 0); //false

console.log(undefined == undefined); //true
console.log(null == null); //true

(4) NaN的比較
若是有一個操做數是NaN,則相等操做符返回 false; 兩個操做數都是NaN,相等操做符也返回 false, NaN不與任何數相等, NaN不等於NaN

console.log(NaN == 0); //false
console.log(NaN == NaN); //false

(5) 兩個對象的比較
若是兩個操做數都是對象,則比較它們是否是同一個對象。
① 若是兩個操做數都指向同一個對象,則相等操做符返回 true;不然, 返回false
② 對於引用類型的數據,比較的是地址

console.log([] == []); //false
console.log({} == {}); //false

let a = [];
let b = a;
console.log(a == b); //true

3.多益筆試題

console.log('' == 0); //true
空串轉爲數字爲0

console.log([] == 0); //true
[]調用toString()返回空串,再轉爲數字爲0

console.log({} == 0); //false
{}調用toString()返回[object Object],再轉爲數字爲NaN

4.很繞的一題
(剛剛原本寫了很詳細的解析,沒保存,此次不想再寫了。)
關鍵在於:
!可將變量轉換成boolean類型,null、undefined、NaN以及空字符串('')取反都爲true,其他都爲false。
{}調用toString()返回[object Object],再轉爲數字爲NaN

console.log([] == ![]); //true
console.log(![]); //false
至關於
console.log([] == 0); //true

console.log({} == !{}); //false
console.log(!{}); //false
至關於
console.log({} == 0); //false

"==="全等運算符

(相比起來,全等運算符就沒有那麼多條條框框了,相等運算符整理到吐血)
(1)若是類型不一樣,就必定不相等
(2)若是兩個都是數值,而且是同一個值,那麼相等;若是其中至少一個是NaN,那麼不相等。(判斷一個值是不是NaN,只能使用isNaN( ) 來判斷)
(3)若是兩個都是字符串,每一個位置的字符都同樣,那麼相等,不然不相等。
(4)若是兩個值都是true,或者兩個值都是false,那麼相等
(5)若是兩個值都引用同一個對象或是函數,那麼相等,不然不相等
(6)若是兩個值都是null,或者兩個值都是undefined,那麼相等

顯示轉換 VS 隱式轉換

顯式轉換的數據類型

1.將非數值轉換爲數值類型的函數

  • Number():Number(mix),能夠用於任何數據類型,該函數先將mix的數據類型轉換爲number類型,而後再將mix的值轉換爲數值。
    若mix的值能直接轉換成數字,則直接顯示。若不能則顯示0或NaN.
  • parseInt():將字符串轉換爲數值,不遵循四捨五入。這裏的string必須是數字類型的開頭字符串,一直遍歷到非數值的那個字符才中止。若不是數字開頭,則會顯示NaN.
  • parseFloat():將string轉換爲浮點數。從數字位開始看,直到非數字位結束,用法與parseInt(string)一致。

2.將其它類型的數據轉換爲字符串類型的函數

  • String(mix):將mix轉換成字符串類型。該函數能夠將任何數據類型的值轉換爲字符串。
  • toString()demo.toString()將demo轉換成字符串類型。demo不能是null undefined

3.將值轉換成布爾值類型
Boolean()方法把undefined、null、-0、+0、NaN、''(空字符串)六個值的轉化爲false,其餘的值所有爲true。

隱式的數據類型轉換

隱式類型的轉換是系統進行運算時自動進行的,可是調用的方法都是顯式類型轉換的方法。

1.遞增和遞減操做符
不只適用於整數,還能夠用於字符串、布爾值、浮點數值和對象。
即先將變量經過Number()轉換成number的數據類型,而後再進行遞增、遞減操做。

2.正負號
不只適用於整數,還能夠用於字符串、布爾值、浮點數值和對象。
將變量經過Number()轉換成number的數據類型。

3.isNaN(變量)
執行過程爲:即先將變量經過Number()轉換,再進行isNaN()判斷 。

4.加號
加法有兩個做用。

  • 若是沒有運算過程當中沒有字符串時,就將變量經過`Number()轉換爲number類型後,再進行運算。
  • 若是有字符串的話,加號兩邊起的就是字符串鏈接做用。

5.- * / % (減號,乘號,除號,取餘)
運算時把數據轉換成number類型後,再進行運算。

6.&& || ! (與或非運算)
將運算符兩邊的值轉換成經過Boolean()函數轉換成布爾類型,而後再進行運算。
不一樣的是:&& || 返回的是比較後自身的原值,而 !運算返回的是布爾值.

7.< > <= >= == != 比較運算符
當數字和字符串比較大小時,會隱示將字符串轉換成number類型進行比較。
而當字符串和字符串比較大小時,則比較的是ascii碼的大小。最後返回的則是布爾值

幾道很適合放這裏的題

1.

var str = 1 + 2 + 'abc';
console.log(str); //3abc

2.

var a;
var b = a * 0;
//console.log(b); //NaN
//console.log(b === b); //false
if(b === b){
    console.log(b * 2 + "2" - 0 +4)
}else{
    console.log(!b * 2 + "2" - 0 +4)
} //26

3.

var a = 1;
//console.log(a); //1
var b = a * 0;
//console.log(b); //0
if(b === b){
  console.log(b * 2 + "2" -0 + 4)
}else{
  console.log(!b * 2 + "2" - 0 +4)
} //6

4.涉及精度問題

var a = 1.0 - 0.9;
if(a == 0.1){
  console.log(true);
}
else{
  console.log(false);
} // false

var b = 0.8 - 0.7;
if(a == b){
  console.log(true);
}else{
  console.log(false);
} // false

本文參考連接:
toString()方法的討論參考到了這篇:
https://www.cnblogs.com/xiaoh...

==&===的比較參考了這兩篇:
http://javascript.ruanyifeng.com/grammar/operator.html#toc6
https://blog.csdn.net/magic_xiang/article/details/83686224

參考圖片來自:博主:cc_ccc

相關文章
相關標籤/搜索