重學前端(二)
- 運行時類型是代碼實際執行過程中我們用到的類型。所有的類型數據都會屬於7個類型之一。從變量、參數、返回值到表達式中間結果,任何JavaScript代碼運行過程中產生的數據,都具有運行時類型。
類型
Undefined
Null
Boolean
String
Number
Symbol
Object
Undefined
Null
Undefined
類型表示未定義,他的類型只有一個值,就是undefined
.任何變量在賦值前是Undefined
類型、值爲undefined
,一般我們可以用全局變量undefined
(就是名爲undefined
的這個變量)來表達這個值,或者void
運算來把任意一個表達式變成undefined
值Null
類型也只有一個值,就是null
,表示爲控制,與undefined
不同
String
String
用於表示文本數據,最大長度爲2^53 - 1
Number
-
Number
類型基本符合IEEE 754-2008
規定的雙精度浮點數規則,根據浮點數的定義,非整數的Number
類型無法用 **== (===也不行)**來比較-
0.1 + 0.2 == 0.3 //輸出 false
-
正確的比較方法:使用
JavaScript
提供的最小精度值 -
Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON
-
-
NaN,佔用了 9007199254740990,這原本是符合IEEE規則的數字;
-
Infinity,無窮大;
-
-Infinity,負無窮大。
-
JavaScript
中有+0 和 -0 ,在假髮類運算中它們沒有區別,單數觸發的場合則需要特別留意區分**,‘忘記檢測除以-0,而得到負無窮大’**的情況經常會導致錯誤,而區分+0 和 -0 的方式,正式檢測 1/x 是infinity
還是-infinity
Symbol
Symbol
是ES6
中引入的新類型,它是一切非字符串的對象key
的集合,在ES6
中,整個對象系統被用Symbol
重
Object
- 對象的定義是‘屬性的集合’。屬性分爲數據屬性和訪問器屬性,二者都是
key-value
結構,key
可以是字符串或者Symbol
類型 JS
中的類僅僅是運行時對象的一個私有屬性,而JS
中時無法自定義類型的,在js
的幾個基本類型中,都在對象類型中有一個親戚
Number
String
Boolean
Symbol
- 所以,3 和
new Number(3)
是完全不同的值,它們是一個Number
類型,一個是對象類型,Number
、String
、Boolean
,三個構造器是倆用的,當跟new
搭配時,它們產生對象,當直接調用的時候,它們表示強制類型轉換 - .(點)運算符提供了裝箱操作,它會根據基礎類型構造一個臨時對象,使得我們能在基礎類型上調用對應對象的方法
裝箱轉換
- 每一種基本類型
Number
、String
、Boolean
、Symbol
在對象中都有對應的類,所謂裝箱轉換,正是把基本類型轉換爲對應的對象,他是類型轉換中一種相當重要的種類
拆箱轉換
- 在JavaScript標準中,規定了
ToPrimitive
函數,它是對象類型到基本類型的轉換(即,拆箱轉換)。 - 對象到 String 和 Number 的轉換都遵循“先拆箱再轉換”的規則。通過拆箱轉換,把對象變成基本類型,再從基本類型轉換爲對應的 String 或者 Number。
- 拆箱轉換會嘗試調用 valueOf 和 toString 來獲得拆箱後的基本類型。如果 valueOf 和 toString 都不存在,或者沒有返回基本類型,則會產生類型錯誤 TypeError。
總結
- List 和 Record: 用於描述函數傳參過程。
- Set:主要用於解釋字符集等。
- Completion Record:用於描述異常、跳出等語句執行過程。
- Reference:用於描述對象屬性訪問、delete等。
- Property Descriptor:用於描述對象的屬性。
- Lexical Environment 和 Environment Record:用於描述變量和作用域。
- Data Block:用於描述二進制數據。
JavaScript
對象的特徵
- 對象具有唯一標識性:即使完全相同的倆個對象,也並非同一個對象
- 對象有狀態:對象具有狀態,同一對象可能處於不同狀態之下
- 對象具有信鴿網i:季對象的狀態,可能因爲它的行爲產生變遷
(一)具有唯一標識性
- 各種語言的對象唯一標識性都是用內存地址來體現的,對象具有唯一表示的內存地址,所以具有唯一的標識
(二)第二 和 第三特徵
-
在
JS
中,將狀態和行爲統一抽象爲‘屬性’,考慮到JavaScript
中函數設計成一種特殊對象 -
下面代碼就展示了 普通屬性 和 函數作爲屬性的一個例子,其中
o
是對象,d
是屬性,而函數f
也是一個屬性,儘管寫法不太相同,但是對JavaScript
來說,d
和f
就是倆個普通屬性 -
var o = { d:1, f(){ console.log(this.d) } }
JavaScript
中對象獨有的特色是:對象具有高度的動態性,這是因爲JS
賦予了使用者在運行是爲對象添加狀態和行爲的能力
- 爲了提高抽象能力,
JavaScript
的屬性被設計成比別的語言更加複雜的形式,它提供了 數據屬性和訪問器屬性(getter
/setter
)倆類
JavaScript
對象的倆類屬性
數據屬性具有四個特徵
value
:就是屬性的值writable
:決定屬性能否被賦值enumerable
:決定for in
能否枚舉該屬性configurable
:決定改屬性能否被刪除或者改變特徵值
訪問器(getter
/ setter
)屬性
getter
:函數 或者undefined
,在取屬性值時被調用setter
:函數 或者undefined
,在設置屬性值時被調用enumerable
:決定for in
能否枚舉該屬性configurable
:決定該屬性能否被刪除或者改變特徵值
訪問器屬性是的屬性在讀和寫時執行代碼,它允許使用者在寫和堵屬性時,得到完全不同的值,它可以是爲一種函數的語法糖
我們通常用於定義屬性的代碼會產生數據屬性,其中的writable
、enumerable
、configurable
都會默認true
, 我們可以使用內置函數 Object.getOwnPropertyDescripter
來查看
JavaScript
對象的具體設計:具有高度動態性的屬性集合
JavaScript
得原型
- 如果所有對象都有私有字段[[prototype]],就是對象的原型
- 讀一個屬性,如果對象本身沒有,則會繼續訪問對象的原型,知道原型爲空或者找到爲止,(原型鏈)
ES6
,JS
提供了一系列內置函數,以便更爲直接的訪問操縱原型
Object.create
根據指定的原型創建新對象,原型可以是null;Object.getPrototypeOf
獲得一個對象的原型;Object.setPrototypeOf
設置一個對象的原型。
早期版本中的類與原型
-
‘類’的定義是一個私有屬性[[class]],語言標準爲內置類型諸如
Number
、String
、Date
等指定了[[class]]屬性,以表示它們的類。語言使用者唯一可以訪問[[class]]屬性的方式是Object.prototype.toString
-
var o = new Object; var n = new Number; var s = new String; var b = new Boolean; var d = new Date; var arg = function(){ return arguments }(); var r = new RegExp; var f = new Function; var arr = new Array; var e = new Error; console.log([o, n, s, b, d, arg, r, f, arr, e].map(v => Object.prototype.toString.call(v))); //輸出 (10) ["[object Object]", "[object Number]", "[object String]", "[object Boolean]", "[object Date]", "[object Arguments]", "[object RegExp]", "[object Function]", "[object Array]", "[object Error]"] 0: "[object Object]" 1: "[object Number]" 2: "[object String]" 3: "[object Boolean]" 4: "[object Date]" 5: "[object Arguments]" 6: "[object RegExp]" 7: "[object Function]" 8: "[object Array]" 9: "[object Error]" length: 10 __proto__: Array(0)
new
運算接受一個構造器 和一組調用參數,實際上做了幾件事
- 以構造器的
prototype
屬性(注意與私有字段[[prototype]]的區分)爲原型,創建新對象 - 將
this
和調用參數傳給構造器,執行 - 如果構造器返回的時對象,則返回,否則返回第一步創建的對象
JavaScript
中的對象分類
- 宿主對象(
host Objects
):由JavaScript
宿主環境提供的環境,它們的行爲完全由宿主環境決定 - 內置對象(
Built-in Object
):由JavaScript
語言提供的對象- 內置對象(
intrinsic Objects
):由標準規定,隨着JavaScript
運行時創建而自動創建的對象實例 - 原生對象(
Native Object
):可以由用戶通過Array
、RegExp
等內置構造器或者特殊語法創建的對象 - 普通對象(
Ordinary Objects
):由{}語法、Objects
構造器或者class
關鍵字定義類創建的對象,它能夠被原型繼承
- 內置對象(
宿主對象
- 瀏覽器環境中的宿主,全局對象時
window
,window
上又有很多屬性,比如document
,實際上這個全局對象window
上的屬性,一部分來自於JavaScript
語言,一部分來自於瀏覽器環境 - 宿主對象也分爲固有的和用戶可創建的倆種,比如
document.createElement
就可以創建一些dom
對象,宿主也會提供一些構造器,比如我們可以使用new Image
來創建img
對象
內置對象-固有對象
- 固有對象是由標準規定,隨着
JavaScript
運行時創建而自動創建的對象實例,固有對象在任何JS
代碼執行前就已經被創建出來了。
內置對象-原生對象
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5EcAR0pB-1581861071709)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200123193705440.png)]
- 通過這些構造器,我們可以用
new
運算創建薪得對象,所以我們把這些對象稱作爲原生對象 - 這些構造器創建的對象多數使用了私有字段,例如:
Error: [[ErrorData]]
Boolean: [[BooleanData]]
Number: [[NumberData]]
Date: [[DateValue]]
RegExp: [[RegExpMatcher]]
Symbol: [[SymbolData]]
Map: [[MapData]]
用對象來模擬函數與構造器:函數對象與構造器對象
- 函數對象的定義是:具有[[call]]私有字段的對象,構造器對象的定義是:具有私有字段[[construct]]的對象