JS高級學習筆記(1)- 基本數據類型 和 強制類型轉換

必讀:html

Javascript對象Oject的強制類型轉換面試

JavaScript築基篇(二)->JavaScript數據類型segmentfault

聊一聊valueOf和toString數組

深刻理解JavaScript系列(12):變量對象(Variable Object)函數

1.JS 的數據類型

  • 基本數據類型(其實也統稱爲基本型或原始型)this

    undefined,null,number,boolean,stringspa

  • 一種複雜數據類型(引用型)prototype

    Object指針

 

1.1數據類型介紹

 

undefined 類型:聲明未定義日誌

let a
a === undefined // true

 

null 類型:null值表示一個空指針,初始化空對象可賦值爲null

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

 

boolean 類型:只有兩個字面值true false。可是這兩個值和數字值不是一回事,所以true不必定等於1,而false也不必定等於0。

要將一個值轉爲boolean型等價的值,有兩種方案:

  • 一種是顯式轉換-調用類型轉換函數Boolean()

  • 一種是自動轉換-如if(value)中的value就會自動轉化成爲boolean值

各種型與boolean型之間值得轉換關係以下表

數據類型 轉換爲true的值 轉換爲false的值
boolean true false
string 任何非空字符串 "" (空字符串)
bumber 任何非零數字值(包括無窮大) 0和NaN
undefined undefined
null null
Object 任何對象

 

 

number 類型:

表示整型,浮點型和NaN

JS中,0/0、NaN/0會返回NaN,其它數字/0會返回Infinity,不會報錯。

isNaN()

console.log(NaN + 1); // NaN,任何涉及到NaN的操做都會返回NaN
console.log(NaN === NaN); // false,NaN與任何值都不相等,包括NaN自己
console.log(isNaN(NaN)); // true,是NaN
console.log(isNaN('10')); // false,被轉爲數字10
console.log(isNaN(true)); // false,被轉爲數字1
console.log(isNaN(null)); // false,被轉爲數字0
console.log(isNaN(undefined)); // true,返回NaN
console.log(isNaN('hello')); // true,沒法轉換爲數字
console.log(0/0);// NaN,0/0返回NaN
console.log(NaN/0);// NaN,NaN/0返回NaN
console.log(1/0);// Infinity,其它數字/0返回Infinity
console.log('1'/0);// Infinity,'1'成功轉爲數字
console.log('1a'/0);// NaN,'1a'轉爲數字失敗,變爲NaN
console.log(Infinity/0);// Infinity,其它數字/0返回Infinity

注意:Infinity的類型是Number(不是基礎數據類型)

有兩種方法能夠將非number類型的值轉換爲number類型

  • 一種是隱式轉換,如進行(\*、/)操做時,會自動其他類型的值轉爲number類型

  • 一種是顯示轉換-調用Number()、parseInt()、parseFloat()方法轉換

Number():

  • 若是是boolean值,true和false將分別被替換爲1和0

  • 若是是數字值,只是簡單的傳入和返回

  • 若是是null值,返回0

  • 若是是undefined,返回NaN

  • 若是是字符串,遵循下列規則:

    • 若是字符串中只包含數字,則將其轉換爲十進制數值,即」1「會變成1,」123「會變成123,而」011「會變成11(前導的0被忽略)

    • 若是字符串中包含有效的浮點格式,如」1.1「,則將其轉換爲對應的浮點數(一樣,也會忽略前導0)

    • 若是字符串中包含有效的十六進制格式,例如」0xf「,則將其轉換爲相同大小的十進制整數值

    • 若是字符串是空的,則將其轉換爲0

    • 若是字符串中包含除了上述格式以外的字符,則將其轉換爲NaN

  • 若是是對象,則調用對象的valueOf()方法,而後依照前面的規則轉換返回的值。若是轉換的結果是NaN,則調用對象的toString()方法,而後再依次按照前面的規則轉換返回的字符串值。

console.log(Number(''));//0
console.log(Number('a'));//NaN
console.log(Number(true));//1
console.log(Number('001'));//1
console.log(Number('001.1'));//1.1
console.log(Number('0xf'));//15
console.log(Number('000xf'));//NaN
var a = {}; // 調用對象的valueOf()方法
console.log(Number(a));//NaN
a.toString = function(){return 2}; // 重寫valueOf()方法
console.log(Number(a));//2
a.valueOf = function(){return 1};
console.log(Number(a));//1

parseInt():

經常用於將其它類型值轉化爲整形。parseInt轉換與Number()有區別,具體規則以下:

  • parseInt(value,radius)有兩個參數,第一個參數是須要轉換的值,第二個參數是轉換進制(該值介於 2 ~ 36 之間。若是該參數小於 2 或者大於 36,則 parseInt() 將返回 NaN。),若是不傳(或值爲0),默認以10爲基數(若是value以 「0x」 或 「0X」 開頭,將以 16 爲基數)

  • 注意在第二個參數默認的狀況下,若是須要轉換的string值以0開頭,如'070',有一些環境中,會自動轉化爲8進制56,有一些環境中會自動轉化爲10進制70。因此爲了統一效果,咱們在轉換爲10進制時,會將第二個參數傳10

console.log(parseInt(''));//NaN
console.log(parseInt('a'));//NaN
console.log(parseInt('1234blue'));//1234
console.log(parseInt(true));//NaN
console.log(parseInt('070'));//70,可是有一些環境中會自動轉換爲8進制56
console.log(parseInt('070',8));//56
console.log(parseInt('001.1'));//1
console.log(parseInt('0xf'));//15,16進制
console.log(parseInt('AF',16));//175,16進制
console.log(parseInt('AF'));//NaN
console.log(parseInt('000xf'));//0
var a = {};
console.log(parseInt(a));//NaN
a.toString = function(){return 2}; // 重寫valueOf()方法
console.log(parseInt(a));//2
a.valueOf = function(){return 1}; // 重寫valueOf()方法
console.log(parseInt(a));//2

parseFloat():

parseFloat()轉換規則基本與parseInt()一致,只有以下不一樣點

  • parseFloat()遇到浮動數據時,浮點有效(可是隻有第一個.有效),如"10.1"會被轉爲10.1;'10.1.1'會被轉爲10.1

  • parseFloat()只會默認處理爲10進制,並且會忽略字符串前面的0,因此不會有在默認狀況下轉爲8進制的情

console.log(parseFloat('1234blue'));//1234
console.log(parseFloat('1234blue',2));//1234
console.log(parseFloat('0xA'));//0
console.log(parseFloat('10.1'));//10.1
console.log(parseFloat('10.1.1'));//10.1
console.log(parseFloat('010'));//10    

因爲Number()函數在轉換字符串時比較複雜並且不夠合理,所以在處理整數的時候更經常使用的是parseInt()函數-需注意最好第二個參數傳10,處理浮點數時更經常使用parseFloat()

另外注意,浮點數直接的計算存在偏差,因此兩個浮點數沒法用"="進行判斷

var a=10.2;
var b= 10.1;
console.log(a - b === 0.1);//false
console.log(a - 10.1 === 0.1);//false,實際是0.09999999999999964
console.log(a - 0.1 === 10.1);//true

 

string:

string類型用於表示由零或多個16位Unicode字符組成的字符序列,即字符串。字符串能夠由單引號(')或雙引號(")表示。任何字符串的長度均可以經過訪問其length屬性取得。

要把一個值轉換爲一個字符串有三種方式。

  • 第一種是使用幾乎每一個值都有的toString()方法(除去null和undefined沒有)

    • toString(radius)有一個參數-基數,當須要toString的值爲number時,參數能夠生效(能夠轉換爲對應進制輸出,如10.toString(8)輸出爲12。

  • 第二種是隱式轉換,好比字符串+ number(null,undefined,object等),會默認轉爲字符串(若是後面相加的是object對象,會返回object對象的toString或valueOf值)

  • 第三種是經過轉換函數String(),轉換規則以下

    • 若是值有toString()方法,則調用該方法(沒有參數)並返回相應的結果(注意,valueOf()方法沒用)

    • 若是值是null,則返回null

    • 若是值是undefined,則返回undefined

var a = 10;
console.log(a.toString());//10
console.log(a.toString(8));//12

var b = '10'
console.log(b.toString(8));//10,字符串基數沒用

var c = {};
console.log(c);//[object Object]
console.log(c + '1');//[object Object]1
console.log(String(c));//[object Object]

c.valueOf = function () { return '重寫c的valueOf方法' };
console.log(c);// {valueOf: ƒ}   valueOf重寫
console.log(c + '1');// 重寫c的valueOf方法1    隱式轉換時,valueOf起做用了

console.log(String(c));// [object Object]
c.toString = function () { return '重寫c的toString方法' };
console.log(c);// {valueOf: ƒ, toString: ƒ}  toString起做用了
console.log(String(c)); // 重寫c的toString方法

console.log(String(null));// null,null和undefined能夠String()輸出
console.log(String(undefined));// undefined ,null和undefined能夠String()輸出
// console.log(null.toString());//報錯,null和undefined不能toString

let d = {}
d.valueOf = function () {
  console.log('valueOf 執行了')
  return 'valueOf'
};
d.toString = function () {
  console.log('toString 執行了')
  return 'toString'
};
console.log(d + '1') // 隱式轉換 valueOf 執行了
console.log(String(d)) // String toString 執行了

 

object 類型:

Object的每一個實例都具備下列屬性和方法:

  • constructor——保存着用於建立當前對象的函數

  • hasOwnProperty(propertyName)——用於檢查給定的屬性在當前對象實例中(而不是在實例的原型中)是否存在。其中,做爲參數的屬性名(propertyName)必須以字符串形式指定(例如:o.hasOwnProperty("name")

  • isPrototypeOf(object)——用於檢查傳入的對象是不是另外一個對象的原型

  • propertyIsEnumerable(propertyName)——用於檢查給定的屬性是否可以使用for-in語句來枚舉

  • toString()——返回對象的字符串表示

  • valueOf()——返回對象的字符串、數值或布爾值表示。一般與toString()方法的返回值相同。

var obj = new Object();
obj.name = 'zs';
obj.sayHi = function () {
  console.log('Hi');
}
console.log(obj.hasOwnProperty('a')); // 實例對象 true
console.log(obj.hasOwnProperty('sayHi')); // 實例對象 true
console.log(obj); // 實例對象
console.log(obj.constructor); // 構造函數Object()
console.log(obj.__proto__); // 原型

 

2.valueOf()toString()

  • valueOf方法返回指定對象的原始值。

  • toString: 返回對象的字符串表示

valueOf轉換規則

MDN對valueOf()的描述

JavaScript調用valueOf方法將對象轉換爲原始值。你不多須要本身調用valueOf方法;當遇到要預期的原始值的對象時,JavaScript會自動調用它。

默認狀況下,valueOf方法由 Object 後面的每一個對象繼承。 每一個內置的核心對象都會覆蓋此方法以返回適當的值。若是對象沒有原始值,則valueOf將返回對象自己。

JavaScript的許多內置對象都重寫了該函數,以實現更適合自身的功能須要。所以,不一樣類型對象的valueOf()方法的返回值和返回值類型都可能不一樣。

非原始值(也就是對象)重寫規則以下:

對象 valueOf返回值
Array 數組自己
Boolean 布爾值
Date 返回毫秒形式的時間戳
Function 函數自己
Number 數字值
Object 對象自己
String 字符串值
// Array:返回數組對象自己
var array = ["ABC", true, 12, -5];
console.log(array.valueOf() === array);   // true

// Date:當前時間距1970年1月1日午夜的毫秒數
var date = new Date(2013, 7, 18, 23, 11, 59, 230);
console.log(date.valueOf());   // 1376838719230

// Number:返回數字值
var num =  15.26540;
console.log(num.valueOf());   // 15.2654

// 布爾:返回布爾值true或false
var bool = true;
console.log(bool.valueOf() === bool);   // true

// new一個Boolean對象
var newBool = new Boolean(true);
// valueOf()返回的是true,二者的值相等
console.log(newBool.valueOf() == newBool);   // true
// 可是不全等,二者類型不相等,前者是boolean類型,後者是object類型
console.log(newBool.valueOf() === newBool);   // false

// Function:返回函數自己
function foo(){}
console.log( foo.valueOf() === foo );   // true
var foo2 =  new Function("x", "y", "return x + y;");
console.log( foo2.valueOf() );
/*
ƒ anonymous(x,y) {return x + y;}
*/

// Object:返回對象自己
var obj = {name: "張三", age: 18};
console.log( obj.valueOf() === obj );   // true

// String:返回字符串值
var str = "http://www.xyz.com";
console.log( str.valueOf() === str );   // true

// new一個字符串對象
var str2 = new String("http://www.xyz.com");
// 二者的值相等,但不全等,由於類型不一樣,前者爲string類型,後者爲object類型
console.log( str2.valueOf() === str2 );   // false

 

對象轉換爲布爾值

  1. 直接轉換爲true(包裝類型也同樣),不調用valueOf和toString

 

對象轉換爲數字

在預期會將對象用做數字使用時,好比參與算術運算等等操做,對象轉換爲數字會依次調用valueOf和toString方法,具體規則以下:

  1. 若是對象具備valueOf方法且返回原始值(string、number、boolean、undefined、null),則將該原始值轉換爲數字(轉換失敗會返回NaN),並返回這個數字

  2. 若是對象具備toString方法且返回原始值(string、number、boolean、undefined、null),則將該原始值轉換爲數字(轉換失敗會返回NaN),並返回這個數字

  3. 轉換失敗,拋出TypeError

 

對象轉換爲字符串

  1. 若是對象具備toString方法且返回原始值(string、number、boolean、undefined、null),則將該原始值轉換爲字符串,並返回該字符串

  2. 若是對象具備valueOf方法且返回原始值(string、number、boolean、undefined、null),則將該原始值轉換爲字符串,並返回該字符串

  3. 轉換失敗,拋出TypeError

 

toString轉換規則

對象 toString返回值
Array 以逗號分割的字符串,如[1,2]的toString返回值爲"1,2"
Boolean "True"
Date 可讀的時間字符串,如"Tue Oct 15 2019 12:20:56 GMT+0800 (中國標準時間)"
Function 聲明函數的JS源代碼字符串
Number "數字值"
Object "[object Object]"
String "字符串"

 

Boolean.prototype.toString()

toString() 方法返回指定的布爾對象的字符串形式

let flag = new Boolean(true);
console.log(flag.toString()) // true

let flag1 = new Boolean(1);
console.log(flag1.toString()) // true

 

Array.prototype.toString()

toString()返回一個字符串,表示指定的數組及其元素。

let array = ['abc', true, 12, undefined, 'ok']
console.log(array.toString()); // abc,true,12,,ok

 

Function.prototype.toString()

toString() 方法返回一個表示當前函數源代碼的字符串。

function fun(num) {
  num += 5
}

console.log(fun.toString());
/**
 * function fun(num) {  num += 5 }
 */

 

Object.prototype.toString()

toString() 方法返回一個表示該對象的字符串。

let obj = { name: 'houfee'}
console.log(obj.toString()); // [object Object]

 

3.對象到原始值的轉換

對象轉換爲Boolean

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日誌
Object.prototype.valueOf = function () {
  console.log('valueOf');
  return valueOf.call(this);
};
// 添加toString日誌
Object.prototype.toString = function () {
  console.log('toString');
  return toString.call(this);
};
var a = {};
var b = new Boolean(false);

if (a) {
  console.log(1);
}
if (b) {
  // console.log(typeof b);
  // console.log(b);
  console.log(2);
}

 

對象轉換爲Number

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日誌
Object.prototype.valueOf = function () {
  console.log('valueOf');
  return valueOf.call(this);
};
// 添加toString日誌
Object.prototype.toString = function () {
  console.log('toString');
  return toString.call(this);
};
var a = {};
console.log(++a); // valueOf toString NaN

分析

  1. valueOf方法返回的是對象自己,不是原始值,繼續執行

  2. toString方法返回的是"[object Object]",是原始值(字符串),將字符串轉換爲數字NaN

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日誌
Object.prototype.valueOf = function () {
  console.log('valueOf');
  return "1"; // 強制返回原始值
};
// 添加toString日誌
Object.prototype.toString = function () {
  console.log('toString');
  return toString.call(this);
};
var a = {};
console.log(++a); // valueOf 2

分析

  1. valueOf返回原始值(字符串),直接將該字符串轉換爲數字,獲得1

 

對象轉換爲字符串

在預期會將對象用做字符串時,好比一個字符串拼接了字符串,傳入了一個對象,此時會發生轉換。

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日誌
Object.prototype.valueOf = function () {
  console.log('valueOf');
  return valueOf.call(this);
};
// 添加toString日誌
Object.prototype.toString = function () {
  console.log('toString');
  return toString.call(this); // '[object Object]'  toString方法先調用 ,若是返回結果是字符串,則中止調用 valueOf,不是字符串,那麼就調用 valueOf
};
var a = {};
console.log(a.toString()); // valueOf toString [object Object]str
// alert(a) // alert主動調用toString方法,返回了字符串"[object Object]",對象最終轉換爲該字符串

 

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日誌
Object.prototype.valueOf = function () {
  console.log('valueOf');
  return valueOf.call(this);
};
// 添加toString日誌
Object.prototype.toString = function () {
  console.log('toString');
  return this;
};
var a = {};
alert(a); 
/*
toString
valueOf
Uncaught TypeError: Cannot convert object to primitive value
    at 1.js:16
*/

 

使用加號運算符鏈接字符串和對象時的處理

// 保存原始的valueOf
var valueOf = Object.prototype.valueOf;
var toString = Object.prototype.toString;

// 添加valueOf日誌
Object.prototype.valueOf = function () {
  console.log('valueOf');
  return valueOf.call(this);
};
// 添加toString日誌
Object.prototype.toString = function () {
  console.log('toString');
  return toString.call(this); // '[object Object]'  toString方法先調用 ,若是返回結果是字符串,則中止調用 valueOf,不是字符串,那麼就調用 valueOf
};
var a = {};
console.log(a + 'str'); // valueOf toString [object Object]str
// alert(a) // alert主動調用toString方法,返回了字符串"[object Object]",對象最終轉換爲該字符串

 

4.強制類型轉換

Number強制轉換對象

let a = { name: 123 };
console.log(Number(a)); // NaN
/*
* JS對象強制類型轉換
* 主要調用 object.valueOf() 和 object.toString() 方法
* 1.先調用 object 的 valueOf() 方法
* 2.判斷返回值 是否爲 基礎數據類型?
* 3.是!則轉換規則按照相應數據類型的規則對其進行轉換
* 4.不是!在返回值的基礎上繼續調用 toString() 方法
* 5.判斷調用 toString() 方法返回值是否爲 基礎數據類型
* 6.是!則轉換規則按照相應數據類型的規則對其進行轉換
* 7.不是!報錯:
* */

 

 如今咱們用自定義方法覆蓋toString()方法:

a.toString = function () {return {name: 'newName'}} // 讓toString方法返回值爲 複雜數據類型
a.toString() // 調用覆蓋的方法
Number(a) // 報錯

 如今驗證讓toString()方法返回值爲 基礎數據類型

a.toString = function () {return '321'} // 讓toString方法返回值爲 複雜數據類型
a.toString() // 調用覆蓋的方法
Number(a) // 321

因此Number強制轉換對象的過程即爲如上7步

 

String()強制轉換對象

let b = {name: 'houfee'}
console.log(String(b)); // [object Object]
let c = []
console.log(String(c)); // 空字符串
let d = {}
console.log(String(d)); // [object Object]

  1. 先調用對象的toString方法

  2. 判斷該方法的返回值是否爲基礎數據類型(Number,String,Boolean,Undefined,Null)

  3. 若返回值爲基礎數據類型,則轉換規則按照相應數據類型的轉換規則對其進行轉換

  4. 若返回值不爲基礎數據類型,則在該返回值的基礎上繼續調用valueOf方法

  5. 判斷valueOf的返回值是否爲基礎數據類型

  6. 判斷是否爲基礎數據類型,如果基礎數據類型則進行操做3

  7. 若仍舊不爲基礎數據類型則報錯

 

String與Number的區別則在於

  • Number是先調用valueOf()再調用toString ()

  • 而String是先調用toString()再調用valueOf()

Number()先轉換爲原始類型,再轉化爲字符串形式

String()先轉換爲字符串形式,再轉化爲原始類型

 

 

5.判斷數據類型

function isArray(value) {
  return Object.prototype.toString.call(value) == "[object Array]"
}
function isFunction(value) {
  return Object.prototype.toString.call(value) == "[object Function]"
}
function isRegExp(value) {
  return Object.prototype.toString.call(value) == "[object RegExp]"
}

 

6.面試題

console.log({}); // {}
console.log(Number({})); // NaN、
console.log(String({})); // [object Object]
console.log(Boolean({})); // true

console.log([]); // []
console.log(Number([])); // 0
console.log(String([])); // 空字符串
console.log(Boolean([])); // true

console.log({} + {}) // [object Object][object Object]
console.log({} + []) // [object Object]
console.log([] + {}) // [object Object]
console.log([] + []) // 空字符串
相關文章
相關標籤/搜索