js數據類型與隱式類型轉換


執行環境

執行環境是js中最為重要的一個概念。執行環境定義了變量或函數有權訪問的其他數據,決定了它們各自的行為。每個執行環境都有一個與之關聯的變量對象(variable object),環境中定義的所有變量和函數都保存在這個對象中。雖然我們寫的代碼無法訪問這個對象,但解析器在處理數據時會在后台使用它。

全局執行環境

全局執行環境是最外圍的一個執行環境。根據ECMAScript實現所在的宿主環境不同,表示執行環境的對象也不一樣。在Web瀏覽器中,全局執行環境被認為是window對象,因此所有全局變量和函數都是作為window對象的屬性和方法創建的。某個執行環境中的所有代碼執行完畢后,該環境被銷毀,保存在其中的所有變量和函數定義也隨之銷毀(全局執行環境直到應用程序退出---例如關閉網頁或瀏覽器時才會被銷毀)。

函數執行環境

每個函數都有自己的執行環境。當執行流進入一個函數時,函數的環境就會被推入一個環境棧中。而在函數執行之后,棧將其環境彈出,把控制權返回給之前的執行環境。ECMAScript程序中的執行例句正式由這個方便的機制控制這。

堆棧內存

  • js中有兩大內存:堆內存(heap)、棧內存(stack)
  • 堆內存作用:用來存儲內容的(對象存儲的是鍵值對,函數存儲的是代碼字符串)
  • 棧內存作用:也可以被成為作用域,是代碼解析和執行的環境
堆棧內存的釋放問題

堆內存:

堆內存的釋放只要沒有變量占用這個堆內存,瀏覽器就會在空閑的時候把它釋放掉,所以在項目中我們盡可能把不被使用的堆內存手動釋放掉。

棧內存:

函數執行會形成一個私有的占內存,一般函數執行完成,棧內存會自己釋放,除非棧內存中存在某一個東西(例如:棧內存中開辟的堆內存)被棧內存意外的變量(或者是其他東西)占用了,此時的棧內存就不能被釋放掉;全局作用域(棧內存)是在一開始加載js的時候誕生的,當前頁面關閉的時候會自動釋放掉。

基礎數據類型

js中的基礎數據類型,這些值都有固定的大小,往往都是保存在內存空間中,由系統自動分配存儲空間。我們可以直接操作保存在棧內存空間的值,因此基礎數據類型都是按值訪問

基礎數據類型:Number String Undefined Boolean

引用數據類型

由於引用數據類型存儲的值過於復雜(結構復雜即內容較多),渲染引擎會開辟一個新的內存空間,單獨來存儲這些值,最后把內存空間引用地址賦值給對應的變量,后期所有的操作都是基於地址找到空間,然后對空間中的內容進行操作。

引用數據類型:Object Array Date RegExp Math Function
對象數據類型
  1. 開辟一個內存空間(有一個16進制的地址)
  2. 把對象中的屬性名和屬性值一次存儲到內存空間中
  3. 把內存空間的地址賦值給變量
函數數據類型
  1. 開辟一個內存空間(有一個16進制的地址)
  2. 把函數體中的代碼當作"字符串"存儲到內存空間中
    • 函數創建的時候都是無意義的字符串所以說函數只創建不執行是毫無意義的
    • 變量提升只對當前作用域下的var/function處理,主要原因是函數中存的都是字符串,我們看到的函數中的var/function此時還都是字符串呢
    • 當函數執行的時候,就是要把這堆字符串拿出來執行的
  3. 把內存空間地址賦值給變量

在前端面試中經常會遇到這樣一個類似的題目

var a = 10;
var b = a;
b = 20;
// 這時a的值是多少?

在棧內存中的數據發生復制行為時,系統會自動為新的變量分配一個新值。var b = a執行之后,a與b的值都等於10,但是他們其實已經是相互獨立互不影響的值了。

var a = {name:'小明',age:'10' };
var b = a;
b.name = '小紅'
// 這時a.name的值是多少?

我們通過var b = a執行一次復制引用類型的操作。引用類型的復制同樣也會為新的變量自動分配一個新的值保存在棧內存中,但是不同的是,這個新的值,僅僅只是引用類型的一個地址指針。當地址指針相同時,盡管他們相互獨立,但是在堆內存中訪問到的具體對象實際上是同一個。

隱式類型轉換

js中的數據類型是非常弱的,在使用算數運算符時,運算符兩邊的數據類型可以是任意的,比如,一個字符串可以和一個數字相加。之所以不同的數據類型之間可以做運算,是因為js引擎在運算之前會悄悄地把他們進行了隱式類型轉換。

我們先來看機組典型的js中運算符操作結果

console.log([] == []) // false
console.log([] == ![]) // true
console.log([] !== [])  // true
console.log(NaN != NaN) // true
console.log(null == undefined) // true
console.log(null === undefined) // false
console.log(1 == true) // true
console.log(null > 0) // false
console.log(true + 1) // 2
console.log(undefined + 1) // NaN
console.log({} + 1) // [object Object]1
console.log([] + {}) // [object Object]
console.log([2,3] + [1,2])  // 2,31,2

原始值 轉化為值類型 轉化為字符串 轉化為Boolean
false 0 "false" false
true 1 "true" true
0 0 "0" false
1 1 "1" true
"0" 0 "0" true
NaN NaN "NaN" false
Infinity Infinity "Infinity" true
"" 0 "" false
[ ] 0 "" true
[20] 20 "20" true
function(){} NaN "function(){}" true
{} NaN "[object Object]" true
null 0 "null" false
undefined NaN "undefined" false

比較運算

js為我們提供了嚴格比較與類型轉換比較兩種模式,嚴格比較(===)只會在操作符兩側的操作對象類型一致,並且內容一致時才會返回true,否則返回false。而更為廣泛使用的==操作符則會首先將操作對象轉化為相同類型,在進行比較。

相等操作符會對操作值進行隱式轉換后進行比較:

  • 如果一個操作值為布爾值,則在比較之前先將其轉換為數值
  • 如果一個操作值為字符串,另一個操作值為數值,則通過Number()函數將字符串轉換為數值
  • 如果一個操作值是對象,另一個不是,則調用對象的valueOf()方法,得到的結果按照前面的規則進行比較
  • null與undefined是相等的
  • 如果一個操作值為NaN,則相等比較返回false
  • 如果兩個操作值都是對象,則比較它們是不是指向同一個對象

加法運算操作符:
加法運算符在js中也用作字符串拼接,所以加法操作符的規則分為兩種

  • 如果一個數是NaN,則結果就是NaN
  • 如果是Infinity+Infinity,結果是Infinity
  • 如果是-Infinity+(-Infinity),結果是-Infinity
  • 如果是Infinity+(-Infinity),結果是NaN
    如果有一個操作值是字符串,則:
  • 如果兩個都是字符串則,拼接起來
  • 一個有一個操作值是字符串,則將另外的值轉換成字符串,然后拼接起來
  • 如果又一個值是對象、數值或者布爾值,則調用toString()方法取得字符串值,然后再應用前面的字符串規則。對於undefined和null,分別調用String()顯式轉換為字符串。

邏輯操作符(!、&&、||)
邏輯非(!)操作符首先通過Boolean()函數將它的操作值轉換為布爾值,然后求反。

邏輯與(&&)操作符,如果一個操作值不是布爾值時,遵循以下規則進行轉換:

  • 如果第一個操作數經Boolean()轉換后為true,則返回第二個操作值,否則返回第一個值(不是Boolean()轉換后的值)
  • 如果有一個操作值為null,返回null
  • 如果有一個操作值為NaN,返回NaN
  • 如果有一個操作值為undefined,返回undefined

邏輯或(||)操作符,如果一個操作值不是布爾值,遵循以下規則:

  • 如果第一個操作值經Boolean()轉換后為false,則返回第二個操作值,否則返回第一個操作值(不是Boolean()轉換后的值)
  • 對於undefined、null和NaN的處理規則與邏輯與(&&)相同

關系操作符(<, >, <=, >=)
與上述操作符一樣,關系操作符的操作值也可以是任意類型的,所以使用非數值類型參與比較時也需要系統進行隱式類型轉換:

  • 如果兩個操作值都是數值,則進行數值比較
  • 如果兩個操作值都是字符串,則比較字符串對應的字符編碼值
  • 如果只有一個操作值是數值,則將另一個操作值轉換為數值,進行數值比較
  • 如果一個操作數是對象,則調用valueOf()方法(如果對象沒有valueOf()方法則調用toString()方法),得到的結果按照前面的規則執行比較
  • 如果一個操作值是布爾值,則將其轉換為數值,再進行比較


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM