常常被面試官問道的JavaScript數據類型知識你真的懂嗎?

前言

以前面試了幾個開發者,他們確實作過很多項目,能力也是不錯的,可是發現js基礎不紮實, 因而決定寫一下這篇javascrip數據類型相關的基礎文章,其實也不只僅是由於面試了他們,以前本身在面試的時候,也曾經被虐過,面試官說過的最深入的一句話我到如今都記得。javascript

基礎很重要,只有基礎好纔會不多出bug,大多數的bug都是基礎不紮實形成的。java

做者簡介:koala,專一完整的 Node.js 技術棧分享,從 JavaScript 到 Node.js,再到後端數據庫,祝您成爲優秀的高級 Node.js 工程師。【程序員成長指北】做者,Github 博客開源項目 github.com/koala-codin…git

這裏給出兩道咱們公司數據類型基礎相關的面試題和答案,若是都能作對而且知道爲何(能夠選擇忽略本文章):程序員

//類型轉換相關問題
var bar=true;
console.log(bar+0);
console.log(bar+"xyz");
console.log(bar+true);
console.log(bar+false);
console.log('1'>bar);
console.log(1+'2'+false);
console.log('2' + ['koala',1]);

var obj1 = {
   a:1,
   b:2
}
console.log('2'+obj1);

var obj2 = {
    toString:function(){
        return 'a'
    }
}
console.log('2'+obj2)

//輸出結果 1 truexyz 2 1 false 12false 2koala,1 2[object Object] 2a
複製代碼
//做用域和NaN 這裏不具體講做用域,意在說明NaN
var b=1;
function outer(){
    var b=2;
    function inner(){
        b++;
        console.log(b);
        var b=3;
    }
    inner();
}
outer();
//輸出結果 NaN
複製代碼

本篇文章會以一個面試官問問題的角度來進行分析講解github

js中的數據類型

面試官:說一說javascript中有哪些數據類型?面試

JavaScript 中共有七種內置數據類型,包括基本類型對象類型數據庫

基本類型

基本類型分爲如下六種:express

  • string(字符串)
  • boolean(布爾值)
  • number(數字)
  • symbol(符號)
  • null(空值)
  • undefined(未定義)

注意後端

  1. stringnumberbooleannull undefined 這五種類型統稱爲原始類型(Primitive),表示不能再細分下去的基本類型;數組

  2. symbol是ES6中新增的數據類型,symbol 表示獨一無二的值,經過 Symbol 函數調用生成,因爲生成的 symbol 值爲原始類型,因此 Symbol 函數不能使用new 調用;

  3. nullundefined 一般被認爲是特殊值,這兩種類型的值惟一,就是其自己。

對象類型

對象類型也叫引用類型,arrayfunction是對象的子類型。對象在邏輯上是屬性的無序集合,是存放各類值的容器。對象值存儲的是引用地址,因此和基本類型值不可變的特性不一樣,對象值是可變的。

js弱類型語言

面試官:說說你對javascript是弱類型語言的理解?

JavaScript 是弱類型語言,並且JavaScript 聲明變量的時候並無預先肯定的類型,變量的類型就是其值的類型,也就是說變量當前的類型由其值所決定,誇張點說上一秒種的String,下一秒可能就是個Number類型了,這個過程可能就進行了某些操做發生了強制類型轉換。雖然弱類型的這種不須要預先肯定類型的特性給咱們帶來了便利,同時也會給咱們帶來困擾,爲了能充分利用該特性就必須掌握類型轉換的原理。

js中的強制轉換規則

面試官:javascript中強制類型轉換是一個很是易出現bug的點,知道強制轉換時候的規則嗎?

注:規則最好配合下面何時發生轉換使用這些規則看效果更佳。

ToPrimitive(轉換爲原始值)

ToPrimitive對原始類型不發生轉換處理,只針對引用類型(object)的,其目的是將引用類型(object)轉換爲非對象類型,也就是原始類型。

ToPrimitive 運算符接受一個值,和一個可選的指望類型做參數ToPrimitive 運算符將值轉換爲非對象類型,若是對象有能力被轉換爲不止一種原語類型,可使用可選的 指望類型 來暗示那個類型。

轉換後的結果原始類型是由指望類型決定的,指望類型其實就是咱們傳遞的type。直接看下面比較清楚。 ToPrimitive方法大概長這麼個樣子具體以下。

/** * @obj 須要轉換的對象 * @type 指望轉換爲的原始數據類型,可選 */
ToPrimitive(obj,type)
複製代碼
type不一樣值的說明
  • type爲string:
  1. 先調用objtoString方法,若是爲原始值,則return,不然進行第2步
  2. 調用objvalueOf方法,若是爲原始值,則return,不然進行第3步
  3. 拋出TypeError 異常
  • type爲number:
  1. 先調用objvalueOf方法,若是爲原始值,則return,不然進行第2步
  2. 調用objtoString方法,若是爲原始值,則return,不然第3步
  3. 拋出TypeError 異常
  • type參數爲空
  1. 該對象爲Date,則type被設置爲String
  2. 不然,type被設置爲Number
Date數據類型特殊說明:

對於Date數據類型,咱們更多指望得到的是其轉爲時間後的字符串,而非毫秒值(時間戳),若是爲number,則會取到對應的毫秒值,顯然字符串使用更多。 其餘類型對象按照取值的類型操做便可。

ToPrimitive總結

ToPrimitive轉成何種原始類型,取決於type,type參數可選,若指定,則按照指定類型轉換,若不指定,默認根據實用狀況分兩種狀況,Datestring,其他對象爲number。那麼何時會指定type類型呢,那就要看下面兩種轉換方式了。

toString

Object.prototype.toString()

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

每一個對象都有一個 toString() 方法,當對象被表示爲文本值時或者當以指望字符串的方式引用對象時,該方法被自動調用。

這裏先記住,valueOf()toString()在特定的場合下會自行調用。

valueOf

Object.prototype.valueOf()方法返回指定對象的原始值。

JavaScript 調用 valueOf() 方法用來把對象轉換成原始類型的值(數值、字符串和布爾值)。可是咱們不多須要本身調用此函數,valueOf 方法通常都會被 JavaScript 自動調用。

不一樣內置對象的valueOf實現:

  • String => 返回字符串值
  • Number => 返回數字值
  • Date => 返回一個數字,即時間值,字符串中內容是依賴於具體實現的
  • Boolean => 返回Boolean的this值
  • Object => 返回this

對照代碼會更清晰一些:

var str = new String('123');
console.log(str.valueOf());//123

var num = new Number(123);
console.log(num.valueOf());//123

var date = new Date();
console.log(date.valueOf()); //1526990889729

var bool = new Boolean('123');
console.log(bool.valueOf());//true

var obj = new Object({valueOf:()=>{
    return 1
}})
console.log(obj.valueOf());//1
複製代碼

Number

Number運算符轉換規則:

  • null 轉換爲 0
  • undefined 轉換爲 NaN
  • true 轉換爲 1,false 轉換爲 0
  • 字符串轉換時遵循數字常量規則,轉換失敗返回NaN

注意:對象這裏要先轉換爲原始值,調用ToPrimitive轉換,type指定爲number了,繼續回到ToPrimitive進行轉換。

String

String 運算符轉換規則

  • null 轉換爲 'null'
  • undefined 轉換爲 undefined
  • true 轉換爲 'true'false 轉換爲 'false'
  • 數字轉換遵循通用規則,極大極小的數字使用指數形式

注意:對象這裏要先轉換爲原始值,調用ToPrimitive轉換,type就指定爲string了,繼續回到ToPrimitive進行轉換(上面有將到ToPrimitive的轉換規則)。

String(null)                 // 'null'
String(undefined)            // 'undefined'
String(true)                 // 'true'
String(1)                    // '1'
String(-1)                   // '-1'
String(0)                    // '0'
String(-0)                   // '0'
String(Math.pow(1000,10))    // '1e+30'
String(Infinity)             // 'Infinity'
String(-Infinity)            // '-Infinity'
String({})                   // '[object Object]'
String([1,[2,3]])            // '1,2,3'
String(['koala',1])          //koala,1
複製代碼

Boolean

ToBoolean 運算符轉換規則

除了下述 6 個值轉換結果爲 false,其餘所有爲true

  1. undefined
  2. null
  3. -0
  4. 0或+0
  5. NaN
  6. ''(空字符串)

假值之外的值都是真值。其中包括全部對象(包括空對象)的轉換結果都是true,甚至連false對應的布爾對象new Boolean(false)也是true

Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false

Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true
複製代碼

js轉換規則不一樣場景應用

面試官問:知道了具體轉換成什麼的規則,可是都在什麼狀況下發生什麼樣的轉換呢?

何時自動轉換爲string類型

  • 在沒有對象的前提下

    字符串的自動轉換,主要發生在字符串的加法運算時。當一個值爲字符串,另外一個值爲非字符串,則後者轉爲字符串。

'2' + 1 // '21'
'2' + true // "2true"
'2' + false // "2false"
'2' + undefined // "2undefined"
'2' + null // "2null"
複製代碼
  • 當有對象且與對象+時候
//toString的對象
var obj2 = {
    toString:function(){
        return 'a'
    }
}
console.log('2'+obj2)
//輸出結果2a

//常規對象
var obj1 = {
   a:1,
   b:2
}
console.log('2'+obj1);
//輸出結果 2[object Object]

//幾種特殊對象
'2' + {} // "2[object Object]"
'2' + [] // "2"
'2' + function (){} // "2function (){}"
'2' + ['koala',1] // 2koala,1
複製代碼

對下面'2'+obj2詳細舉例說明以下:

  1. 左邊爲stringToPrimitive原始值轉換後不發生變化
  2. 右邊轉化時一樣按照ToPrimitive進行原始值轉換,因爲指定的type是number,進行ToPrimitive轉化調用obj2.valueof(),獲得的不是原始值,進行第三步
  3. 調用toString() return 'a'
  4. 符號兩邊存在string,並且是+號運算符則都採用String規則轉換爲string類型進行拼接
  5. 輸出結果2a

對下面'2'+obj1詳細舉例說明以下:

  1. 左邊爲stringToPrimitive轉換爲原始值後不發生變化
  2. 右邊轉化時一樣按照ToPrimitive進行原始值轉換,因爲指定的type是number,進行ToPrimitive轉化調用obj2.valueof(),獲得{ a: 1, b: 2 }
  3. 調用toString() return [object Object]
  4. 符號兩邊存在string,並且是+號運算符則都採用String規則轉換爲string類型進行拼接
  5. 輸出結果2[object Object]

代碼中幾種特殊對象的轉換規則基本相同,就不一一說明,你們能夠想一下流程。

注意:無論是對象還不是對象,都有一個轉換爲原始值的過程,也就是ToPrimitive轉換,只不過原始類型轉換後不發生變化,對象類型纔會發生具體轉換。

string類型轉換開發過程當中可能出錯的點:

var obj = {
  width: '100'
};

obj.width + 20 // "10020"

複製代碼

預期輸出結果120 實際輸出結果10020

何時自動轉換爲Number類型

  • 有加法運算符,可是無String類型的時候,都會優先轉換爲Number類型

    例子:

    true + 0 // 1
    true + true // 2
    true + false //1
    複製代碼
  • 除了加法運算符,其餘運算符都會把運算自動轉成數值。 例子:

    '5' - '2' // 3
    '5' * '2' // 10
    true - 1  // 0
    false - 1 // -1
    '1' - 1   // 0
    '5' * []    // 0
    false / '5' // 0
    'abc' - 1   // NaN
    null + 1 // 1
    undefined + 1 // NaN
    
    //一元運算符(注意點)
    +'abc' // NaN
    -'abc' // NaN
    +true // 1
    -false // 0
    複製代碼

注意:null轉爲數值時爲0,而undefined轉爲數值時爲NaN

判斷等號也放在Number裏面特殊說明

== 抽象相等比較與+運算符不一樣,再也不是String優先,而是Number優先。 下面列舉x == y的例子

  1. 若是x,y均爲number,直接比較 沒什麼可解釋的了
1 == 2 //false
複製代碼
  1. 若是存在對象,ToPrimitive()type爲number進行轉換,再進行後面比較
var obj1 = {
    valueOf:function(){
        return '1'
    }
}
1 == obj1  //true
//obj1轉爲原始值,調用obj1.valueOf()
//返回原始值'1'
//'1'toNumber獲得 1 而後比較 1 == 1
[] == ![] //true
//[]做爲對象ToPrimitive獲得 '' 
//![]做爲boolean轉換獲得0 
//'' == 0 
//轉換爲 0==0 //true
複製代碼
  1. 存在boolean,按照ToNumberboolean轉換爲1或者0,再進行後面比較
//boolean 先轉成number,按照上面的規則獲得1 
//3 == 1 false
//0 == 0 true
3 == true // false
'0' == false //true
複製代碼

4.若是xstringynumberx轉成number進行比較

//'0' toNumber()獲得 0 
//0 == 0 true
'0' == 0 //true
複製代碼

何時進行布爾轉換

  • 布爾比較時
  • if(obj) , while(obj)等判斷時或者 三元運算符只可以包含布爾值

條件部分的每一個值都至關於false,使用否認運算符後,就變成了true

if ( !undefined
  && !null
  && !0
  && !NaN
  && !''
) {
  console.log('true');
} // true

//下面兩種狀況也會轉成布爾類型
expression ? true : false
!! expression
複製代碼

js中的數據類型判斷

面試官問:如何判斷數據類型?怎麼判斷一個值究竟是數組類型仍是對象?

三種方式,分別爲 typeofinstanceofObject.prototype.toString()

typeof

經過 typeof操做符來判斷一個值屬於哪一種基本類型。

typeof 'seymoe'    // 'string'
typeof true        // 'boolean'
typeof 10          // 'number'
typeof Symbol()    // 'symbol'
typeof null        // 'object' 沒法斷定是否爲 null
typeof undefined   // 'undefined'

typeof {}           // 'object'
typeof []           // 'object'
typeof(() => {})    // 'function'
複製代碼

上面代碼的輸出結果能夠看出,

  1. null 的斷定有偏差,獲得的結果 若是使用 typeofnull獲得的結果是object

  2. 操做符對對象類型及其子類型,例如函數(可調用對象)、數組(有序索引對象)等進行斷定,則除了函數都會獲得 object 的結果。

綜上能夠看出typeOf對於判斷類型還有一些不足,在對象的子類型和null狀況下。

instanceof

經過 instanceof 操做符也能夠對對象類型進行斷定,其原理就是測試構造函數的prototype 是否出如今被檢測對象的原型鏈上。

[] instanceof Array            // true
({}) instanceof Object         // true
(()=>{}) instanceof Function   // true
複製代碼

複製代碼注意:instanceof 也不是萬能的。 舉個例子:

let arr = []
let obj = {}
arr instanceof Array    // true
arr instanceof Object   // true
obj instanceof Object   // true
複製代碼

在這個例子中,arr 數組至關於 new Array() 出的一個實例,因此 arr.__proto__ === Array.prototype,又由於 Array屬於 Object 子類型,即Array.prototype.__proto__ === Object.prototype,所以 Object 構造函數在 arr 的原型鏈上。因此 instanceof 仍然沒法優雅的判斷一個值到底屬於數組仍是普通對象。

還有一點須要說明下,有些開發者會說 Object.prototype.__proto__ === null,豈不是說 arr instanceof null 也應該爲 true,這個語句其實會報錯提示右側參數應該爲對象,這也印證 typeof null 的結果爲 object 真的只是javascript中的一個bug

Object.prototype.toString() 能夠說是斷定 JavaScript 中數據類型的終極解決方法了,具體用法請看如下代碼:

Object.prototype.toString.call({})              // '[object Object]'
Object.prototype.toString.call([])              // '[object Array]'
Object.prototype.toString.call(() => {})        // '[object Function]'
Object.prototype.toString.call('seymoe')        // '[object String]'
Object.prototype.toString.call(1)               // '[object Number]'
Object.prototype.toString.call(true)            // '[object Boolean]'
Object.prototype.toString.call(Symbol())        // '[object Symbol]'
Object.prototype.toString.call(null)            // '[object Null]'
Object.prototype.toString.call(undefined)       // '[object Undefined]'

Object.prototype.toString.call(new Date())      // '[object Date]'
Object.prototype.toString.call(Math)            // '[object Math]'
Object.prototype.toString.call(new Set())       // '[object Set]'
Object.prototype.toString.call(new WeakSet())   // '[object WeakSet]'
Object.prototype.toString.call(new Map())       // '[object Map]'
Object.prototype.toString.call(new WeakMap())   // '[object WeakMap]'
複製代碼

咱們能夠發現該方法在傳入任何類型的值都能返回對應準確的對象類型。用法雖簡單明瞭,但其中有幾個點須要理解清楚:

  • 該方法本質就是依託Object.prototype.toString()方法獲得對象內部屬性 [[Class]]
  • 傳入原始類型卻可以斷定出結果是由於對值進行了包裝
  • nullundefined 可以輸出結果是內部實現有作處理

NaN相關總結

NaN的概念

NaN 是一個全局對象的屬性,NaN 是一個全局對象的屬性,NaN是一種特殊的Number類型。

何時返回NaN (開篇第二道題也獲得解決)

  • 無窮大除以無窮大
  • 給任意負數作開方運算
  • 算數運算符與不是數字或沒法轉換爲數字的操做數一塊兒使用
  • 字符串解析成數字

一些例子:

Infinity / Infinity;   // 無窮大除以無窮大
Math.sqrt(-1);         // 給任意負數作開方運算
'a' - 1;               // 算數運算符與不是數字或沒法轉換爲數字的操做數一塊兒使用
'a' * 1;
'a' / 1;
parseInt('a');         // 字符串解析成數字
parseFloat('a');

Number('a');   //NaN
'abc' - 1   // NaN
undefined + 1 // NaN
//一元運算符(注意點)
+'abc' // NaN
-'abc' // NaN
複製代碼

誤區

toStringString的區別

  • toString
  1. toString()能夠將數據都轉爲字符串,可是nullundefined不能夠轉換。

    console.log(null.toString())
    //報錯 TypeError: Cannot read property 'toString' of null
    
    console.log(undefined.toString())
    //報錯 TypeError: Cannot read property 'toString' of undefined
    複製代碼
  2. toString()括號中能夠寫數字,表明進制

    二進制:.toString(2);

    八進制:.toString(8);

    十進制:.toString(10);

    十六進制:.toString(16);

  • String
  1. String()能夠將nullundefined轉換爲字符串,可是無法轉進制字符串

    console.log(String(null));
    // null
    console.log(String(undefined));
    // undefined
    複製代碼

交流

關注公衆號:『程序員成長指北』, 獲取更多精選文章

我的公衆號技術棧

公衆號二維碼

相關文章
相關標籤/搜索